最近帮老师做的项目中使用到了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,控件不是拖拽来的,当然为了学习,为了提高代码能力,我建议不拖拽,如果在实际项目中那就不一样了),我过会会将所有代码上传,有问题的欢迎留言讨论。
关于我自己
一个正派但不正经的程序员
-
18年计算机专业硕士毕业生,腾讯SNG部门实习生,现加盟快手科技 ,后端研发工程师一枚
-
喜欢技术,喜欢互联网
-
民遥控 ,赵雷、陈粒、宋冬野
-
时不时写篇文章,偶尔数羊,其实说到底,只是想和你聊聊
网友评论