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 }