Qt 串口通信,数据读写

1.串口连接

串口图形界面

.pro文件中添加serialPort

QT       += core gui serialport 
//查找可用的串口
foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
{
    ui->PortBox->addItem(info.portName());
}

QString setPortName = ui->PortBox->currentText();	//端口
int setBaudBox = ui->BaudBox->currentText().toInt();	//波特率
QSerialPort::DataBits setDataBits = ui->BitBox->currentText();	//数据位
QSerialPort::StopBits setStopBits = ui->StopBox->currentText();	//停止位
QSerialPort::Parity setParityBits = ui->ParityBox->currentText();	//校验位
QSerialPort::FlowControl setFlowControl = ui->FlowControl->currentText();	//控制流

//通过读取界面设置的端口数据,选择并设置正确的数据

if(dataBits == "5"){
    setDataBits = QSerialPort::Data5;
}else if(dataBits == "6"){
    setDataBits = QSerialPort::Data6;
}else if(dataBits == "7"){
    setDataBits = QSerialPort::Data7;
}else{
    setDataBits = QSerialPort::Data8;
}

if(stopBits == "1"){
    setStopBits = QSerialPort::OneStop;
}else if(stopBits == "2"){
    setStopBits = QSerialPort::TwoStop;
}else{
    setStopBits = QSerialPort::OneAndHalfStop;
}

if(parityBits == "None"){
    setParityBits = QSerialPort::NoParity;
}else if(parityBits == "Odd"){
    setParityBits = QSerialPort::OddParity;
}else if(parityBits == "Even"){
    setParityBits = QSerialPort::EvenParity;
}else if(parityBits == "Mark"){
    setParityBits = QSerialPort::MarkParity;
}else /*if(parityBits == "Space")*/{
    setParityBits = QSerialPort::SpaceParity;
}

if(flowControl == "HardWare"){
    setFlowControl = QSerialPort::HardwareControl;
}else if(flowControl == "SoftWare"){
    setFlowControl = QSerialPort::SoftwareControl;
}else /*if(flowControl == "None")*/{
    setFlowControl = QSerialPort::NoFlowControl;
}

serialPort.setPortName(setPortName);	//将设置的串口参数写入
serialPort.setBaudRate(setBaudBox);
serialPort.setDataBits(setDataBits);
serialPort.setStopBits(setStopBits);
serialPort.setParity(setParityBits);
serialPort.setFlowControl(setFlowControl);
serialPort.open(QIODevice::ReadWrite);	//打开串口

2.串口读写数据

//send_byt 位要写入的数据
void mySerialPort::slot_sendText(QByteArray send_byt)
{
	 serialPort.write(QByteArray::fromHex(send_byt));
}

//读取串口中返回的数据
void mySerialPort::slot_serialPortRead()
{
    QByteArray readText = serialPort.readAll();
    emit showRead(readText,button_name);
}

这条语句为读取返回数据的关键
作用:当发送数据有效,有返回数据时,会触发slot_serialPortRead()读取返回数据

connect(&serialPort,&QIODevice::readyRead,this,&mySerialPort::slot_serialPortRead);
可以根据自己的需求放在适合的位置,不知道放哪,可以直接放在mySerialPort::mySerialPort(QObject *parent) : QObject(parent){}中;
mySerialPort为我当前函数所在

QSerialPort serialPort;
connect(&serialPort,&QIODevice::readyRead,this,&mySerialPort::slot_serialPortRead);

在实际工作中,通过串口写入的数据往往是公司给定的协议,我们需要将协议转换为具体的数据
可以得知我们可能需要发送不同的数据,这就需要我们在图形界面上获取输入的组成协议的数据,再通过协议规则生成完整的数据,并且需要CRC校验。
CRC校验的种类很多,实际工作中根据给定的CRC校验进行校验。

起始码、命令码、功能码、对象索引,有效数据 等根据实际情况输入,
数据长度:第四字节到累计和取反前字节数,[4,n-1]
CRC校验:根据给定的校验数据校验
累计和取反:第二字节到累计和取反前一字节,[2,n-1], 计算方式:将每一字节的16进制数相加,满0下0x100从0重新相加,得到累计和,再以0x100 - 累计和。

//*******发送采集数据命令************//
void MySerialPort::gatherLog()
{
    QString startCode = "*";                   //起始码
    QString cmdCode = "A0";                    //命令类型码
    
    QString code2 = "0800";                    //功能码
    static quint16 tmp = 0;						//对象索引
    
    QString validData = "aabb";                //有效数据
    QByteArray crcData = QByteArray::fromHex(validData.toLatin1());                                   //将有效数据转换为16进制
    quint16 crc = CRC16_Dn_Cal((quint8 *)crcData.data(),(quint32)crcData.length(),(quint16)0xffff);         //CRC16校验
    crc = ((crc & 0x00FF) << 8) + ((crc & 0xFF00) >> 8);                                                //高低位转换
    quint16 index = ((tmp & 0x00FF) << 8) + ((tmp & 0xFF00) >> 8);          //偏移的字节
    
    QString needPacketData = code2 + QString("%1").arg(index,4,16,QLatin1Char('0')) + QString::number(crc, 16)  + validData;      //  QString::number(crc, 16)  10进制整数转16进制字符串
    QByteArray cheakSumData = data_packet(cmdCode,needPacketData);           //得到需要进行校验的数据
    QByteArray send_data = cheakSumData + cumulativeSum(cheakSumData);                      //累计和取反
    serialport.write(startCode.toLatin1() + send_data);         //串口发送采集命令
    tmp++;

}

/* ------CRC校验函数------  */
quint16 MySerialPort::CRC16_Dn_Cal(quint8 * dat, quint32 len, quint16 startCrc)
{
    const  unsigned short  CRC16_Dn_ByteTab[ 256 ] = {
        0x0000,  0xC0C1,  0xC181,  0x0140,  0xC301,  0x03C0,  0x0280,  0xC241,
        0xC601,  0x06C0,  0x0780,  0xC741,  0x0500,  0xC5C1,  0xC481,  0x0440,
        0xCC01,  0x0CC0,  0x0D80,  0xCD41,  0x0F00,  0xCFC1,  0xCE81,  0x0E40,
        0x0A00,  0xCAC1,  0xCB81,  0x0B40,  0xC901,  0x09C0,  0x0880,  0xC841,
        0xD801,  0x18C0,  0x1980,  0xD941,  0x1B00,  0xDBC1,  0xDA81,  0x1A40,
        0x1E00,  0xDEC1,  0xDF81,  0x1F40,  0xDD01,  0x1DC0,  0x1C80,  0xDC41,
        0x1400,  0xD4C1,  0xD581,  0x1540,  0xD701,  0x17C0,  0x1680,  0xD641,
        0xD201,  0x12C0,  0x1380,  0xD341,  0x1100,  0xD1C1,  0xD081,  0x1040,
        0xF001,  0x30C0,  0x3180,  0xF141,  0x3300,  0xF3C1,  0xF281,  0x3240,
        0x3600,  0xF6C1,  0xF781,  0x3740,  0xF501,  0x35C0,  0x3480,  0xF441,
        0x3C00,  0xFCC1,  0xFD81,  0x3D40,  0xFF01,  0x3FC0,  0x3E80,  0xFE41,
        0xFA01,  0x3AC0,  0x3B80,  0xFB41,  0x3900,  0xF9C1,  0xF881,  0x3840,
        0x2800,  0xE8C1,  0xE981,  0x2940,  0xEB01,  0x2BC0,  0x2A80,  0xEA41,
        0xEE01,  0x2EC0,  0x2F80,  0xEF41,  0x2D00,  0xEDC1,  0xEC81,  0x2C40,
        0xE401,  0x24C0,  0x2580,  0xE541,  0x2700,  0xE7C1,  0xE681,  0x2640,
        0x2200,  0xE2C1,  0xE381,  0x2340,  0xE101,  0x21C0,  0x2080,  0xE041,
        0xA001,  0x60C0,  0x6180,  0xA141,  0x6300,  0xA3C1,  0xA281,  0x6240,
        0x6600,  0xA6C1,  0xA781,  0x6740,  0xA501,  0x65C0,  0x6480,  0xA441,
        0x6C00,  0xACC1,  0xAD81,  0x6D40,  0xAF01,  0x6FC0,  0x6E80,  0xAE41,
        0xAA01,  0x6AC0,  0x6B80,  0xAB41,  0x6900,  0xA9C1,  0xA881,  0x6840,
        0x7800,  0xB8C1,  0xB981,  0x7940,  0xBB01,  0x7BC0,  0x7A80,  0xBA41,
        0xBE01,  0x7EC0,  0x7F80,  0xBF41,  0x7D00,  0xBDC1,  0xBC81,  0x7C40,
        0xB401,  0x74C0,  0x7580,  0xB541,  0x7700,  0xB7C1,  0xB681,  0x7640,
        0x7200,  0xB2C1,  0xB381,  0x7340,  0xB101,  0x71C0,  0x7080,  0xB041,
        0x5000,  0x90C1,  0x9181,  0x5140,  0x9301,  0x53C0,  0x5280,  0x9241,
        0x9601,  0x56C0,  0x5780,  0x9741,  0x5500,  0x95C1,  0x9481,  0x5440,
        0x9C01,  0x5CC0,  0x5D80,  0x9D41,  0x5F00,  0x9FC1,  0x9E81,  0x5E40,
        0x5A00,  0x9AC1,  0x9B81,  0x5B40,  0x9901,  0x59C0,  0x5880,  0x9841,
        0x8801,  0x48C0,  0x4980,  0x8941,  0x4B00,  0x8BC1,  0x8A81,  0x4A40,
        0x4E00,  0x8EC1,  0x8F81,  0x4F40,  0x8D01,  0x4DC0,  0x4C80,  0x8C41,
        0x4400,  0x84C1,  0x8581,  0x4540,  0x8701,  0x47C0,  0x4680,  0x8641,
        0x8201,  0x42C0,  0x4380,  0x8341,  0x4100,  0x81C1,  0x8081,  0x4040
    };
    quint8    temp;
    quint32   i;
    quint16   crc = startCrc;
    for(i = 0; i < len; i ++)
    {
        temp=(quint8)(crc & 0x00FF) ^ dat[i];
        crc >>= 8;
        crc ^= CRC16_Dn_ByteTab[temp];
    }
    return crc;
}

/* --------cheakSum校验函数---------*/
QByteArray MySerialPort::cumulativeSum(QByteArray str)
{
    QByteArray tem = str;
    quint8 sum = 0;
    quint16 max = 0x100;
    for(int i=0;i<tem.length();i++)
    {
        sum += tem.at(i);           //循环对tem求和
    }
    sum = sum & 0x00FF;				
    sum = max - sum;                //得到校验和
    return QByteArray::fromHex(QString::number(sum, 16).toLatin1());
}

/*---------数据封包函数---------*/
QByteArray MySerialPort::data_packet(QString code,QString str)
{
    QByteArray cmd,after_packet;
    cmd = QByteArray::fromHex(code.toLatin1());             //获得命令类型码
    QString package = str;                                  //n个byte的数据包
    int length1 = package.length() / 2;                     //按2个字符1个byte分,计算出数据长度
    QByteArray datalength = QByteArray::fromHex(QByteArray::number(length1,16));        //转换为16进制字符串
    QByteArray packet = QByteArray::fromHex(package.toLatin1());    //数据封包
    after_packet = cmd + datalength + packet;
    return after_packet;
}
  • 4
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值