[转]qt实现串口通讯 - 纯洁de小学生 - 博客园
摘要:上位机软件程序通过QT实现,采集输入信息,根据实际需要做出合适的串口通讯协议,实现效果如下图所示:
主要实现的功能:
1.串口基本参数可选,可调
2.显示区域可选择十六进制/asicii码显示,可根据自己的需求调整多少字节对齐,显示的比较工整,有利于解析协议
3.可自己制定协议头,其他子项内容都是以十进制输入,内置checksum自动计算
4.实时显示发送/接收字节数
5.可自己定制时间周期定时发送
6.实时显示时间
代码实现:
实现过程较为简单,主要是协议处理:
串口设备:新建串口对象 -> 寻找可用串口设置 -> 设置串口基本参数 -> 打开串口 ->监听串口
串口协议:LineEdit的内容是大端格式,所以使用的时候要将变量转换成大端,默认是小端
注意:
1 QString("%1").arg(ui>lineEdit_S_num>text().toInt(),8,16,QChar('0'))2 3 第一个参数 : 将Qstring转换为int型4 第二个参数 : 需要将几个字符串转换成十六进制的,5 如char型 :需要两个字符6 short型 : 需要四个字符7 int/long : 需要八个字符8 第三个参数: 转换为多少进制9 第四个参数: 不足位数的用0补齐
1 //QByteArray里面的数据按照对应的通讯协议进行调整 2 void Widget::int_adjust(QByteArray &str,qint8 startcount) 3 { 4 qint8 temp1; 5 qint8 temp2; 6 temp1 = str[startcount]; 7 temp2 = str[startcount+1]; 8 str[startcount] = str[startcount+3]; 9 str[startcount+1] = str[startcount+2];10 str[startcount+2] =temp2;11 str[startcount+3] =temp1;12 }13 void Widget::short_adjust(QByteArray &str,qint8 startcount)14 {15 qint8 temp1;16 temp1 = str[startcount];17 str[startcount] = str[startcount+1];18 str[startcount+1] = temp1;19 }
1 //字符串转成十六进制实现 2 void Widget::StringToHex(QString str, QByteArray &senddata) 3 { 4 5 int hexdata,lowhexdata; 6 7 int hexdatalen = 0; 8 9 int len = str.length();10 11 senddata.resize(len/2);12 13 char lstr,hstr;14 15 for(int i=0; i<len; )16 {17 //char lstr,18 hstr=str[i].toLatin1();19 if(hstr == ' ')20 {21 i++;22 continue;23 }24 i++;25 if(i >= len)26 break;27 lstr = str[i].toLatin1();28 hexdata = ConvertHexChar(hstr);29 lowhexdata = ConvertHexChar(lstr);30 if((hexdata == 16) || (lowhexdata == 16))31 break;32 else33 hexdata = hexdata*16+lowhexdata;34 i++;35 senddata[hexdatalen] = (char)hexdata;36 hexdatalen++;37 }38 senddata.resize(hexdatalen);39 }40 41 42 char Widget::ConvertHexChar(char ch)43 {44 if((ch >= '0') && (ch <= '9'))45 return ch-0x30;46 else if((ch >= 'A') && (ch <= 'F'))47 return ch-'A'+10;48 else if((ch >= 'a') && (ch <= 'f'))49 return ch-'a'+10;50 else return (-1);51 52 53 }
要点,易错点基本已经指出,其他的比较简单,这里不再赘叙
1 #include "widget.h" 2 #include "ui_widget.h" 3 #include <QTimer> 4 #include <QDateTime> 5 #include <QMessageBox> 6 static int CountBase = 0; 7 static int SENDNUMSIZE = 20; 8 static int recvCount = 0; 9 Widget::Widget(QWidget *parent) : 10 QWidget(parent), 11 ui(new Ui::Widget) 12 { 13 ui->setupUi(this); 14 serial = new QSerialPort; 15 /* regester software timer*/ 16 atimer = new QTimer(); 17 atimer->setInterval(1000); 18 atimer->start(); 19 20 cycletime = new QTimer(); 21 cycletime->setInterval(ui->lineEdit_cycletime->text().toInt()); 22 23 QObject::connect(atimer,&QTimer::timeout,this,&Widget::timer_handle); 24 25 //查找可用的串口 26 foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts()) 27 { 28 QSerialPort serial; 29 serial.setPort(info); 30 if(serial.open(QIODevice::ReadWrite)) 31 { 32 ui->comBox->addItem(serial.portName()); 33 serial.close(); 34 } 35 } 36 //设置波特率下拉菜单默认显示第0项 37 ui->baudBox->setCurrentIndex(0); 38 ui->baudBox->setEnabled(false); 39 ui->stopbitBox->setEnabled(false); 40 ui->databitBox->setEnabled(false); 41 ui->checkBox->setEnabled(false); 42 ui->comBox->setEnabled(false); 43 } 44 45 Widget::~Widget() 46 { 47 delete ui; 48 } 49 void Widget::timer_handle(void) 50 { 51 52 QDateTime current_date_time =QDateTime::currentDateTime(); 53 QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss ddd"); 54 // ui->textBrowser_date 55 ui->label_date->setText(current_date); 56 57 } 58 59 void Widget::on_pushButton_oprea_clicked() 60 { 61 if(ui->pushButton_oprea->text() == tr("串口已关闭")) 62 { 63 serial = new QSerialPort; 64 //设置串口名 65 serial->setPortName(ui->comBox->currentText()); 66 //打开串口 67 serial->open(QIODevice::ReadWrite); 68 //设置波特率 69 serial->setBaudRate(QSerialPort::Baud115200);//设置波特率为115200 70 //设置数据位数 71 switch (ui->databitBox->currentIndex()) 72 { 73 case 0: 74 serial->setDataBits(QSerialPort::Data8);//设置数据位8 75 break; 76 default: 77 break; 78 } 79 //设置校验位 80 switch (ui->checkBox->currentIndex()) 81 { 82 case 0: 83 serial->setParity(QSerialPort::NoParity); 84 break; 85 default: 86 break; 87 } 88 //设置停止位 89 switch (ui->stopbitBox->currentIndex()) 90 { 91 case 0: 92 serial->setStopBits(QSerialPort::OneStop);//停止位设置为1 93 break; 94 case 1: 95 serial->setStopBits(QSerialPort::TwoStop); 96 default: 97 break; 98 } 99 //设置流控制100 serial->setFlowControl(QSerialPort::NoFlowControl);//设置为无流控制101 102 //关闭设置菜单使能103 ui->baudBox->setEnabled(true);104 ui->stopbitBox->setEnabled(true);105 ui->databitBox->setEnabled(true);106 ui->checkBox->setEnabled(true);107 ui->comBox->setEnabled(true);108 ui->pushButton_oprea->setText(tr("串口已打开"));109 110 //连接信号槽111 QObject::connect(serial,&QSerialPort::readyRead,this,&Widget::ReadData);112 }113 else114 {115 cycletime->stop();116 //关闭串口117 serial->clear();118 serial->close();119 serial->deleteLater();120 121 //恢复设置使能122 ui->baudBox->setEnabled(false);123 ui->stopbitBox->setEnabled(false);124 ui->databitBox->setEnabled(false);125 ui->checkBox->setEnabled(false);126 ui->comBox->setEnabled(false);127 ui->pushButton_oprea->setText(tr("串口已关闭"));128 }129 }130 //读取接收到的信息131 void Widget::ReadData()132 {133 QByteArray temp;134 if(ui->HEX_SHOW->isChecked())135 {136 SENDNUMSIZE = ui->lineEdit_duiqi->text().toInt();137 temp = serial->readAll();138 QDataStream out(&temp,QIODevice::ReadWrite); //将字节数组读入139 while(!out.atEnd())140 {141 qint8 outChar = 0;142 static qint8 datacount = 1;143 recvCount++;144 out>>outChar; //每字节填充一次,直到结束145 datacount++;146 //十六进制的转换147 QString str = QString(" %1").arg(outChar&0xFF,2,16,QLatin1Char('0'));148 ui->textBrowser->insertPlainText(str);149 ui->label_recvvalue->setNum(recvCount);150 if(SENDNUMSIZE+2 == datacount)151 {152 datacount = 1;153 ui->textBrowser->insertPlainText("\n");154 ui->textBrowser->moveCursor(QTextCursor::End);155 }156 }157 }158 else159 {160 161 temp += serial->readAll();162 if(!temp.isEmpty())163 {164 ui->textBrowser->append(temp);165 ui->textBrowser->moveCursor(QTextCursor::End);166 }167 temp.clear();168 }169 170 }171 short Widget::checksum(QByteArray ba)172 {173 short i = 0,sumValue = 0;174 175 for(i=2;i<(ba.length());i++)176 {177 sumValue+=ba.at(i);178 }179 return sumValue;180 }181 182 void Widget::on_send_clicked()183 {184 short checkValue = 0;185 QString str;186 QByteArray senddata;187 if(ui->pushButton_oprea->text() == tr("串口已关闭"))188 {189 QMessageBox::information(this, "warning", "串口没打开", QMessageBox::Yes);190 191 }192 if(ui->radio_dash->isChecked())193 {194 str = ui->lineEdit_head->text()195 + QString("%1").arg(ui->lineEdit_infopage->text().toShort(),2,16,QChar('0'))196 + QString("%1").arg(ui->lineEdit_menu->text().toShort(),2,16,QChar('0'))197 + QString("%1").arg(ui->lineEdit_speed->text().toShort(),2,16,QChar('0'))198 + QString("%1").arg(ui->lineEdit_FP->text().toShort(),2,16,QChar('0'))199 + QString("%1").arg(ui->lineEdit_BP->text().toShort(),2,16,QChar('0'))200 + QString("%1").arg(ui->lineEdit_gear->text().toShort(),2,16,QChar('0'))201 + QString("%1").arg(ui->lineEdit_hour->text().toShort(),2,16,QChar('0'))202 + QString("%1").arg(ui->lineEdit_minute->text().toShort(),2,16,QChar('0'))203 + QString("%1").arg(ui->lineEdit_TemP->text().toShort(),4,16,QChar('0'))//10204 + QString("%1").arg(ui->lineEdit_trip->text().toShort(),4,16,QChar('0'))//12205 + QString("%1").arg(ui->lineEdit_C_Trip->text().toShort(),4,16,QChar('0'))//14206 + QString("%1").arg(ui->lineEdit_odo->text().toInt(),8,16,QChar('0'))//16207 + QString("%1").arg(ui->lineEdit_LF_Press->text().toShort(),4,16,QChar('0'))//20208 + QString("%1").arg(ui->lineEdit_LB_Press->text().toShort(),4,16,QChar('0'))//22209 + QString("%1").arg(ui->lineEdit_RF_Press->text().toShort(),4,16,QChar('0'))//24210 + QString("%1").arg(ui->lineEdit_RB_Press->text().toShort(),4,16,QChar('0'))//26211 + QString("%1").arg(ui->lineEdit_oil_cost->text().toInt(),8,16,QChar('0'))//28212 + QString("%1").arg(ui->lineEdit_C_oilcost->text().toShort(),2,16,QChar('0'))213 + QString("%1").arg(ui->lineEdit_AV_oil_cost->text().toShort(),2,16,QChar('0'))214 + QString("%1").arg(ui->lineEdit_can_warning->text().toShort(),2,16,QChar('0'))215 + QString("%1").arg(ui->lineEdit_icon->text().toShort(),4,16,QChar('0'))//35216 + QString("%1").arg(ui->lineEdit_backlight->text().toShort(),2,16,QChar('0'));217 /*************** 调整short 和 init 数据类型字节发送顺序 ****************/218 StringToHex(str,senddata);//将str字符串转换为16进制的形式219 short_adjust(senddata,10);220 short_adjust(senddata,12);221 short_adjust(senddata,14);222 int_adjust(senddata,16);223 short_adjust(senddata,20);224 short_adjust(senddata,22);225 short_adjust(senddata,24);226 short_adjust(senddata,26);227 int_adjust(senddata,28);228 short_adjust(senddata,35);229 }230 else{231 str = ui->lineEdit_head->text()232 + QString("%1").arg(ui->lineEdit_ST_Page->text().toShort(),2,16,QChar('0'))233 + QString("%1").arg(ui->lineEdit_menu_level->text().toShort(),2,16,QChar('0'))234 + QString("%1").arg(ui->lineEdit_cursor->text().toShort(),2,16,QChar('0'))235 + QString("%1").arg(ui->lineEdit_C_selcet->text().toShort(),2,16,QChar('0'))236 + QString("%1").arg(ui->lineEdit_num->text().toShort(),2,16,QChar('0'))237 + QString("%1").arg(ui->lineEdit_S_num->text().toInt(),8,16,QChar('0'))238 + QString("%1").arg(ui->lineEdit_S_hour->text().toShort(),2,16,QChar('0'))239 + QString("%1").arg(ui->lineEdit_S_minute->text().toShort(),2,16,QChar('0'))240 + QString("%1").arg(ui->lineEdit_S_year->text().toShort(),4,16,QChar('0'))241 + QString("%1").arg(ui->lineEdit_S_month->text().toShort(),2,16,QChar('0'))242 + QString("%1").arg(ui->lineEdit_S_day->text().toShort(),2,16,QChar('0'))243 + QString("%1").arg(ui->lineEdit_S_backlight->text().toShort(),2,16,QChar('0'));244 /*************** 调整short 和 init 数据类型字节发送顺序 ****************/245 StringToHex(str,senddata);//将str字符串转换为16进制的形式246 int_adjust(senddata,7);247 short_adjust(senddata,13);248 }249 250 251 checkValue = checksum(senddata);252 senddata.append((char)(checkValue));253 serial->write(senddata);//发送到串口254 CountBase+=senddata.length();255 256 ui->label_sendvalue->setNum(CountBase);257 }258 void Widget::int_adjust(QByteArray &str,qint8 startcount)259 {260 qint8 temp1;261 qint8 temp2;262 temp1 = str[startcount];263 temp2 = str[startcount+1];264 str[startcount] = str[startcount+3];265 str[startcount+1] = str[startcount+2];266 str[startcount+2] =temp2;267 str[startcount+3] =temp1;268 }269 void Widget::short_adjust(QByteArray &str,qint8 startcount)270 {271 qint8 temp1;272 temp1 = str[startcount];273 str[startcount] = str[startcount+1];274 str[startcount+1] = temp1;275 }276 277 void Widget::StringToHex(QString str, QByteArray &senddata)278 {279 280 int hexdata,lowhexdata;281 282 int hexdatalen = 0;283 284 int len = str.length();285 286 senddata.resize(len/2);287 288 char lstr,hstr;289 290 for(int i=0; i<len; )291 {292 //char lstr,293 hstr=str[i].toLatin1();294 if(hstr == ' ')295 {296 i++;297 continue;298 }299 i++;300 if(i >= len)301 break;302 lstr = str[i].toLatin1();303 hexdata = ConvertHexChar(hstr);304 lowhexdata = ConvertHexChar(lstr);305 if((hexdata == 16) || (lowhexdata == 16))306 break;307 else308 hexdata = hexdata*16+lowhexdata;309 i++;310 senddata[hexdatalen] = (char)hexdata;311 hexdatalen++;312 }313 senddata.resize(hexdatalen);314 }315 316 317 char Widget::ConvertHexChar(char ch)318 {319 if((ch >= '0') && (ch <= '9'))320 return ch-0x30;321 else if((ch >= 'A') && (ch <= 'F'))322 return ch-'A'+10;323 else if((ch >= 'a') && (ch <= 'f'))324 return ch-'a'+10;325 else return (-1);326 327 328 }329 330 331 void Widget::on_pushButton_clicked()332 {333 ui->textBrowser->clear();334 CountBase = 0;335 ui->label_sendvalue->setNum(0);336 recvCount = 0;337 ui->label_recvvalue->setNum(0);338 }339 void Widget::cycletime_handle(void)340 {341 on_send_clicked();342 }343 void Widget::on_lineEdit_duiqi_editingFinished()344 {345 SENDNUMSIZE = ui->lineEdit_duiqi->text().toInt();346 }347 348 void Widget::on_checkBox_TIMER_stateChanged(int arg1)349 {350 if(ui->checkBox_TIMER->isChecked())351 {352 cycletime->start();353 QObject::connect(cycletime,&QTimer::timeout,this,&Widget::cycletime_handle);354 }355 else356 {357 cycletime->stop();358 }359 360 }
---------------------
作者:纯洁de小学生
来源:CNBLOGS
原文:https://www.cnblogs.com/st-home/p/10929020.html
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件