關(guān)于QT串口通信的一點理解

最近幫老師做的項目中使用到了QT串口,然后首先百度了一下,發(fā)現(xiàn)網(wǎng)上的QT串口代碼都是同一個版本。而且沒有公開源代碼,遂自己寫了個簡單的串口通信代碼,并將它公布出來,一方面供有需要的人參考,另一方面記錄下來,也可以防止自己忘記了。

本項目沒有用到QT自帶的串口通信模塊,使用了第三方庫qextserialport,這個庫基本已經(jīng)滿足了串口所有的功能,而且上手也快。好了。廢話不多說了,先來張效果圖吧。


這是整體效果圖,主要實現(xiàn)的是開發(fā)板和下位機通信,上位機通過串口發(fā)送指令給下位機,下位機再執(zhí)行相應(yīng)的操作。本文主要講講串口通信的部分吧。

簡單來說,串口通信分為三部分:1:設(shè)置端口號和波特率等等,數(shù)據(jù)位和校驗之類的一般的可以提前設(shè)定好,再代碼中同樣也可以設(shè)定。2:將數(shù)據(jù)寫入串口,這個時候就要分發(fā)送的是多少進(jìn)制的數(shù)據(jù)了,雖然計算機在實際存儲時是不區(qū)分進(jìn)制的。3:讀串口數(shù)據(jù),將串口接收到的數(shù)據(jù)讀出來,進(jìn)行下一步處理。后面我會把全部代碼貼出來,代碼經(jīng)過調(diào)試已經(jīng)可以運行了。本文中具體的控件布局我就不講了,我只講講一些核心的代碼,大家感興趣的話可以自己去跑跑我的代碼,代碼中注釋非常詳細(xì),每一行都有注釋,看起來不費勁。

1.設(shè)置端口和波特率

//打開串口,波特率和端口號可以通過下拉菜單進(jìn)行選擇
void uwiCMonitorPC::on_openMyComBtn_clicked()
{
    QString portName = portNameComboBox->currentText(); //獲取串口名
    myCom = new Win_QextSerialPort(portName,QextSerialBase::EventDriven);
    //定義串口對象,并傳遞參數(shù),在構(gòu)造函數(shù)里對其進(jìn)行初始化
    myCom ->open(QIODevice::ReadWrite); //打開串口
    if(baudRateComboBox->currentText()==tr("38400")) //根據(jù)下拉菜單中內(nèi)容對串口進(jìn)行設(shè)置
    //設(shè)置波特率
    myCom->setBaudRate(BAUD38400);
    else if(baudRateComboBox->currentText()==tr("115200"))
    myCom->setBaudRate(BAUD115200);
    //設(shè)置數(shù)據(jù)位
    myCom->setDataBits(DATA_8);
    //設(shè)置奇偶校驗
    myCom->setParity(PAR_NONE);
    //設(shè)置停止位 
    myCom->setStopBits(STOP_1);    
    myCom->setFlowControl(FLOW_OFF);  //設(shè)置數(shù)據(jù)流控制,我們使用無數(shù)據(jù)流控制的默認(rèn)設(shè)置
    myCom->setTimeout(500);  //設(shè)置延時
    connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
    //信號和槽函數(shù)關(guān)聯(lián),當(dāng)串口緩沖區(qū)有數(shù)據(jù)時,進(jìn)行讀串口操作
    openMyComBtn->setEnabled(false); //打開串口后“打開串口”按鈕不可用
    closeMyComBtn->setEnabled(true); //打開串口后“關(guān)閉串口”按鈕可用
    sendMsgBtn->setEnabled(true); //打開串口后“發(fā)送數(shù)據(jù)”按鈕可用
    O2U1->setEnabled(true);
    O2U2->setEnabled(true);
    O2U3->setEnabled(true);
    baudRateComboBox->setEnabled(false); //設(shè)置各個組合框不可用
    portNameComboBox->setEnabled(false);
}

在端口設(shè)置和波特率配置中,主要用到的控件有QComboBox,可以實現(xiàn)下拉菜單功能,還沒用過這個控件的小伙伴可以自行百度下,很簡單的啦。

2.寫串口數(shù)據(jù)

//發(fā)送消息
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進(jìn)制數(shù)轉(zhuǎn)化為可以發(fā)送的QByteArray 數(shù)據(jù)
    myCom->write(outData);//將數(shù)據(jù)寫入串口
}

數(shù)據(jù)格式轉(zhuǎn)換真心累啊,我在后面中會給大家介紹我在數(shù)據(jù)格式轉(zhuǎn)換中遇到的坑,大家可以參考,寫入數(shù)據(jù)部分,其實最主要的控件就是一個lineedit,也即文本框,將要發(fā)送的數(shù)據(jù)輸入到文本框,然后讀取文本框中的內(nèi)容即可 table[11]=edit1->text().toInt();將edit1中輸入的內(nèi)容轉(zhuǎn)換成10進(jìn)制,并存貯在table中,然后就可以寫入串口了,當(dāng)然怎么寫入的我們就可以不用管了,你只要負(fù)責(zé)把數(shù)據(jù)準(zhǔn)備好就可以了,直接送到函數(shù) myCom->write(outData);中就可以了,調(diào)用了第三方庫,很多步驟我們都省了。

3.讀串口數(shù)據(jù)

if (myCom->bytesAvailable()<=0)
{return;}//如果沒有收到數(shù)據(jù)就返回
    Sleep(100);//延時100ms確保數(shù)據(jù)可以一次讀出
    QByteArray temp = myCom->readAll();//得到全部數(shù)據(jù)
    QString tempDataHex=uwiCMonitorPC::ByteArrayToHexStr(temp);//字節(jié)數(shù)組變?yōu)樽址?    textBrowser->insertPlainText(tempDataHex+"\n"); //返回數(shù)據(jù)顯示

讀串口部分也就是一個函數(shù) myCom->readAll();讀之前需要延時一段時間以確保串口數(shù)據(jù)可以一次接受完成。將得到的數(shù)據(jù)轉(zhuǎn)換為QString類型,然后就可以送進(jìn)去顯示了。

串口通信主要的核心部分大概就是這三部分了,調(diào)用第三方庫,主要難點就在于數(shù)據(jù)類型轉(zhuǎn)換,因為串口發(fā)送和文本框接受顯示的數(shù)據(jù)類型是不一樣的,還有發(fā)送16進(jìn)制數(shù)據(jù)時也得進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換。反正我在格式轉(zhuǎn)換上面花了很多時間,我在下篇博客中會貼出各種格式轉(zhuǎn)換的代碼,供大家參考。

對串口通信原理不了解的可以自己先去網(wǎng)上自行了解下原理,等了解原理后再寫串口程序就游潤有余了,整個代碼我已經(jīng)打包好了,只要用cmake編譯下就可以運行了(所有的控件都是用代碼實現(xiàn)的,沒有基于qt caeater,控件不是拖拽來的,當(dāng)然為了學(xué)習(xí),為了提高代碼能力,我建議不拖拽,如果在實際項目中那就不一樣了),我過會會將所有代碼上傳,有問題的歡迎留言討論。


關(guān)于我自己

一個正派但不正經(jīng)的程序員

  • 18年計算機專業(yè)碩士畢業(yè)生,騰訊SNG部門實習(xí)生,現(xiàn)加盟快手科技 ,后端研發(fā)工程師一枚

  • 喜歡技術(shù),喜歡互聯(lián)網(wǎng)

  • 民遙控 ,趙雷、陳粒、宋冬野

  • 時不時寫篇文章,偶爾數(shù)羊,其實說到底,只是想和你聊聊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 姓名:莫益彰 學(xué)號:16030140019 【嵌牛導(dǎo)讀】:串口通信是指外設(shè)和計算機間,通過數(shù)據(jù)信號線 、地線、控制...
    換個名字消消毒閱讀 1,668評論 1 5
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,667評論 25 709
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 13,881評論 2 59
  • 茶靡花開,陌路之美。 孤首望河畔,夕陽斜下,不知離人淚。 心中難緬舊時光,杯中清酒一飲盡。 飛鴿...
    a36e8aaff5a5閱讀 498評論 0 0
  • 文/逐夢水鄉(xiāng) 前幾天,寫的一篇《來,考考你,這道題的答案是多少》,寥寥幾百字,閱讀量居然過了一萬,而且還有上漲的趨...
    逐夢水鄉(xiāng)閱讀 424評論 16 26

友情鏈接更多精彩內(nèi)容