zoukankan      html  css  js  c++  java
  • 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("
    ");
    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
  • 相关阅读:
    TypeScript 源码详细解读(3)词法2-标记解析
    TypeScript 源码详细解读(2)词法1-字符处理
    TypeScript 源码详细解读(1)总览
    7年编程语言设计精华总结——写给想创造或正在创造一门新编程语言的同学
    我为什么开发新语言
    CLR值类型和引用类型
    运行时内存模型
    IronPython之基本类型
    .NET 应用程序域?
    .NET程序如何启动?
  • 原文地址:https://www.cnblogs.com/st-home/p/10929020.html
Copyright © 2011-2022 走看看