摘要:上位機軟件程序通過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 }