Qt C++串口SerialPort通讯发送指令读写NFC M1卡

本示例使用的发卡器: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;
        }
    }
}
相关推荐
超喜欢下雨天5 分钟前
服务器安装 ros2时遇到底层库依赖冲突的问题
linux·运维·服务器·ros2
oioihoii19 分钟前
C++11 forward_list 从基础到精通:原理、实践与性能优化
c++·性能优化·list
m0_6873998427 分钟前
写一个Ununtu C++ 程序,调用ffmpeg API, 来判断一个数字电影的视频文件mxf 是不是Jpeg2000?
开发语言·c++·ffmpeg
tan77º1 小时前
【Linux网络编程】网络基础
linux·服务器·网络
看到我,请让我去学习1 小时前
Qt编程-qml操作(js,c++,canvas)
开发语言·qt
笑衬人心。1 小时前
Ubuntu 22.04 + MySQL 8 无密码登录问题与 root 密码重置指南
linux·mysql·ubuntu
Ronin3052 小时前
【C++】类型转换
开发语言·c++
mrbone112 小时前
Git-git worktree的使用
开发语言·c++·git·cmake·worktree·gitab
哈市雪花3 小时前
相机:Camera原理讲解(使用OpenGL+QT开发三维CAD)
qt·3d·交互·相机·图形学·opengl·视角
chanalbert3 小时前
CentOS系统新手指导手册
linux·运维·centos