
本示例使用的发卡器:https://item.taobao.com/item.htm?spm=a21dvs.23580594.0.0.52de2c1bVIuGpf&ft=t&id=18645495882
一、确定已安装Qt Serial Port组件

二、在.pro项目文件声明引用Serialport组件

三、在.h头文件内引用Serialport组件

四、在.cpp程序中实列化serial,并绑定串口接收数据的槽函数

五、打开串口并设置波特率、数据位、校验位、停止位
cpp
void MainWindow::on_Butt_Open_clicked()
{
if(ui->Butt_Open->text() == "打开串口")
{
//设置串口为下拉栏所选串口名
serial->setPortName(ui->Com_Serial->currentText());
//设置波特率
switch (ui->Com_Baud->currentIndex())
{
case 0: serial->setBaudRate(QSerialPort::Baud4800); break;//4800
case 1: serial->setBaudRate(QSerialPort::Baud9600); break;
case 2: serial->setBaudRate(QSerialPort::Baud19200); break;
case 3: serial->setBaudRate(QSerialPort::Baud38400); break;
case 4: serial->setBaudRate(QSerialPort::Baud57600); break;
case 5: serial->setBaudRate(QSerialPort::Baud115200); break;
default: break;
}
//设置数据位数
switch (ui->Com_Size->currentIndex())
{
case 0:serial->setDataBits(QSerialPort::Data5); break;//1位
case 1:serial->setDataBits(QSerialPort::Data6); break;
case 2:serial->setDataBits(QSerialPort::Data7); break;//1位
case 3:serial->setDataBits(QSerialPort::Data8); break;
default: break;
}
//设置校验位
switch (ui->Com_Parity->currentIndex())
{
case 0:serial->setParity(QSerialPort::NoParity); break;//无校验位
case 1:serial->setParity(QSerialPort::OddParity); break;
case 2:serial->setParity(QSerialPort::EvenParity); break;
case 3:serial->setParity(QSerialPort::MarkParity); break;
default: break;
}
//设置停止位
switch (ui->Com_Stop->currentIndex())
{
case 0:serial->setStopBits(QSerialPort::OneStop); break;//1位
case 1:serial->setStopBits(QSerialPort::OneAndHalfStop); break;
case 2:serial->setStopBits(QSerialPort::TwoStop); break;
default: break;
}
//设置流控制
//serial->setFlowControl(QSerialPort::NoFlowControl);//无流控制
serial->setFlowControl(QSerialPort::SoftwareControl);
//打开串口 同时判断是否成功
bool info = serial->open(QIODevice::ReadWrite);
if(info == true)
{
qDebug()<<"success";
//改变label颜色(指示灯)
ui->label_16->setStyleSheet("background-color:rgb(0,255,0);border-radius:10px;");
//关闭下拉栏设置使能
ui->Com_Serial->setEnabled(false);
ui->Com_Baud->setEnabled(false);
ui->Com_Size->setEnabled(false);
ui->Com_Parity->setEnabled(false);
ui->Com_Stop->setEnabled(false);
//改变按钮文本为"关闭串口"
ui->Butt_Open->setText(tr("关闭串口"));
ui->Label_status->setText("");
}
else
{
qDebug()<<"fail";
QMessageBox::critical (this, "警告", "串口打开失败!", QMessageBox::Ok);
}
}
else
{ //关闭串口
serial->clear();
serial->close();
//改变label颜色(指示灯)
ui->label_16->setStyleSheet("background-color:rgb(255,0,0);border-radius:10px;");
//恢复下拉栏设置使能
ui->Com_Serial->setEnabled(true);
ui->Com_Baud->setEnabled(true);
ui->Com_Size->setEnabled(true);
ui->Com_Parity->setEnabled(true);
ui->Com_Stop->setEnabled(true);
//改变按钮文本为"打开串口"
ui->Butt_Open->setText(tr("打开串口"));
ui->Label_status->setText("请先选择并打开与发卡器相连的串口!");
}
}
六、向串口发送读M1卡扇区数据的指令
cpp
void MainWindow::on_Butt_ReadCard_clicked()
{
unsigned char authkeybuf[6];
QString authkeystr=ui->Text_key->toPlainText().trimmed();
int checkbuflen=checkhexdata(authkeystr,authkeybuf);
if (checkbuflen!=6){
QMessageBox::critical(NULL, "提示", QString::asprintf("十六进制认证密钥输入错误,请输入 %d", 6)+ " 字节的16进制认证密钥!");
ui->Text_key->setFocus();
return;
}
if (serial->isOpen()) { //检查串口是否打开
unsigned char databuff[16];
databuff[0]=0x0e;
databuff[1]=0x78;
databuff[2]=0x17;
databuff[3]=0x00; //表示读取任意卡
databuff[4]=0x00;
databuff[5]=0x00;
databuff[6]=0x00;
databuff[7]=ui->Com_Area->currentIndex(); //扇区号
databuff[8]=ui->Com_Auth->currentIndex(); //认证方式
for(int i=0;i<6;i++){databuff[9+i]=authkeybuf[i];} //认证密钥
char crc= 0;
for (int i=1;i<=14;i++){
crc=crc xor databuff[i];
}
databuff[15]=crc;
sendData.clear();
sendData.append(reinterpret_cast<const char*>(databuff), sizeof(databuff));
FuncCode=2;
getdatapoint=0;
serial->write(sendData);
QString dispinf=ByteArrayToHexString(sendData);
ui->Text_HexData->setPlainText(dispinf);
listadditems(getsystime()+" Send:"+dispinf);
}else{
QMessageBox::critical (this, "警告", "请先打开与发卡器相连的串口!", QMessageBox::Ok);
}
}
七、串口接收数据的槽函数返回读卡操作结果
cpp
void MainWindow::ReadData()//读取接收到的信息
{
QByteArray buf = serial->readAll();
int buflen=buf.length();
unsigned char databuff[buflen];
std::copy(buf.begin(), buf.end(), databuff);
QString str="";
int crc=0;
if (FuncCode>=0){ //读、写M1、Ntag卡指令,为防止数据分包上传,先将数据存入缓冲
for (int i=0;i<buflen;i++){
getdatabuff[getdatapoint]=databuff[i];
getdatapoint++;
}
for (int i=0;i<getdatapoint;i++){ //校验缓冲区内数据crc,如果校验成功即认为数据全部接收完,开始分析接收数据
str =str+QString::asprintf("%02X ", getdatabuff[i]);
if (i>0){crc=crc xor getdatabuff[i];}
}
}else{ //其他串口调试指令,显示串口接收数据
for (int i=0;i<buflen;i++){ //
str =str+QString::asprintf("%02X ", databuff[i]);
if (i>0){crc=crc xor databuff[i];}
}
if(crc!=0){listadditems(getsystime()+" Receive:"+str);}
}
if(crc==0){ //接收数据校验成功,数据有效
getdatapoint=0;
listadditems(getsystime()+" Receive:"+str);
QString cardhao="";
QString carddata="";
switch(FuncCode){
case 1: //只读卡号
case 2:
case 3:
case 4:
if(getdatabuff[0]==1){ //只返回一个字节的有效数据
switch(getdatabuff[1]){
case 1:
str="密码认证成功,卡片序列号已知,但读取扇区内容失败!";break;
case 2:
str="第0块读出,但第1、2块没读出,仅扇区内容前16个字节的数据有效!";break;
case 3:
str="第0、1块读出,但第2块没读出,仅扇区内容前32个字节的数据有效!";break;
case 8:
str="未寻到卡!";break;
case 9:
str="两张以上卡片同时在感应区,发生冲突!";break;
case 10:
str="无法选择激活卡片!";break;
case 11:
str="密码装载失败,卡片序列号已知!";break;
case 12:
str="密码认证失败,卡片序列号已知!";break;
}
ui->Label_status->setText(str);
}else{
if(getdatabuff[0]==5){ //返回五个字节的有效数据
str="读取卡号成功";
cardhao=QString::asprintf("%02X%02X%02X%02X", getdatabuff[2], getdatabuff[3], getdatabuff[4], getdatabuff[5]);
switch(getdatabuff[1]){
case 0:
if(FuncCode==3){
str="写扇区数据成功";
}else{
if(FuncCode==4){str="修改扇区密钥成功";}
}
break;
case 1:
str="密码认证成功,卡片序列号已知,但读取扇区内容失败";break;
case 2:
str="第0块读出,但第1、2块没读出,仅扇区内容前16个字节的数据有效";break;
case 3:
str="第0、1块读出,但第2块没读出,仅扇区内容前32个字节的数据有效";break;
case 8:
str="未寻到卡!";break;
case 9:
str="两张以上卡片同时在感应区,发生冲突";break;
case 10:
str="无法选择激活卡片";break;
case 11:
str="密码装载失败,卡片序列号已知";break;
case 12:
str="密码认证失败,卡片序列号已知";break;
}
ui->Label_status->setText(str+",16进制卡号:"+cardhao);
}else{
if(getdatabuff[0]==53){ //返回五十三个字节的有效数据
cardhao=QString::asprintf("%02X%02X%02X%02X", getdatabuff[2], getdatabuff[3], getdatabuff[4], getdatabuff[5]);
for (int i=6;i<=getdatabuff[0];i++){carddata=carddata+QString::asprintf("%02X", getdatabuff[i])+" ";}
ui->Text_Data->setPlainText(carddata);
ui->Label_status->setText("读扇区数据成功,16进制卡号:"+cardhao);
}
}
}
break;
case 5:
break;
case 6:
if (getdatabuff[0]>7){
cardhao="16进制卡号:"+QString::asprintf("%02X%02X%02X%02X%02X%02X%02X", getdatabuff[2], getdatabuff[3], getdatabuff[4], getdatabuff[5], getdatabuff[6], getdatabuff[7], getdatabuff[8]);
}
if(getdatabuff[1]==0){
ui->Label_status->setText("写Ntag卡块数据成功,"+cardhao);
}else{
if(getdatabuff[1]==8){ui->Label_status->setText("未寻到卡!"); }
else{
if(getdatabuff[1]==9){ui->Label_status->setText("两张以上卡片同时在感应区,发生冲突!"); }
else{
if(getdatabuff[1]==12){ui->Label_status->setText("密码认证失败!"+cardhao); }
else{
if(getdatabuff[1]==13){ui->Label_status->setText("读卡失败,可能要带密码操作!"+cardhao); }
else{
ui->Label_status->setText("写Ntag卡失败,"+QString::asprintf("返回错误代码:%d",getdatabuff[1]));
}
}
}
}
}
break;
case 7: //读Ntag卡返回状态
if (getdatabuff[0]>7){
cardhao="16进制卡号:"+QString::asprintf("%02X%02X%02X%02X%02X%02X%02X", getdatabuff[2], getdatabuff[3], getdatabuff[4], getdatabuff[5], getdatabuff[6], getdatabuff[7], getdatabuff[8]);
}
if(getdatabuff[1]==0){
for (int i=11;i<=getdatabuff[0];i++){carddata=carddata+QString::asprintf("%02X", getdatabuff[i])+" ";}
ui->Text_TagData->setPlainText(carddata);
ui->Label_status->setText("读Ntag卡块数据成功,"+cardhao);
}else{
if(getdatabuff[1]==8){ui->Label_status->setText("未寻到卡!"); }
else{
if(getdatabuff[1]==9){ui->Label_status->setText("两张以上卡片同时在感应区,发生冲突!"); }
else{
if(getdatabuff[1]==12){ui->Label_status->setText("密码认证失败!"+cardhao); }
else{
if(getdatabuff[1]==13){ui->Label_status->setText("读卡失败,可能要带密码操作!"+cardhao); }
else{
ui->Label_status->setText("读Ntag卡失败,"+QString::asprintf("返回错误代码:%d",getdatabuff[1]));
}
}
}
}
}
break;
case 8: //读Ntag卡号返回状态
if(getdatabuff[0]==8 && getdatabuff[1]==0){
cardhao=QString::asprintf("%02X%02X%02X%02X%02X%02X%02X", getdatabuff[2], getdatabuff[3], getdatabuff[4], getdatabuff[5], getdatabuff[6], getdatabuff[7], getdatabuff[8]);
ui->Label_status->setText("读Ntag卡号成功,16进制卡号:"+cardhao);
}else{
if(getdatabuff[0]==1 && getdatabuff[1]==8){
ui->Label_status->setText("未寻到卡!");
}else{
if(getdatabuff[0]==1 && getdatabuff[1]==9){
ui->Label_status->setText("读Ntag卡号失败,感应区内的卡不是Ntag卡!");
}
}
}
break;
case 9: //校验Ntag卡密钥
if(getdatabuff[0]==3 && getdatabuff[1]==0){
QString packhex=QString::asprintf("%02X%02X", getdatabuff[2], getdatabuff[3]);
ui->Label_status->setText("Ntag卡密钥校验成功,PACK密钥确认码:"+packhex);
}else{
if(getdatabuff[0]==1 && getdatabuff[1]==12){
ui->Label_status->setText("Ntag卡密钥校验失败,请先读取卡号、输入8位正确的认证密钥再校验试试!");
}
}
break;
case 10:
break;
}
}
}