本示例使用的發卡器: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,并綁定串口接收數據的槽函數
五、打開串口并設置波特率、數據位、校驗位、停止位?
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;//4800case 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卡扇區數據的指令
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);}
}
七、串口接收數據的槽函數返回讀卡操作結果
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;}}
}
?