程序员码农的世界

关于QT串口通信的一点理解

2018-11-26  本文已影响10人  帅气的程小二

最近帮老师做的项目中使用到了QT串口,然后首先百度了一下,发现网上的QT串口代码都是同一个版本。而且没有公开源代码,遂自己写了个简单的串口通信代码,并将它公布出来,一方面供有需要的人参考,另一方面记录下来,也可以防止自己忘记了。

本项目没有用到QT自带的串口通信模块,使用了第三方库qextserialport,这个库基本已经满足了串口所有的功能,而且上手也快。好了。废话不多说了,先来张效果图吧。


这是整体效果图,主要实现的是开发板和下位机通信,上位机通过串口发送指令给下位机,下位机再执行相应的操作。本文主要讲讲串口通信的部分吧。

简单来说,串口通信分为三部分:1:设置端口号和波特率等等,数据位和校验之类的一般的可以提前设定好,再代码中同样也可以设定。2:将数据写入串口,这个时候就要分发送的是多少进制的数据了,虽然计算机在实际存储时是不区分进制的。3:读串口数据,将串口接收到的数据读出来,进行下一步处理。后面我会把全部代码贴出来,代码经过调试已经可以运行了。本文中具体的控件布局我就不讲了,我只讲讲一些核心的代码,大家感兴趣的话可以自己去跑跑我的代码,代码中注释非常详细,每一行都有注释,看起来不费劲。

1.设置端口和波特率

//打开串口,波特率和端口号可以通过下拉菜单进行选择
void uwiCMonitorPC::on_openMyComBtn_clicked()
{
    QString portName = portNameComboBox->currentText(); //获取串口名
    myCom = new Win_QextSerialPort(portName,QextSerialBase::EventDriven);
    //定义串口对象,并传递参数,在构造函数里对其进行初始化
    myCom ->open(QIODevice::ReadWrite); //打开串口
    if(baudRateComboBox->currentText()==tr("38400")) //根据下拉菜单中内容对串口进行设置
    //设置波特率
    myCom->setBaudRate(BAUD38400);
    else if(baudRateComboBox->currentText()==tr("115200"))
    myCom->setBaudRate(BAUD115200);
    //设置数据位
    myCom->setDataBits(DATA_8);
    //设置奇偶校验
    myCom->setParity(PAR_NONE);
    //设置停止位 
    myCom->setStopBits(STOP_1);    
    myCom->setFlowControl(FLOW_OFF);  //设置数据流控制,我们使用无数据流控制的默认设置
    myCom->setTimeout(500);  //设置延时
    connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
    //信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作
    openMyComBtn->setEnabled(false); //打开串口后“打开串口”按钮不可用
    closeMyComBtn->setEnabled(true); //打开串口后“关闭串口”按钮可用
    sendMsgBtn->setEnabled(true); //打开串口后“发送数据”按钮可用
    O2U1->setEnabled(true);
    O2U2->setEnabled(true);
    O2U3->setEnabled(true);
    baudRateComboBox->setEnabled(false); //设置各个组合框不可用
    portNameComboBox->setEnabled(false);
}

在端口设置和波特率配置中,主要用到的控件有QComboBox,可以实现下拉菜单功能,还没用过这个控件的小伙伴可以自行百度下,很简单的啦。

2.写串口数据

//发送消息
void uwiCMonitorPC::on_sendMsgBtn_clicked()
{ 
if(O2U1->isChecked()||O2U2->isChecked()||O2U3->isChecked())//判断选择的是那种功能
{
    QString num;
    if(O2U1->isChecked())//配置查询
    {
      int table[20]={0x2e,0x2d,0x3d,0x3e,0x00,0x0d,0x01,0x00,0x00,0x00,0x00};
      int *p=table;
      int wCRC =CRC16(p,11);
      table[11]=wCRC>>8;
      table[12]=wCRC&0x00ff;
      for(int i=0;i<13;i++)
        num+=table[i];
     }  
    else if(O2U2->isChecked())//地址配置
    {
      int table[20]={0x2e,0x2d,0x3d,0x3e,0x00,0x11,0x02,0x00,0x00,0x00,0x00,
0x00,0x0c,0x01,0x02};
      table[11]=edit1->text().toInt();
      int *p=table;
      int wCRC =CRC16(p,15);
      table[15]=wCRC>>8;
      table[16]=wCRC&0x00ff;
      for(int i=0;i<17;i++)
        num+=table[i];
    }
    else if(O2U3->isChecked())//功能配置
    {
       int table[20]={0x2e,0x2d,0x3d,0x3e,0x00,0x0e,0x03,0x00,0x00,0x00};
       if(device->currentText()==tr("投料机"))           table[10]=0x01;
       else if(device->currentText()==tr("增氧泵"))      table[10]=0x02;
       else if(device->currentText()==tr("三合一"))      table[10]=0x03;
       else if(device->currentText()==tr("氨  氮"))      table[10]=0x04;
       else if(device->currentText()==tr("气象站"))      table[10]=0x05;
       else if(device->currentText()==tr("三合一和氨氮")) table[10]=0x06;
       else                                             table[10]=0x07;
       table[11]=edit5->text().toInt();
       int *p=table;
       int wCRC =CRC16(p,12);
       table[12]=wCRC>>8;
       table[13]=wCRC&0x00ff;
       for(int i=0;i<14;i++)
        num+=table[i];
     
    }
    QByteArray outData=num.toAscii();//将16进制数转化为可以发送的QByteArray 数据
    myCom->write(outData);//将数据写入串口
}

数据格式转换真心累啊,我在后面中会给大家介绍我在数据格式转换中遇到的坑,大家可以参考,写入数据部分,其实最主要的控件就是一个lineedit,也即文本框,将要发送的数据输入到文本框,然后读取文本框中的内容即可 table[11]=edit1->text().toInt();将edit1中输入的内容转换成10进制,并存贮在table中,然后就可以写入串口了,当然怎么写入的我们就可以不用管了,你只要负责把数据准备好就可以了,直接送到函数 myCom->write(outData);中就可以了,调用了第三方库,很多步骤我们都省了。

3.读串口数据

if (myCom->bytesAvailable()<=0)
{return;}//如果没有收到数据就返回
    Sleep(100);//延时100ms确保数据可以一次读出
    QByteArray temp = myCom->readAll();//得到全部数据
    QString tempDataHex=uwiCMonitorPC::ByteArrayToHexStr(temp);//字节数组变为字符串
    textBrowser->insertPlainText(tempDataHex+"\n"); //返回数据显示

读串口部分也就是一个函数 myCom->readAll();读之前需要延时一段时间以确保串口数据可以一次接受完成。将得到的数据转换为QString类型,然后就可以送进去显示了。

串口通信主要的核心部分大概就是这三部分了,调用第三方库,主要难点就在于数据类型转换,因为串口发送和文本框接受显示的数据类型是不一样的,还有发送16进制数据时也得进行数据类型转换。反正我在格式转换上面花了很多时间,我在下篇博客中会贴出各种格式转换的代码,供大家参考。

对串口通信原理不了解的可以自己先去网上自行了解下原理,等了解原理后再写串口程序就游润有余了,整个代码我已经打包好了,只要用cmake编译下就可以运行了(所有的控件都是用代码实现的,没有基于qt caeater,控件不是拖拽来的,当然为了学习,为了提高代码能力,我建议不拖拽,如果在实际项目中那就不一样了),我过会会将所有代码上传,有问题的欢迎留言讨论。


关于我自己

一个正派但不正经的程序员

上一篇下一篇

猜你喜欢

热点阅读