qt实现串口通讯

摘要:上位机软件程序通过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         else
33             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         else
114         {
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     else
159     {
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'))//10
204                 + QString("%1").arg(ui->lineEdit_trip->text().toShort(),4,16,QChar('0'))//12
205                 + QString("%1").arg(ui->lineEdit_C_Trip->text().toShort(),4,16,QChar('0'))//14
206                 + QString("%1").arg(ui->lineEdit_odo->text().toInt(),8,16,QChar('0'))//16
207                 + QString("%1").arg(ui->lineEdit_LF_Press->text().toShort(),4,16,QChar('0'))//20
208                 + QString("%1").arg(ui->lineEdit_LB_Press->text().toShort(),4,16,QChar('0'))//22
209                 + QString("%1").arg(ui->lineEdit_RF_Press->text().toShort(),4,16,QChar('0'))//24
210                 + QString("%1").arg(ui->lineEdit_RB_Press->text().toShort(),4,16,QChar('0'))//26
211                 + QString("%1").arg(ui->lineEdit_oil_cost->text().toInt(),8,16,QChar('0'))//28
212                 + 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'))//35
216                 + 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         else
308             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     else
356     {
357         cycletime->stop();
358     }
359 
360 }
all code

 

posted @ 2019-05-27 09:26  纯洁de小学生  阅读(6671)  评论(0编辑  收藏  举报