HX9809U-L超高频读写器:
读写器厂家提供SDK,采用动态链接加载的方式。方式如下`:
1.头文件定义相关变量
class CUHFDlg : public CDialog
{
// Construction
public:
CUHFDlg(CWnd* pParent = NULL); // standard constructor
void addMsg(CString str);//自定义消息添加函数
HINSTANCE g_hRRLibrary;//串口句柄
unsigned char ComAdr;//读写器地址
int Frmhandle;//读写器操作句柄
BOOL b_Search;//寻卡开启标志位
BOOL b_SearchOK;//EPC号码寻卡成功标志位
int by_EPClength;//EPC号长度
unsigned char EPC[100];//EPC号码 以字符存储 16进制显示单个字符
CString str_EPC;//EPC号码字符串
/******************************定义函数**************************/
//打开串口
typedef int (FAR WINAPI*POpenComPort)(int port, unsigned char *ComAdr,unsigned char baud,int *Frmhandle);
//关闭串口
typedef int (FAR WINAPI*PCloseComPort)();
//寻卡
typedef int (FAR WINAPI*PInventory_G2)(unsigned char *ComAdr, unsigned char *EPClenandEPC,
int *Totallen, int *CardNum, int FrmHandle);
//读卡
typedef int (FAR WINAPI*PReadCard_G2)(unsigned char *ComAdr,
unsigned char *EPC,
unsigned char Mem,
unsigned char WordPtr,
unsigned char Num,
unsigned char *Password,
unsigned char maskadr,
unsigned char maskLen,
unsigned char maskFlag,
unsigned char *Data,
unsigned char EPClength,
int *errorcode,
int FrmHandle);
//写卡
typedef int (FAR WINAPI*PWriteCard_G2)(unsigned char *ComAdr,
unsigned char *EPC,
unsigned char Mem,
unsigned char WordPtr,
unsigned char Writedatalen,
unsigned char *WrittenData,
unsigned char *Password,
unsigned char maskadr,
unsigned char maskLen,
unsigned char maskFlag,
int *WrittenDataNum,
unsigned char EPClength,
int *errorcode,
int FrmHandle);
//实例化函数
POpenComPort RR_OpenComPort;
PCloseComPort RR_CloseComPort;
PInventory_G2 RR_Inventory_G2;
PReadCard_G2 RR_ReadCard_G2;
PWriteCard_G2 RR_WriteCard_G2;
// Dialog Data
//{{AFX_DATA(CUHFDlg)
enum { IDD = IDD_UHF_DIALOG };
CListBox m_ListBox;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CUHFDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CUHFDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnBtnOpenCom();
afx_msg void OnBtnCloseCom();
virtual void OnOK();
virtual void OnCancel();
afx_msg void OnBtnSearch();
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnBtnReadcard();
afx_msg void OnBtnWritecard();
afx_msg void OnBtnReadEPC();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
- 加载动态链接库,导出函数
BOOL CUHFDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
//初始化控件
GetDlgItem(IDC_BTN_CLOSECOM)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_SEARCH)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
//调用UHF动态链接库
g_hRRLibrary = LoadLibrary("UHFReader09.dll");
//导出动态链接库函数
if (g_hRRLibrary ==NULL)
{
addMsg("UHFReader09.dll加载失败");
return FALSE;
}
addMsg("UHFReader09.dll加载成功");
if(!(RR_OpenComPort = (POpenComPort)GetProcAddress(g_hRRLibrary,"OpenComPort")))
{
addMsg("OpenComPort加载失败");
return FALSE;
}
if(!(RR_CloseComPort = (PCloseComPort)GetProcAddress(g_hRRLibrary,"CloseComPort")))
{
addMsg("CloseComPort加载失败");
return FALSE;
}
if(!(RR_Inventory_G2 = (PInventory_G2)GetProcAddress(g_hRRLibrary,"Inventory_G2")))
{
addMsg("Inventory_G2加载失败");
return FALSE;
}
if(!(RR_ReadCard_G2 = (PReadCard_G2)GetProcAddress(g_hRRLibrary,"ReadCard_G2")))
{
addMsg("ReadCard_G2加载失败");
return FALSE;
}
if(!(RR_WriteCard_G2 = (PWriteCard_G2)GetProcAddress(g_hRRLibrary,"WriteCard_G2")))
{
addMsg("WriteCard_G2加载失败");
return FALSE;
}
addMsg("函数导出成功!");
return TRUE; // return TRUE unless you set the focus to a control
}
3 根据函数指针,调用函数,实现SDK功能。
void CUHFDlg::OnBtnOpenCom()
{
// TODO: Add your control notification handler code here
int port=4;//端口号
BYTE baud=5; //波特率 0=9600bps 1=19200bps 2=38400bps 4=56000 bps 5=57600 bps 6=115200 bps
ComAdr=255;//输入输出变量,输入255返回,读写器实际的地址,读写器默认返回0
int ret = RR_OpenComPort(port, &ComAdr,baud,&Frmhandle);
if(ret==0)
{
addMsg("端口打开成功!");
GetDlgItem(IDC_BTN_OPENCOM)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_SEARCH)->EnableWindow(TRUE);
GetDlgItem(IDC_BTN_CLOSECOM)->EnableWindow(TRUE);
}
else if(ret==0x35)
{
addMsg("端口已打开或被占用!");
}
else
{
addMsg("端口打开失败!");
}
}
void CUHFDlg::OnBtnCloseCom()
{
// TODO: Add your control notification handler code here
int ret = RR_CloseComPort();
if(ret==0)
{
addMsg("端口关闭成功!");
GetDlgItem(IDC_BTN_OPENCOM)->EnableWindow(TRUE);
GetDlgItem(IDC_BTN_CLOSECOM)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_SEARCH)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
}
else
{
addMsg("端口关闭失败!");
}
}
void CUHFDlg::addMsg(CString str)
{
SYSTEMTIME st;
CString strTime;
GetLocalTime(&st);
strTime.Format("%.2d:%.2d:%.2d ",st.wHour,st.wMinute,st.wSecond);
int count = ((CListBox*)GetDlgItem(IDC_LISTBOX))->GetCount();
if (count==2000)
{
((CListBox*)GetDlgItem(IDC_LISTBOX))->DeleteString(0);
count--;
}
((CListBox*)GetDlgItem(IDC_LISTBOX))->InsertString(count,strTime+str);
((CListBox*)GetDlgItem(IDC_LISTBOX))->SetCurSel(count);
}
void CUHFDlg::OnBtnSearch()
{
b_SearchOK=FALSE;
if (!b_Search)
{
//设置寻卡定时器
SetTimer(1,100,NULL);
b_Search=TRUE;
}
else
{
b_Search=FALSE;
KillTimer(1);
addMsg("寻卡结束!");
}
}
void CUHFDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
addMsg("寻卡中....");
int CardNum=0;//搜寻到的卡数量
int fCmdRet = RR_Inventory_G2(&ComAdr,EPC, &by_EPClength, &CardNum, Frmhandle);
if (fCmdRet==-1)
{
addMsg("函数调用失败!");
return;
}
if (fCmdRet==0xFB)
{
addMsg("无电子标签可操作!");
return;
}
if (fCmdRet==1)
{
addMsg("询查时间结束前返回!");
}
if (fCmdRet==2)
{
addMsg("询查时间结束使得询查退出!");
}
if (fCmdRet==3)
{
addMsg("如果读到的标签数量无法在一条消息内传送完,将分多次发送。!");
}
if (fCmdRet==4)
{
addMsg("还有电子标签未读取,电子标签数量太多,MCU存储不了!");
}
if (CardNum=1)
{
str_EPC.Format("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",EPC[1],EPC[2],EPC[3],EPC[4],EPC[5],EPC[6],EPC[7],EPC[8],EPC[9],EPC[10],EPC[11],EPC[12]);
addMsg("卡号:"+str_EPC);
b_Search=FALSE;
b_SearchOK=TRUE;
KillTimer(1);
addMsg("寻卡结束");
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(TRUE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(TRUE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(TRUE);
}
CDialog::OnTimer(nIDEvent);
}
void CUHFDlg::OnBtnReadEPC()
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
BYTE fOperEPC[100];指向输入数组变量(输入的是每字节都转化为字符的数据)。是电子标签的EPC号
BYTE Mem=0x01;//输入变量,一个字节。选择要读取的存储区要读取的存储区。0x00: 保留区;0x01:EPC存储器;0x02:TID存储器;0x03:用户存储器。
BYTE WordPtr=0x00;//输入变量,一个字节。指定要读取的字起始地址。0x00 表示从第一个字(第一个16位存储体)开始读,0x01表示从第2个字开始读,依次类推。
BYTE Num=0x08; //输入变量,一个字节。要读取的字的个数。不能设置为0x00,将返回参数错误信息。Num不能超过120,即最多读取120个字。若Num设置为0或者超过了120,将返回参数出错的消息。
BYTE fPassword[4]={0x0,0x0,0x0,0x0};//指向输入数组变量(输入的是每字节都转化为字符的数据),四个字节,这四个字节是访问密码。
//32位的访问密码的最高位在PassWord的第一字节(从左往右)的最高位,访问密码最低位在PassWord第四字节的最低位,PassWord的前两个字节放置访问密码的高字。
BYTE maskadr=0;//输入变量,EPC掩模起始字节地址。
BYTE maskLen=12;//输入变量,掩模字节数
BYTE maskFlag=0;//输入变量,掩模使能标记 maskFlag =1:掩模使能;maskFlag =0:掩模禁止;
BYTE CardData[320]; //Data:指向输出数组变量(输出的是每字节都转化为字符的数据),是从标签中读取的数据
int Errorcode=-1;//输出变量,一个字节,读写器返回响应状态为0xFC时,返回错误代码。
BYTE EPClength;//输入变量,一个字节。EPC号的字节长度
//获取EPC号码,如果EPC号码为空,则返回
if(str_EPC=="")
{
addMsg("EPC号码为空");
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
return;
}
EPClength=str_EPC.GetLength()/2;
for(int i=0;i<EPClength;i++)
{
fOperEPC[i]=(BYTE)strtoul(str_EPC.Left(2),NULL,16);
str_EPC=str_EPC.Right(str_EPC.GetLength()-2);
}
int fCmdRet = RR_ReadCard_G2(&ComAdr, fOperEPC, Mem, WordPtr, Num, fPassword, maskadr, maskLen, maskFlag, CardData, EPClength, &Errorcode, Frmhandle);
if (fCmdRet == 0)
{
CString str,s2,temp,temps;
temps="";
temp="";
for(int i=0;i<Num*2;i++)
{
temp.Format("%02X",CardData[i]);
temps=temps+temp;
}
addMsg(temps);
addMsg("读数据成功!");
}
else
{
addMsg("读数据失败!");
CString str_rec;
str_rec.Format("错误代码:0X%02X",fCmdRet);
addMsg(str_rec);
}
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
}
void CUHFDlg::OnBtnReadcard()
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
BYTE fOperEPC[100];指向输入数组变量(输入的是每字节都转化为字符的数据)。是电子标签的EPC号
BYTE Mem=0x03;//输入变量,一个字节。选择要读取的存储区要读取的存储区。0x00: 保留区;0x01:EPC存储器;0x02:TID存储器;0x03:用户存储器。
BYTE WordPtr=0x00;//输入变量,一个字节。指定要读取的字起始地址。0x00 表示从第一个字(第一个16位存储体)开始读,0x01表示从第2个字开始读,依次类推。
BYTE Num=0x07; //输入变量,一个字节。要读取的字的个数。不能设置为0x00,将返回参数错误信息。Num不能超过120,即最多读取120个字。若Num设置为0或者超过了120,将返回参数出错的消息。
BYTE fPassword[4]={0x0,0x0,0x0,0x0};//指向输入数组变量(输入的是每字节都转化为字符的数据),四个字节,这四个字节是访问密码。
//32位的访问密码的最高位在PassWord的第一字节(从左往右)的最高位,访问密码最低位在PassWord第四字节的最低位,PassWord的前两个字节放置访问密码的高字。
BYTE maskadr=0;//输入变量,EPC掩模起始字节地址。
BYTE maskLen=12;//输入变量,掩模字节数
BYTE maskFlag=0;//输入变量,掩模使能标记 maskFlag =1:掩模使能;maskFlag =0:掩模禁止;
BYTE CardData[320]; //Data:指向输出数组变量(输出的是每字节都转化为字符的数据),是从标签中读取的数据
int Errorcode=-1;//输出变量,一个字节,读写器返回响应状态为0xFC时,返回错误代码。
BYTE EPClength;//输入变量,一个字节。EPC号的字节长度
//获取EPC号码,如果EPC号码为空,则返回
if(str_EPC=="")
{
addMsg("EPC号码为空");
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
return;
}
EPClength=str_EPC.GetLength()/2;
for(int i=0;i<EPClength;i++)
{
fOperEPC[i]=(BYTE)strtoul(str_EPC.Left(2),NULL,16);
str_EPC=str_EPC.Right(str_EPC.GetLength()-2);
}
int fCmdRet = RR_ReadCard_G2(&ComAdr, fOperEPC, Mem, WordPtr, Num, fPassword, maskadr, maskLen, maskFlag, CardData, EPClength, &Errorcode, Frmhandle);
if (fCmdRet == 0)
{
CString temp,temps;
temps="";
temp="";
for(int i=0;i<Num*2;i++)
{
temp.Format("%02x",CardData[i]);
temps=temps+temp;
}
addMsg(temps);
char msg[15]={0};
memcpy(&msg,CardData,14);
CString str;
str.Format("%s",msg);
addMsg(msg);
addMsg("读数据成功!");
}
else
{
addMsg("读数据失败!");
CString str_rec;
str_rec.Format("错误代码:0X%02X",fCmdRet);
addMsg(str_rec);
}
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
}
void CUHFDlg::OnBtnWritecard()
{
// TODO: Add your control notification handler code here
BYTE fOperEPC[100];//指向输入数组变量(输入的是每字节都转化为字符的数据)。是电子标签的EPC号。
BYTE Mem=0x03;//输入变量,一个字节。选择要读取的存储区要读取的存储区。0x00: 保留区;0x01:EPC存储器;0x02:TID存储器;0x03:用户存储器。
BYTE WordPtr=0x00;//输入变量,一个字节。指定要写入的字起始地址。指定要写入数据的起始地址。如果写的是EPC区,则会忽略这个起始地址。EPC区总是规定从EPC区0x02地址(EPC号的第一个字节)开始写。
BYTE Writedatalen=14; //输入变量,一个字节。待写入的字节数(长度必须为偶数字节数)。Writedatalen必须大于0,这里字节数必须和实际待写入的数据个数相等。否则将会返回参数错误的消息。
BYTE CardData[320]; //指向输入数组变量(输入的是每字节都转化为字符的数据)。待写入的字。这是要写入到存储区的数据。比如,WordPtr等于0x02,则输出变量Data中第一个字(从左边起)写在Mem指定的存储区的地址0x02中,第二个字写在0x03中,依次类推。
BYTE fPassword[4]={0x0,0x0,0x0,0x0};//指向输入数组变量(输入的是每字节都转化为字符的数据),四个字节,这四个字节是访问密码。
//32位的访问密码的最高位在PassWord的第一字节(从左往右)的最高位,访问密码最低位在PassWord第四字节的最低位,PassWord的前两个字节放置访问密码的高字。
BYTE maskadr=0;//输入变量,EPC掩模起始字节地址。
BYTE maskLen=0;//输入变量,掩模字节数
BYTE maskFlag=0;//输入变量,掩模使能标记 maskFlag =1:掩模使能;maskFlag =0:掩模禁止;
int Errorcode=-1;//输出变量,一个字节,读写器返回响应状态为0xFC时,返回错误代码。
int WritedataNum;//输出变量,已经写入的字的个数。(以字为单位)
BYTE EPClength;//输入变量,一个字节。EPC号的字节长度
//获取EPC号码,如果EPC号码为空,则返回
if(str_EPC=="")
{
addMsg("EPC号码为空");
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
return;
}
EPClength=str_EPC.GetLength()/2;
for(int i=0;i<EPClength;i++)
{
fOperEPC[i]=(BYTE)strtoul(str_EPC.Left(2),NULL,16);
str_EPC=str_EPC.Right(str_EPC.GetLength()-2);
}
CString str1,str2,str3,str_ALL;
//获取写入的内容
GetDlgItemText(IDC_EDIT_NUMBER,str1);
GetDlgItemText(IDC_EDIT_NAME,str2);
GetDlgItemText(IDC_EDIT_VALUE,str3);
str_ALL=str1+str2+str3;
if((str_ALL.GetLength())!=14)
{
MessageBox("字符串长度错误!",NULL,MB_OK);
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
return;
}
memset(&CardData,0,sizeof(CardData));
memcpy(&CardData,str_ALL,str_ALL.GetLength());
//写入数据
int fCmdRet = RR_WriteCard_G2(&ComAdr, fOperEPC, Mem, WordPtr, Writedatalen, CardData, fPassword, maskadr, maskLen, maskFlag, &WritedataNum, EPClength, &Errorcode, Frmhandle);
if (fCmdRet == 0)
{
addMsg("写数据成功!");
}
else
{
addMsg("写数据失败!");
CString str_rec;
str_rec.Format("错误代码:0X%02X",fCmdRet);
addMsg(str_rec);
}
GetDlgItem(IDC_BTN_READCARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_WRITECARD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_READEPC)->EnableWindow(FALSE);
}
二.EPCC1-G2电子标签相关知识
电子标签内部有四个功能区:
- 保留区 4字 WORD[01]=8位16进制灭活密码WORD[23]=8位16进制读写密码;
- EPC区 WORD[2~7]=EPC号码,标签读写需根据EPC号码来操作;
- TID区 WORD[2~5]=16进制全球唯一ID 只读
- 用户区 WORD[0~31] 储存用户数据