Qt编写串口通信程序
- 格式:pdf
- 大小:1.20 MB
- 文档页数:19
Qt下实现多线程的串⼝通信简述Qt下⽆论是RS232、RS422、RS485的串⼝通信都可以使⽤统⼀的编码实现。
本⽂把每路串⼝的通信各放在⼀个线程中,使⽤movetoThread的⽅式实现。
代码之路⽤SerialPort类实现串⼝功能,Widget类调⽤串⼝。
serialport.h如下#include <QObject>#include <QSerialPort>#include <QString>#include <QByteArray>#include <QObject>#include <QDebug>#include <QObject>#include <QThread>class SerialPort : public QObject{Q_OBJECTpublic:explicit SerialPort(QObject *parent = NULL);~SerialPort();void init_port(); //初始化串⼝public slots:void handle_data(); //处理接收到的数据void write_data(); //发送数据signals://接收数据void receive_data(QByteArray tmp);private:QThread *my_thread;QSerialPort *port;};serailport.cpp如下#include "serialport.h"SerialPort::SerialPort(QObject *parent) : QObject(parent){my_thread = new QThread();port = new QSerialPort();init_port();this->moveToThread(my_thread);port->moveToThread(my_thread);my_thread->start(); //启动线程}SerialPort::~SerialPort(){port->close();port->deleteLater();my_thread->quit();my_thread->wait();my_thread->deleteLater();}void SerialPort::init_port(){port->setPortName("/dev/ttyS1"); //串⼝名 windows下写作COM1port->setBaudRate(38400); //波特率port->setDataBits(QSerialPort::Data8); //数据位port->setStopBits(QSerialPort::OneStop); //停⽌位port->setParity(QSerialPort::NoParity); //奇偶校验port->setFlowControl(QSerialPort::NoFlowControl); //流控制if (port->open(QIODevice::ReadWrite)){qDebug() << "Port have been opened";}else{qDebug() << "open it failed";}connect(port, SIGNAL(readyRead()), this, SLOT(handle_data()), Qt::QueuedConnection); //Qt::DirectConnection }void SerialPort::handle_data(){QByteArray data = port->readAll();qDebug() << QStringLiteral("data received(收到的数据):") << data;qDebug() << "handing thread is:" << QThread::currentThreadId();emit receive_data(data);}void SerialPort::write_data(){qDebug() << "write_id is:" << QThread::currentThreadId();port->write("data", 4); //发送“data”字符}widget.h的调⽤代码#include "serialport.h"public slots:void on_receive(QByteArray tmpdata);private:SerialPort *local_serial;widget.cpp调⽤代码//构造函数中local_serial = new SerialPort();connect(ui->pushButton, SIGNAL(clicked()), local_serial, SLOT(write_data()),Qt::QueuedConnection);connect(local_serial, SIGNAL(receive_data(QByteArray)), this, SLOT(on_receive(QByteArray)), Qt::QueuedConnection);//on_receive槽函数void Widget::on_receive(QByteArray tmpdata){ui->textEdit->append(tmpdata);}写在最后本⽂例⼦实现的串⼝号是 /dev/ttyS1(对应windows系统是COM1⼝),波特率38400,数据位8,停⽌位1,⽆校验位的串⼝通信。
Qt串口通信编程开发环境配置目录1 开发环境 (1)1.1 编程环境 (1)1.2 工程设置 (1)1.3 调试窗口设置 (2)1.4 依赖库 (2)1.5 源代码的适配 (2)2 运行及硬件环境 (3)2.1 串口设备 (3)2.2 虚拟串口工具 (3)2.3 串口调试助手 (3)2.4 运行支持文件 (3)3 第三方串口库的生成 (4)3.1 打开源码里的工程 (4)3.2 qextserialport源码问题解决 (4)4 故障解决 (5)4.1 转到槽函数失败 (5)积分下载本文档可免费提供技术支持。
1 开发环境1.1 编程环境工程采用Windows系统下的Qt Creator开发环境,Qt版本5.10.1(Qt的较新版,Bug 较少,支持串口库,图形库QChart),安装文件qt-opensource-windows-x86-5.10.1.exe安装的编译器采用MinGW32. 。
MARK32000-采用的串口时Qt自带串口库QSerialPort,若需第三方串口库可自行编译。
1.2 工程设置工程设置:在XXXX.pro文件中添加下面两行:QT += serialport #添加Qt串口支持CONFIG += console #显示控制台提示窗口,以方便调试,注释掉即可不显示黑色命令提示框如果采用第三方的串口库(本软件不含第三方库源代码),而不采用Qt的串口库,则要添加如下工程:INCLUDEPATH += qextserialport-1.2win-alphaLIBS += -L "../SerialProtocol/qextserialport-1.2win-alpha/build/" -lqextserialportd若路径找不到,可改成绝对路径。
相对路径基于项目生成的build路径,需要将第三方串口库“qextserialport”的生成文件“build”目录下的qextserialportd.a .dll拷贝到build-SerialProtocol-Desktop_Qt_5_10_1_MinGW_32bit-Debug目录下。
Qt编写串口通信程序全程图文讲解(一)(原创)首先说明我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写,程序稍有不同,请自己改动。
在Qt中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport 类,我们这里也是使用的该类。
我们可以去/projects/qextserialport/files/进行下载,也可以去下载论坛上的/bbs/read.php?tid=22847下载到的文件为:qextserialport-1.2win-alpha.zip其内容如下图:我们在windows下只需要使用其中的6个文件:qextserialbase.cpp和qextserialbase.h,qextserialport.cpp和qextserialport.h,win_qextserialport.cpp和win_qextserialport.h如果在Linux下只需将win_qextserialport.cpp和win_qextserialport.h 换为posix_qextserialport.cpp和posix_qextserialport.h即可。
下面我们将讲述详细编程过程,这里我们先给出完整的程序,然后再进行逐句分析。
1.打开Qt Creator,新建Qt4 Gui Application,工程名设置为mycom,其他使用默认选项。
(注意:建立的工程路径不能有中文。
)2.将上面所说的6个文件复制到工程文件夹下,如下图。
3.在工程中添加这6个文件。
在Qt Creator中左侧的文件列表上,鼠标右击工程文件夹,在弹出的菜单中选择Add Existing Files,添加已存在的文件。
如下图:选择工程文件夹里的那6个文件,进行添加。
如下图。
添加好后文件列表如下图所示:4.点击mainwindow.ui,在窗口上加入一个Text Browser,用来显示信息。
Qt中的串⼝编程串⾏接⼝简称串⼝,也称串⾏通信接⼝或串⾏通讯接⼝(通常指COM接⼝),是采⽤串⾏通信⽅式的扩展接⼝。
串⾏接⼝(Serial Interface) 是指数据⼀位⼀位地顺序传送,其特点是通信线路简单,只要⼀对传输线就可以实现双向通信,⼤⼤降低了成本,特别适⽤于远距离通信,但传送速度较慢。
根据信息的传送⽅向,串⾏通讯可以进⼀步分为单⼯、半双⼯和全双⼯三种。
串⾏接⼝按电⽓标准及协议来分包括RS-232-C、RS-422、RS485等。
异步串⾏是指UART(Universal Asynchronous Receiver/Transmitter),通⽤异步接收/发送。
UART包含TTL电平的串⼝和RS232电平的串⼝。
TTL电平是3.3V的,⽽RS232是负逻辑电平,它定义+5~+12V为低电平,⽽-12~-5V为⾼电平。
UART作为异步串⼝通信协议的⼀种,⼯作原理是将传输数据的每个字符⼀位接⼀位地传输,其中各位的意义如下:起始位:先发出⼀个逻辑”0”的信号,表⽰传输字符的开始。
数据位:紧接在起始位之后,数据位的个数可以是4、5、6、7、8等,构成⼀个字符,从最低位开始传送,靠时钟定位。
奇偶校验位:数据位加上这⼀位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。
停⽌位:它是⼀个字符数据的结束标志,可以是1位、1.5位、2位的⾼电平。
由于数据是在传输线上定时的,并且每⼀个设备有其⾃⼰的时钟,很可能在通信中两台设备间出现了⼩⼩的不同步。
因此停⽌位不仅仅是表⽰传输的结束,并且提供计算机校正时钟同步的机会。
适⽤于停⽌位的位数越多,不同时钟同步的容忍程度越⼤,但是数据传输率同时也越慢。
空闲位:处于逻辑“1”状态,表⽰当前线路上没有数据传送。
此外,在异步通信中还有⼀个重要的参数,即波特率,它是衡量数据传送速率的指标,表⽰每秒钟传送的符号数(symbol)。
收发双⽅的波特率必须保持⼀致,才能保证数据的正常通信。
qserialport高级编程QSerialPort是Qt框架中用于串口通信的类,它提供了一种方便的方式来在Qt应用程序中进行串口通信。
在进行QSerialPort高级编程时,我们可以从以下几个方面来全面了解和使用它:1. 打开和关闭串口,使用QSerialPort类可以很容易地打开和关闭串口。
在打开串口时,我们可以设置串口的参数,如波特率、数据位、停止位和校验位等。
而在关闭串口时,我们需要确保在不需要使用串口时及时关闭,以释放资源。
2. 读写数据,QSerialPort类提供了read和write方法来进行数据的读取和写入。
在高级编程中,我们可以通过设置超时时间、使用信号槽机制等方式来确保数据的稳定和准确的读写。
3. 错误处理,在串口通信中,可能会出现各种错误,如串口无法打开、数据传输超时、校验错误等。
在高级编程中,我们需要考虑如何处理这些错误,可以通过捕获错误码、设置错误处理策略等方式来保证程序的稳定性和可靠性。
4. 事件驱动,QSerialPort类支持事件驱动的串口通信,我们可以利用信号槽机制来处理串口事件,比如数据到达事件、错误事件等。
在高级编程中,我们可以充分利用事件驱动的特性来实现更加灵活和高效的串口通信。
5. 跨平台兼容性,Qt框架具有良好的跨平台兼容性,因此使用QSerialPort进行高级编程时,可以在不同的操作系统上实现相似的串口通信功能,这为开发者提供了很大的便利。
总之,QSerialPort类提供了丰富的API和功能,可以满足各种复杂的串口通信需求。
在进行高级编程时,我们需要充分了解其特性和用法,从多个角度全面考虑和处理各种情况,以确保程序的稳定性和可靠性。
Qt 串行通讯Hanford2016年11月09日目录目录第1章Qt 串行通讯 (1)1.1 配置.pro文件 (1)1.2 查询串口信息 (1)1.3 配置、打开串口 (3)1.4 setRequestToSend在Windows上的BUG (5)1.5 读取串口数据 (6)1.6 发送串口数据 (7)1.7 同步读取 (7)1.8 本文示例代码 (8)1.9 Qt 示例代码 (10)I第1章Qt 串行通讯最近要在Android 手机上开发串行通讯程序,为此学习了一下Qt的串行通讯。
本文中,Qt的版本为 5.7.0。
1.1 配置.pro文件使用Qt 5.7.0 创建“Qt Widgets Application”类型的项目,然后修改.pro 文件,如下图所示:图1.1给变量QT 增加serialport,说明程序里将使用串行通讯相关的类。
1.2 查询串口信息本节将通过代码查找系统里的串口,然后填入下图所示的下拉列表框中。
1图1.2函数QSerialPortInfo::availablePorts 会返回系统所有的串口,它的使用请函数GetIntInStr 根据串口名称(如COM5)获取串口号(如:5),其代码2根据std::map<int,QString> mapPort填充下拉列表框QComboBox cboPort1.3 配置、打开串口34首先new 一个QSerialPort 对象,然后设置该对象的串行通讯参数,最后调用QSerialPort::open 函数打开串口。
这里需要说明一下流控制。
通讯的双方A 和B ,假如A 给B 发送数据时,B 反应过慢,A 不管不顾的不停发送数据,结果会导致数据丢失。
为了防止这种情况发生,可使用流控制(也叫握手)。
软件流控制(XON/XOFF ):通讯的一方(B )如果不能及时处理串口数据,会给对方(A )发送XOFF 字符,对方接收到这个字符后,会停止发送数据;B 不再忙的时候,会给A 发送XON 字符,A 接收到这个字符后,会接着发送数据。
qt串口通信讲义摘要:1.QT 串口通信概述2.QT 串口通信的基本步骤3.QT 串口通信的实现方法4.QT 串口通信的注意事项5.总结正文:一、QT 串口通信概述QT 串口通信是指通过串口(RS-232 或者RS-485)在QT 应用程序中实现数据传输的一种通信方式。
串口通信在电子设备、计算机外设、通信设备等领域有着广泛的应用。
QT 作为一款跨平台的C++图形用户界面库,提供了丰富的串口通信功能,使得开发者可以方便地实现串口通信应用。
二、QT 串口通信的基本步骤1.创建串口对象在QT 中,需要先创建一个串口对象,可以使用`QSerialPort`类或者`QSerialPortInfo`类来创建。
其中,`QSerialPort`类用于实现串口通信,而`QSerialPortInfo`类用于获取系统中可用的串口信息。
2.配置串口参数创建串口对象后,需要配置串口的相关参数,例如波特率、数据位、停止位等。
可以使用`QSerialPort`类的相关方法进行配置。
3.开启串口配置好串口参数后,需要调用`QSerialPort`类的`open()`方法开启串口。
在此之前,还可以调用`setReadBufferSize()`和`setWriteBufferSize()`方法设置读写缓冲区大小,以提高通信效率。
4.读写数据开启串口后,可以使用`QSerialPort`类的`readAll()`、`readLine()`或者`readPlainText()`方法读取数据,使用`write()`或者`writePlainText()`方法发送数据。
5.关闭串口通信完成后,需要调用`QSerialPort`类的`close()`方法关闭串口。
三、QT 串口通信的实现方法1.使用`QSerialPort`类`QSerialPort`类提供了一系列的方法来实现串口通信,如上文所述的基本步骤中所示。
2.使用`QSerialPortInfo`类`QSerialPortInfo`类可以用于获取系统中可用的串口信息,然后通过`QSerialPort`类创建串口对象并实现通信。
qt串口编程协议解析Qt串口编程是一种用于在Qt应用程序中实现串口通信的技术。
串口通信是一种用于在设备之间传输数据的通信方式,它通常用于连接嵌入式系统、传感器、微控制器等设备。
在Qt中,可以使用Qt Serial Port模块来实现串口通信。
该模块提供了一组类和函数,可以方便地进行串口的配置、打开、关闭、读取和写入操作。
在Qt中进行串口编程的第一步是创建一个QSerialPort对象,并对其进行配置,包括设置串口号、波特率、数据位、校验位、停止位等参数。
然后可以通过open()函数打开串口,通过write()函数向串口写入数据,通过read()函数从串口读取数据,通过close()函数关闭串口。
当涉及到串口通信时,协议解析是一个重要的环节。
协议解析是指根据约定的协议规则对从串口中读取的原始数据进行解析和处理,以获取有意义的信息。
在实际应用中,通常会定义一种通信协议,包括数据包格式、数据帧结构、校验方式等。
在Qt中,可以通过解析原始数据来实现协议解析,从而将原始数据转换为应用程序可以识别和处理的数据。
在进行协议解析时,需要根据通信协议的规定对从串口中读取的数据进行解析,提取出有用的信息,并进行相应的处理。
这可能涉及到数据包的拆分、字段的提取、校验和错误处理等操作。
在Qt 中,可以借助QString、QByteArray等类来处理从串口读取的原始数据,进行数据解析和处理。
总的来说,Qt串口编程和协议解析是在Qt应用程序中实现串口通信并解析通信协议的重要技术。
通过合理配置串口参数和实现协议解析,可以实现可靠的串口通信,并获取并处理从串口中读取的数据。
这对于与嵌入式设备、传感器等进行数据交互的应用具有重要意义。
Qt串口通信编程开发环境配置目录1 开发环境 (1)1.1 编程环境 (1)1.2 工程设置 (1)1.3 调试窗口设置 (2)1.4 依赖库 (2)1.5 源代码的适配 (2)2 运行及硬件环境 (3)2.1 串口设备 (3)2.2 虚拟串口工具 (3)2.3 串口调试助手 (3)2.4 运行支持文件 (3)3 第三方串口库的生成 (4)3.1 打开源码里的工程 (4)3.2 qextserialport源码问题解决 (4)4 故障解决 (5)4.1 转到槽函数失败 (5)积分下载本文档可免费提供技术支持。
1 开发环境1.1 编程环境工程采用Windows系统下的Qt Creator开发环境,Qt版本5.10.1(Qt的较新版,Bug 较少,支持串口库,图形库QChart),安装文件qt-opensource-windows-x86-5.10.1.exe安装的编译器采用MinGW32. 。
MARK32000-采用的串口时Qt自带串口库QSerialPort,若需第三方串口库可自行编译。
1.2 工程设置工程设置:在XXXX.pro文件中添加下面两行:QT += serialport #添加Qt串口支持CONFIG += console #显示控制台提示窗口,以方便调试,注释掉即可不显示黑色命令提示框如果采用第三方的串口库(本软件不含第三方库源代码),而不采用Qt的串口库,则要添加如下工程:INCLUDEPATH += qextserialport-1.2win-alphaLIBS += -L "../SerialProtocol/qextserialport-1.2win-alpha/build/" -lqextserialportd若路径找不到,可改成绝对路径。
相对路径基于项目生成的build路径,需要将第三方串口库“qextserialport”的生成文件“build”目录下的qextserialportd.a .dll拷贝到build-SerialProtocol-Desktop_Qt_5_10_1_MinGW_32bit-Debug目录下。
Qt实现串⼝通信总结注意: Qt5发布之前,Qt实现串⼝通信⼀般是采⽤第三⽅类库qextserialport。
Qt5发布后⾃带了能够⽀持串⼝通信。
1、Qextserialport类介绍在Qt5之前的版本中并没有特定的串⼝控制类,现在⼤部分⼈使⽤的是第三⽅写的qextserialport类,本⽂章主要是讲解怎样利⽤此类实现串⼝通信。
2、⽂件下载地址:最新⽂件下载在⽂章最后!3、⽂件内容:3.1.下载到的⽂件为qextserialport-1.2win-alpha ,解压并打开后其内容如下。
(1)doc⽂件夹中的⽂件内容是QextSerialPort类和QextBaseType的简单的说明,我们可以使⽤记事本程序将它们打开。
(2)examples⽂件夹中是⼏个例⼦程序,可以看⼀下它的源码,不过想运⾏它们好像会出很多问题啊。
(3)html⽂件夹中是QextSerialPort类的使⽤⽂档。
(4)然后就是剩下的⼏个⽂件了。
其中qextserialenumerator.cpp及qextserialenumerator.h⽂件中定义的QextSerialEnumerator类是⽤来获取平台上可⽤的串⼝信息的。
不过,这个类好像并不怎么好⽤,⽽且它不是我们关注的重点,所以下⾯就不再介绍它了。
(5)qextserialbase.cpp和qextserialbase.h⽂件定义了⼀个QextSerialBase类,win_qextserialport.cpp和win_qextserialport.h⽂件定义了⼀个Win_QextSerialPort类,posix_qextserialport.cpp和posix_qextserialport.h⽂件定义了⼀个Posix_QextSerialPort类,qextserialport.cpp 和qextserialport.h⽂件定义了⼀个QextSerialPort类。
Qt串⼝通信开发之QSerialPort模块Qt串⼝通信接收数据不完整的解决⽅法在使⽤串⼝接收数据时,当数据量⼤的时候会出现数据接收不完整的情况。
因为串⼝数据获取函数readAll()由readyRead()信号触发,但readyRead()信号在串⼝读到起始标志时⽴即发送,并不保证⼀定是当前所发数据的起始部分。
因此串⼝通信双⽅在通信前应制定好通信协议,规定好数据的起始和结束标志,串⼝当读到完整的起始和结束标志之后,才认定读完⼀条完整的数据。
本例中⽤串⼝定时发送当前时间,⽤"#"表⽰数据的结尾,定时时间为0毫秒,即能发多快就发多快。
发送void Widget::slotSendData(){QByteArray temp;temp.append(getCurrentTime());temp.append("#");serialPort->write(temp);}接收void Widget::slotReadData(){QByteArray temp = serialPort->readAll();if(!temp.isEmpty()){byteArray.append(temp);if(byteArray.contains("#")){ui->textEditReceive->setText(byteArray.split('#').at(0));byteArray = byteArray.right(byteArray.length()-byteArray.indexOf('#')-1);}}}下⾯是⼀个通过串⼝传输图⽚的例⼦这⾥假设波特率为9600,那么⼀秒钟就能传输9600/8=1200字节。
代码中将定时器设置为1秒,所以选择的图⽚应该⼩于1200字节。
这⾥为了演⽰如何完整接收数据,将图⽚按照指定⼤⼩分段发送,在每段之后紧接着发送字符串“###”。
qt 串口通讯实例Qt串口通讯实例可以基于Qt的串口类QSerialPort进行开发。
首先,需要在Qt项目中引入串口模块。
在.pro文件中添加一行代码:QT += serialport。
1. 打开串口:在Qt中打开串口有如下步骤:a) 创建一个QSerialPort对象,例如"serial";b) 设置串口名称:serial.setPortName("COM1");c) 设置波特率:serial.setBaudRate(QSerialPort::Baud9600);d) 设置数据位:serial.setDataBits(QSerialPort::Data8);e) 设置校验位:serial.setParity(QSerialPort::NoParity);f) 设置停止位:serial.setStopBits(QSerialPort::OneStop);g) 设置流控制:serial.setFlowControl(QSerialPort::NoFlowControl);h) 调用open函数打开串口:serial.open(QIODevice::ReadWrite)。
2. 发送数据:使用write函数可以将数据写入到串口。
例如,可以使用serial.write("Hello World")将字符串“Hello World”发送到串口。
3. 接收数据:可以通过QSerialPort的信号readyRead捕获串口接收到的数据。
其中readyRead是QSerialPort类中的一个信号。
可以将串口接收到的数据读取出来。
例如,在槽函数中使用readAll函数读取数据并打印出来。
下面是一个简单的Qt串口通讯实例,用于演示如何打开串口、发送和接收数据:cpp#include <QCoreApplication>#include <QSerialPort>#include <QSerialPortInfo>#include <QDebug>int main(int argc, char *argv[]){QCoreApplication a(argc, argv);打印可用的串口列表QList<QSerialPortInfo> portlist = QSerialPortInfo::availablePorts();qDebug() << "可用的串口列表:";foreach (QSerialPortInfo portInfo, portlist) {qDebug() << portInfo.portName();}创建串口对象QSerialPort serial;设置串口参数serial.setPortName("COM1");serial.setBaudRate(QSerialPort::Baud9600); serial.setDataBits(QSerialPort::Data8);serial.setParity(QSerialPort::NoParity);serial.setFlowControl(QSerialPort::NoFlowControl);打开串口if (serial.open(QIODevice::ReadWrite)) {qDebug() << "串口打开成功";} else {qDebug() << "串口打开失败";return 0;}发送数据QByteArray sendData = "Hello World";serial.write(sendData);qDebug() << "发送数据:" << sendData;接收数据QByteArray receiveData;while (serial.waitForReadyRead(100)) {receiveData.append(serial.readAll());}qDebug() << "接收数据:" << receiveData;关闭串口serial.close();return a.exec();}注意:在实际使用中,应该根据实际情况修改串口的名称、波特率等参数。
Qt串⼝通信开发之Qt串⼝通信模块QSerialPort开发完整实例(串⼝助⼿开发)之前⾃⼰写了⽤于上位机做基本收发的界⾯,独⽴出来相当于⼀个串⼝助⼿,先贴图:功能作为串⼝助⼿来说还算完善,五个发送槽,⼀个接收槽,可以检测可⽤串⼝并加上相关标志,串⼝设置,记数功能,还有菜单栏上的⽂件操作和⼀些选择功能。
下⾯说⼀说这个项⽬:做这个串⼝助⼿分为两步,第⼀步是设计界⾯,第⼆部是功能的代码实现。
⼀、界⾯设计界⾯设计⽤Qt Designer,当然⽤Qt Creator的界⾯编辑器也可以,只不过感觉Qt Designer更好⽤⼀点,因为可以随时运⾏查看你的界⾯效果⽽不⽤编译整个项⽬输出⼀个可执⾏程序再看看界⾯效果,这样会影响效率。
界⾯设计你想界⾯是什么样就怎么样设计,拉控件,排版,设置⼤⼩,修改对象名等等,都在这上⾯做好,这些⽤程序写的话会很⿇烦,⼯作量也⼤。
这上⾯的对象名很重要,因为在后⾯的代码实现中会⽤到,这个界⾯⽤到的控件还是挺多的,这⾥也不⼀个⼀个讲,我直接贴出来:senderGB_1 - 5都是⼀样的,改下数就⾏当然,⽤你⾃⼰喜欢的命名也可以,后⾯程序改下名字就⾏。
⼆、代码实现先贴代码basictransceiver.h#ifndef BASICTRANSCEIVER_H#define BASICTRANSCEIVER_H#include <QMainWindow>#include "ui_basictransceiver.h"class QTimer;class SerialPortSetting;class QSerialPort;class QPushButton;class BasicTransceiver : public QMainWindow, public Ui::BasicTransceiver{Q_OBJECTpublic:explicit BasicTransceiver(QWidget *parent = 0);~BasicTransceiver();void StringToHex(QString str, QByteArray &senddata);char ConvertHexChar(char ch);void startAutoSend(QPushButton *sendButton);void setConnections();void writeHex(QTextEdit *textEdit);void writeChr(QTextEdit *textEdit);void resetCnt();protected:void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event);private slots:void checkAutoSendCB();void on_cleanButton_clicked();void on_receiveTextBrowser_textChanged(); void setBaudRate();void setParity();void setDataBits();void setStopBits();void setFlowCtrl();void on_connectButton_toggled(bool checked); void setComLabel();void setBaudLabel();void writeToBuf();void enabledSendButton();void disabledSendButton();void enabledAutoSend();void disabledAutoButton();void resetAutoSendCB();void readMyCom();void checkAvailablePorts();void on_checkAPButton_clicked();void checkPort();void on_resetCntButton_clicked();void on_exitButton_clicked();bool saveAs();void open();//void about();private:bool loadFile(const QString &fileName);bool readFile(const QString &fileName);bool saveFile(const QString &fileName);bool writeFile(const QString &fileName);QTimer *Timer_AS;//⾃动发送定时器QTimer *Timer_UPDATE;QTimer *Timer_CP;//定时检测串⼝是否存在SerialPortSetting *SPSetting;QSerialPort *mySerialPort;QSet<QString> portSet;QVector<int> iVec;QString senderFlag;QString readData;bool trashFlag = false;bool portIsOpen = false;int BaudCnt = 0;int ParityCnt = 0;int DataBitsCnt = 0;int StopBitsCnt = 0;int FlowCtrlCnt = 0;};#endif // BASICTRANSCEIVER_Hbasictransceiver.cpp#include "basictransceiver.h"#include "serialportsetting.h"#include "ui_basictransceiver.h"#include "ui_serialportsetting.h"#include <QtSerialPort/QSerialPort>#include <QtSerialPort/QSerialPortInfo>#include <QDebug>#include <QMessageBox>#include <QStatusBar>#include <QPushButton>#include <QByteArray>#include <QDataStream>#include <QTimer>#include <QRegExp>#include <QRegExpValidator>#include <QFile>#include <QFileDialog>#include <QDragEnterEvent>#include <QDropEvent>#include <QMimeData>#include <QAction>BasicTransceiver::BasicTransceiver(QWidget *parent) :QMainWindow(parent){setupUi(this);setFixedSize(1074, 627);receiveTextBrowser->setAcceptDrops(false);//缺省情况下,QTextEdit接受来⾃其他应⽤程序拖拽来的⽂本,把⽂件名显⽰出来。
qserialport方法(最新版3篇)篇1 目录1.QSerialPort 类的概述2.QSerialPort 的主要功能3.QSerialPort 的基本使用方法4.QSerialPort 的信号与槽函数5.QSerialPort 的常见错误与处理篇1正文一、QSerialPort 类的概述QSerialPort 是 Qt 框架中的一个类,用于实现串行通信。
它可以让开发者方便地通过串口与其他设备进行数据传输,如接收或发送数据。
QSerialPort 类继承自 QIODevice 类,因此具有 QIODevice 类的所有功能,同时还提供了一些特定的串行通信方法。
二、QSerialPort 的主要功能QSerialPort 类提供了以下主要功能:1.打开和关闭串行端口:可以使用 open() 方法打开串行端口,使用close() 方法关闭串行端口。
2.读取和发送数据:可以使用 read() 和 write() 方法进行数据的读取和发送。
3.设置和获取端口参数:可以设置端口的波特率、数据位、停止位和校验位等参数,也可以获取当前端口的参数。
4.控制数据流:可以使用 setFlowControl() 和 getFlowControl() 方法控制数据流的方向和状态。
5.异步通信:可以使用 asyncRead() 和 asyncWrite() 方法进行异步读写操作。
三、QSerialPort 的基本使用方法使用 QSerialPort 类进行串行通信的基本步骤如下:1.创建一个 QSerialPort 对象,指定端口名称。
2.使用 open() 方法打开端口,并检查是否成功打开。
3.设置端口参数,如波特率、数据位、停止位和校验位等。
4.使用 read() 或 asyncRead() 方法读取数据,使用 write() 或asyncWrite() 方法发送数据。
5.在通信完成后,使用 close() 方法关闭端口。
[serial.cpp]#include <qapplication.h>#include <qmainwindow.h>#include "mainwindow.h"int main(int argc, char *argv[]){QApplication a(argc,argv);MainWindow m;a.setMainWidget(&m);m.show();return a.exec();}[mainwindow.h]#ifndef MAIN_WINDOW_H#define MAIN_WINDOW_H#include <qmainwindow.h>class QLabel;class QPushButton;class QLineEdit;class QPixmap;class SerialThread;class MainWindow:public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget * parent = 0, const char * name= 0) ; ~MainWindow(){};void setCounter(int no);void setMsgText(char* txt);public slots:void serialOperate();void loadJPEGFile();protected:void paintEvent( QPaintEvent * );private:QLineEdit *msg;QPushButton *btn;QPushButton *btn2LoadImg;QPixmap *pix;QLabel *lab;SerialThread *a;int counter;};#endif[mainwindow.cpp]#include <qlabel.h>#include <qpushbutton.h>#include <qvbox.h>#include <qapplication.h>#include <qlineedit.h>#include <qpixmap.h>#include <qpainter.h>#include <qimage.h>#include <qstring.h>#include "mainwindow.h"#include "serialthread.h"void MainWindow::paintEvent( QPaintEvent * ) {QPainter paint( this );paint.drawLine( 0,0,500,500 ); // draw linepaint.drawPixmap(0,0,*pix);}void MainWindow::loadJPEGFile(){if(!pix->load("testjpeg")){//if(!pix->load("circle")){setMsgText("Load failed");return;}setMsgText("Load success!");update();}void MainWindow::setCounter(int no){counter = no;}void MainWindow::serialOperate(){a = new SerialThread(this);a->start();a->wait();}MainWindow::MainWindow(QWidget * parent , const char * name):QMainWindow(parent, name){counter = 0;QVBox *vbox;vbox = new QVBox(this);vbox->resize(300,150);//msg = new QLabel("SERIAL PROGRAMMING",vbox);msg = new QLineEdit("SERIAL PROGRAMMING",vbox);msg->resize(300,50);pix = new QPixmap();btn = new QPushButton(vbox);btn->setText("GO!");QApplication::connect(btn,SIGNAL(clicked()),this,SLOT(serialOperate()));btn2LoadImg = new QPushButton(vbox);btn2LoadImg->setText("LOAD");lab = new QLabel("before load jpeg",vbox);QApplication::connect(btn2LoadImg,SIGNAL(clicked()),this,SLOT(loadJPEGFile()));//btn->resize(100,75);//vbox->show();};void MainWindow::setMsgText(char* txt){QString msgs(txt);QString count = QString::number(counter,10); msgs.append(count);const char *re = msgs.ascii ();//strcat(msgs,);msg->setText(re);};\\[my_define.h]#define BAUDRA TE B115200#define BLOCK_SIZE 200#define DEVICE "/dev/ttyS0"#define WAIT_TIME 5#define CHANGE_LINE 0x0a#define ACK_NUM 3#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE -1#endif[serialthread.h]#ifndef SERIAL_THREAD_H#define SERIAL_THREAD_H#include <qthread.h>class MainWindow;class SerialThread: public QThread {public:SerialThread(MainWindow *parent);virtual void run();private:MainWindow *parent;};#endif[serialthread.cpp]#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <termios.h>#include <stdio.h>#include "my_define.h"#include "serialthread.h"#include "mainwindow.h"int set_nc_mode(int fd){struct termios options;if ( tcgetattr( fd,&options) != 0){perror("SetupSerial 1");return(FALSE);} /* get current port settings */bzero(&options, sizeof(options));options.c_cflag |= BAUDRA TE | CS8 | CLOCAL | CREAD;options.c_cflag &= ~CRTSCTS;options.c_iflag = IGNPAR;options.c_oflag &=~OPOST;//options.c_lflag = 0;options.c_cc[VTIME] = W AIT_TIME;options.c_cc[VMIN] = BLOCK_SIZE; /* blocking read until 5 chars received */tcflush(fd, TCIFLUSH);tcsetattr(fd,TCSANOW,&options);return(TRUE);}int set_c_mode(int fd){struct termios options;if ( tcgetattr( fd,&options) != 0){perror("SetupSerial 1");return(FALSE);}bzero(&options, sizeof(options));tcflush(fd, TCIOFLUSH);cfsetispeed(&options, BAUDRA TE);cfsetospeed(&options, BAUDRA TE);options.c_cflag |=(CLOCAL|CREAD);options.c_cflag &= ~CRTSCTS;options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;options.c_cflag &= ~PARENB; /* Clear parity enable,clear control mode flag */ options.c_iflag &= ~INPCK; /* Disable parity checking ,*/options.c_cflag &= ~CSTOPB;options.c_iflag |= IGNBRK;options.c_lflag |= ICANON;options.c_lflag &= ~(ECHO | ECHOE | ISIG);options.c_oflag &= ~(OPOST);tcflush(fd, TCIOFLUSH);if (tcsetattr(fd,TCSANOW,&options) != 0){perror("SetupSerial 3");return (FALSE);}return(TRUE);}void send_ack(int fd){char buf[]={\'A\',\'C\',\'K\',CHANGE_LINE};write(fd,buf,sizeof(buf));}void resend(int fd){char buf[]={\'R\',\'S\',\'D\',CHANGE_LINE};write(fd,buf,sizeof(buf));}void delay(int i){int j;for (;i>0;i--)for(j=0;j<65535;j++);}////////////////////////////////////////////////////////////////////////////////////////////SerialThread::SerialThread(MainWindow *parent){this->parent = parent;}void SerialThread::run(){int fd,c, res;int block_num,last_block;int i;char buf[BLOCK_SIZE];char file_name[32];FILE *fp;struct termios oldtio;block_num=last_block=0;fd = open(DEVICE, O_RDWR | O_NOCTTY );parent->setCounter(fd);parent->setMsgText("opend device fd::::::");if (fd <0){perror(DEVICE);parent->setMsgText("open device failed");// exit(-1);}tcgetattr(fd,&oldtio);set_nc_mode(fd);printf("Changed to nc mode\\n");/*res=read(fd,( char *)file_name,32);parent->setCounter(res);parent->setMsgText("res is ::::::");*//*if(res>0){file_name[res-1]=\'\\0\';printf("Received the file name:%s\\n",file_name);}elseprintf("The received file name is error.\\n");fp=fopen(file_name,"wb");if(fp==NULL){printf("Can not creat file %s!\\n",file_name);return;// exit(-1);}else{send_ack(fd);printf("The file %s is created.\\nWaitting for the block num and last block size\\n",file_name);}//set_nc_mode(fd);//printf("Changed to nc mode\\n");res=read(fd,buf,4);printf("res=%d\\n",res);printf("Received the block num \\n");for(i=0,block_num=0;i<4;i++){block_num=block_num*10+buf;printf("buf[%d]=%x\\n",i,buf);}printf("The number of blocks is %d\\n",block_num);send_ack(fd);res=read(fd,buf,3);printf("res=%d\\n",res);printf("Received the last block size \\n");for(i=0,last_block=0;i<3;i++){last_block=last_block*10+buf;printf("buf[%d]=%x\\n",i,buf);}printf("The last block size is %d\\n",last_block);send_ack(fd);printf("Starting receive blocks\\n");for(i=0;i<block_num;i++){res=read(fd,buf,BLOCK_SIZE);if(res!=BLOCK_SIZE){printf("res=%d,\\t Request resend the %d block\\n",res,i); i--;tcflush(fd, TCIOFLUSH);resend(fd);}else{fwrite(buf,1,BLOCK_SIZE,fp);printf("Received the %d block, res=%d\\n",i,res);printf("Send ack signal complete,waiting to read\\n");send_ack(fd);}}printf("start transporting the last block\\n");if(last_block>0){send_ack(fd);res=read(fd,buf,last_block);printf("res=%d\\n",res);if(res!=last_block){printf("Request resend the last block\\n");tcflush(fd, TCIOFLUSH);resend(fd);}elsefwrite(buf,1,last_block,fp);}send_ack(fd);printf("The file transports end\\n");fclose(fp);printf("close the file\\n");tcsetattr(fd,TCSANOW,&oldtio);close(fd);printf("close the serial port\\n");*/}例子2(程序据说有问题)class Nj : public QMainWindow{Q_OBJECTpublic:/** construtor */Nj();/** destructor */~Nj();//串口进程void initlinSerialttys();signals://串口读写void signalslinSerialttys0(int);void signalslinSerialttys1(int);public slots://串口接收void linSerialttys0();void linSerialttys1();//报警窗口void Myalarm(int);private://串口参数linSerial s;FILE *serialport;int fs;//串口接收数据char chRet, phone[20], alarm[10], telephone[20];Nj::Nj(){setCaption("Nj " VERSION);///////////////////////////////////////////////////////////////////// call inits to invoke all other construction partsinitMenuBar();initToolBar();initStatusBar();initDoc();initView();initlinSerialttys();}void Nj::initlinSerialttys() {//串口0s.OpenDevice("/dev/ttyS0"); //打开串口fs = s.GetFileDescriptor(); //获得串口描述符serialport = s.GetFileHandle();//获得文件指针//可以采用串口的文件描述符和文件指针来进行各种文件读写操作s.SetBits(8, 'N', 1);s.SetSpeed(4800);s.SetupRaw(1, 0);connect(this, SIGNAL(signalslinSerialttys0(int)), SLOT(Myalarm(int)));}void Nj::Myalarm(int x){QDialog *groupbox;groupbox = new QDialog();groupbox -> setMinimumSize( 400, 200);groupbox -> setMaximumSize( 400, 200);char h[] = "。
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'))23第⼀个参数 : 将Qstring转换为int型4第⼆个参数 : 需要将⼏个字符串转换成⼗六进制的,5如char型:需要两个字符6 short型 : 需要四个字符7int/long : 需要⼋个字符8第三个参数: 转换为多少进制9第四个参数: 不⾜位数的⽤0补齐1//QByteArray⾥⾯的数据按照对应的通讯协议进⾏调整2void 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 }13void 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//字符串转成⼗六进制实现2void Widget::StringToHex(QString str, QByteArray &senddata)3 {45int hexdata,lowhexdata;67int hexdatalen = 0;89int len = str.length();1011 senddata.resize(len/2);1213char lstr,hstr;1415for(int i=0; i<len; )16 {17//char lstr,18 hstr=str[i].toLatin1();19if(hstr == '')20 {21 i++;22continue;23 }24 i++;25if(i >= len)26break;27 lstr = str[i].toLatin1();28 hexdata = ConvertHexChar(hstr);29 lowhexdata = ConvertHexChar(lstr);30if((hexdata == 16) || (lowhexdata == 16))31break;32else33 hexdata = hexdata*16+lowhexdata;34 i++;35 senddata[hexdatalen] = (char)hexdata;36 hexdatalen++;37 }38 senddata.resize(hexdatalen);39 }404142char Widget::ConvertHexChar(char ch)43 {44if((ch >= '0') && (ch <= '9'))45return ch-0x30;46else if((ch >= 'A') && (ch <= 'F'))47return ch-'A'+10;48else if((ch >= 'a') && (ch <= 'f'))49return ch-'a'+10;50else return (-1);515253 }要点,易错点基本已经指出,其他的⽐较简单,这⾥不再赘叙1 #include "widget.h"2 #include "ui_widget.h"3 #include <QTimer>4 #include <QDateTime>5 #include <QMessageBox>6static int CountBase = 0;7static int SENDNUMSIZE = 20;8static 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();1920 cycletime = new QTimer();21 cycletime->setInterval(ui->lineEdit_cycletime->text().toInt());2223 QObject::connect(atimer,&QTimer::timeout,this,&Widget::timer_handle);2425//查找可⽤的串⼝26foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts())27 {28 QSerialPort serial;29 serial.setPort(info);30if(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 }4445 Widget::~Widget()46 {47delete ui;48 }49void Widget::timer_handle(void)50 {5152 QDateTime current_date_time =QDateTime::currentDateTime();53 QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss ddd"); 54// ui->textBrowser_date55 ui->label_date->setText(current_date);5657 }5859void Widget::on_pushButton_oprea_clicked()60 {61if(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);//设置波特率为11520070//设置数据位数71switch (ui->databitBox->currentIndex())72 {73case0:74 serial->setDataBits(QSerialPort::Data8);//设置数据位875break;76default:77break;78 }79//设置校验位80switch (ui->checkBox->currentIndex())81 {82case0:83 serial->setParity(QSerialPort::NoParity);84break;85default:86break;87 }88//设置停⽌位89switch (ui->stopbitBox->currentIndex())90 {91case0:92 serial->setStopBits(QSerialPort::OneStop);//停⽌位设置为193break;94case1:95 serial->setStopBits(QSerialPort::TwoStop);96default:97break;98 }99//设置流控制100 serial->setFlowControl(QSerialPort::NoFlowControl);//设置为⽆流控制101102//关闭设置菜单使能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("串⼝已打开"));109110//连接信号槽111 QObject::connect(serial,&QSerialPort::readyRead,this,&Widget::ReadData); 112 }113else114 {115 cycletime->stop();116//关闭串⼝117 serial->clear();118 serial->close();119 serial->deleteLater();120121//恢复设置使能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//读取接收到的信息131void Widget::ReadData()132 {133 QByteArray temp;134if(ui->HEX_SHOW->isChecked())135 {136 SENDNUMSIZE = ui->lineEdit_duiqi->text().toInt();137 temp = serial->readAll();138 QDataStream out(&temp,QIODevice::ReadWrite); //将字节数组读⼊139while(!out.atEnd())140 {141 qint8 outChar = 0;142static qint8 datacount = 1;143 recvCount++;144out>>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);150if(SENDNUMSIZE+2 == datacount)151 {152 datacount = 1;153 ui->textBrowser->insertPlainText("\n");154 ui->textBrowser->moveCursor(QTextCursor::End);155 }156 }157 }158else159 {160161 temp += serial->readAll();162if(!temp.isEmpty())163 {164 ui->textBrowser->append(temp);165 ui->textBrowser->moveCursor(QTextCursor::End);166 }167 temp.clear();168 }169170 }171short Widget::checksum(QByteArray ba)172 {173short i = 0,sumValue = 0;174175for(i=2;i<(ba.length());i++)176 {177 sumValue+=ba.at(i);178 }179return sumValue;180 }181182void Widget::on_send_clicked()183 {184short checkValue = 0;185 QString str;186 QByteArray senddata;187if(ui->pushButton_oprea->text() == tr("串⼝已关闭"))188 {189 QMessageBox::information(this, "warning", "串⼝没打开", QMessageBox::Yes);190191 }192if(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'))//12205 + 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'))//16207 + 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'))//35216 + 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 }230else{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 }249250251 checkValue = checksum(senddata);252 senddata.append((char)(checkValue));253 serial->write(senddata);//发送到串⼝254 CountBase+=senddata.length();255256 ui->label_sendvalue->setNum(CountBase);257 }258void 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 }269void 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 }276277void Widget::StringToHex(QString str, QByteArray &senddata) 278 {279280int hexdata,lowhexdata;281282int hexdatalen = 0;283284int len = str.length();285286 senddata.resize(len/2);287288char lstr,hstr;289290for(int i=0; i<len; )291 {292//char lstr,293 hstr=str[i].toLatin1();294if(hstr == '')295 {296 i++;297continue;298 }299 i++;300if(i >= len)301break;302 lstr = str[i].toLatin1();303 hexdata = ConvertHexChar(hstr);304 lowhexdata = ConvertHexChar(lstr);305if((hexdata == 16) || (lowhexdata == 16))306break;307else308 hexdata = hexdata*16+lowhexdata;309 i++;310 senddata[hexdatalen] = (char)hexdata;311 hexdatalen++;312 }313 senddata.resize(hexdatalen);314 }315316317char Widget::ConvertHexChar(char ch)318 {319if((ch >= '0') && (ch <= '9'))320return ch-0x30;321else if((ch >= 'A') && (ch <= 'F'))322return ch-'A'+10;323else if((ch >= 'a') && (ch <= 'f'))324return ch-'a'+10;325else return (-1);326327328 }329330331void 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 }339void Widget::cycletime_handle(void)340 {341 on_send_clicked();342 }343void Widget::on_lineEdit_duiqi_editingFinished()344 {345 SENDNUMSIZE = ui->lineEdit_duiqi->text().toInt();346 }347348void Widget::on_checkBox_TIMER_stateChanged(int arg1)349 {350if(ui->checkBox_TIMER->isChecked())351 {352 cycletime->start();353 QObject::connect(cycletime,&QTimer::timeout,this,&Widget::cycletime_handle); 354 }355else356 {357 cycletime->stop();358 }359360 }all code。
Qt编写串口通信程序图文详解(说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写,程序稍有不同,请自己改动。
)在Qt中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport类,我们这里也是使用的该类。
我们可以去/projects/qextserialport/files/进行下载,也可以去下载我上传到网上的:/bbs/read.php?tid=22847下载到的文件为:qextserialport-1.2win-alpha.zip其内容如下图:我们在windows下只需要使用其中的6个文件:qextserialbase.cpp和qextserialbase.h,qextserialport.cpp和qextserialport.h,win_qextseri alport.cpp和win_qextserialport.h如果在Linux下只需将win_qextserialport.cpp和win_qextserialport.h 换为posix_qextserialpo rt.cpp和posix_qextserialport.h即可。
第一部分:下面我们将讲述编程的详细过程,这里我们先给出完整的程序,然后到第二部分再进行逐句分析。
1.打开Qt Creator,新建Qt4 Gui Application,工程名设置为mycom,其他使用默认选项。
(注意:建立的工程路径不能有中文。
)2.将上面所说的6个文件复制到工程文件夹下,如下图。
3.在工程中添加这6个文件。
在Qt Creator中左侧的文件列表上,鼠标右击工程文件夹,在弹出的菜单中选择Add Existing Files,添加已存在的文件。
如下图:选择工程文件夹里的那6个文件,进行添加。
如下图。
添加好后文件列表如下图所示:4.点击mainwindow.ui,在窗口上加入一个Text Browser,用来显示信息。
如下图。
5.在mainwindow.h的相应位置添加头文件#include "win_qextserialport.h",添加对象声明Win_QextSerialPort *myCom;添加槽函数声明void readMyCom();添加完后,如下图。
6.在mainwindow.cpp的类的构造函数中添加如下语句。
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow){ui->setupUi(this);struct PortSettings myComSetting = {BAUD9600,DATA_8,PAR_NONE,STOP_1,FLOW_OFF, 500};//定义一个结构体,用来存放串口各个参数myCom = new Win_QextSerialPort("com1",myComSetting,QextSerialBase::EventDriven); //定义串口对象,并传递参数,在构造函数里对其进行初始化myCom ->open(QIODevice::ReadWrite);//以可读写方式打开串口connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));//信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作}在下面添加readMyCom()函数的定义,添加如下代码。
void MainWindow::readMyCom() //读串口函数{QByteArray temp = myCom->readAll();//读取串口缓冲区的所有数据给临时变量tempui->textBrowser->insertPlainText(temp);//将串口的数据显示在窗口的文本浏览器中}添加完代码后如下图。
此时如果运行程序,已经能实现读取串口数据的功能了。
我们将单片机采集的温度信息由串口传给计算机,效果如下图。
这样最简单的串口通信程序就完成了。
可以看到它只需要加入几行代码即可,非常简单。
第二部分:上一部分中已经介绍了实现最简单的串口接收程序的编写,下面将对程序内容进行分析。
1.首先应说明操作串口的流程。
步骤一:设置串口参数,如:波特率,数据位,奇偶校验,停止位,数据流控制等。
步骤二:选择串口,如windows下的串口1为“com1”,Linux下为“ttyS0”等,并打开串口。
步骤三:读或写串口。
步骤四:关闭串口。
(我们上一个程序没有写串口和关闭串口的功能,打开串口也是在构造函数里完成的,因为那只是为了用最简单的方法完成串口程序的编写。
在后面我们将会对它进行修改和完善。
)2.下面我们将按照上面的操作串口的流程,讲解第一个程序的编写。
第一,我们在写程序之前,应该浏览一下那6个文件,大概看一下它们里面都是什么内容,各个文件各个类之间有什么联系。
在win_qextserialport.cpp文件中,我们看它的最后一个构造函数,会发现,串口可以在这里进行初始化。
Win_QextSerialPort::Win_QextSerialPort(const QString & name, const PortSettings& setti ngs, QextSerialBase::QueryMode mode) {Win_Handle=INVALID_HANDLE_VALUE;setPortName(name);setBaudRate(settings.BaudRate);setDataBits(settings.DataBits);setStopBits(settings.StopBits);setParity(settings.Parity);setFlowControl(settings.FlowControl);setTimeout(settings.Timeout_Millisec);setQueryMode(mode);init();}它共有三个参数,其中第一个参数const QString & name,应该是串口的名字,是QString类型,我们可以用串口1即“com1”,不用过多说明。
下面我们主要研究第二个和第三个参数。
第二,我们查看第二个参数的位置。
在Qt Creator的菜单中选择Edit->Find/Replace->All projects,如下图。
在弹出的对话框中输入要查找的内容PortSettings,如下图。
点击Search后,便能在下面显示出整个工程中所有PortSettings的位置。
如下图。
我们点击第一条,可以看到在qextserialbase.h文件中有一个struct PortSettings,如下图。
我们双击这一条,进入相应的文件。
如下图。
struct PortSettings{BaudRateType BaudRate;DataBitsType DataBits;ParityType Parity;StopBitsType StopBits;FlowType FlowControl;long Timeout_Millisec;};可以看到在这个结构体里定义了串口初始化的各个参数,而对于BaudRateType等类型的定义,我们在这个结构体的上面可以看到,它们是多个枚举变量。
如下图。
这时我们便应该明白了,这个结构体便是实现串口参数设置的。
第三,定义串口参数。
BaudRateType BaudRate;波特率设置,我们设置为9600,即程序中用BAUD9600;DataBitsType DataBits;数据位设置,我们设置为8位数据位,即DATA_8;ParityType Parity;奇偶校验设置,我们设置为无校验,即PAR_NONE;StopBitsType StopBits;停止位设置,我们设置为1位停止位,即STOP_1;FlowType FlowControl;数据流控制设置,我们设置为无数据流控制,即FLOW_OFF;long Timeout_Millisec;延时设置,我们设置为延时500ms,即500;这样便写出了程序中的那句:struct PortSettings myComSetting = {BAUD9600,DATA_8,PAR_NONE,STOP_1,FLOW_OFF, 500};我们定义了一个结构体变量myComSetting,并对其进行了初始化。
第四,设置第三个参数。
我们先按上面的方法找到它的定义位置,在qextserialbase.h中,如下图。
可以看到查询模式也是枚举变量,有两个选项,我们选择第二个EventDriven,事件驱动。
到这里,我们就可以定义Win_QextSerialPort类的变量了,就是那句:myCom = new Win_QextSerialPort("com1",myComSetting,QextSerialBase::EventDriven);它完成了串口的选择和串口的初始化。
第五,写打开串口函数和读串口函数。
查看win_qextserialport.h文件,我们会发现Win_QextSerialPort类继承自QextSerialBase类。
查看qextserialbase.h文件,我们会发现QextSerialBase类继承自QIODevice 类。
我们在Qt的帮助中查看QIODevice 类,如下图。
其部分内容如下图。
可以看到其中有enum OpenModeFlag{ NotOpen, ReadOnly, WriteOnly, ReadWrite, ..., Unbuffered },virtual bool open( OpenMode mode ),QByteArray readA ll()等内容。
而下面的信号函数中有void readyRead();它可以查看串口是否有新的数据传来。
所以,我们可以用这个类里的这些函数操作串口。
如程序中的语句:myCom ->open(QIODevice::ReadWrite);//我们调用了其中的open函数,用ReadWrite可读写的方式进行打开串口,这个open函数//在win_qextserialport.cpp中被重定义了connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));//我们关联信号readyRead(),和自己写的槽函数readMyCom(),当串口有数据传来时进行读串口操作void MainWindow::readMyCom() //自己写的读串口函数{QByteArray temp = myCom->readAll();//我们调用readAll()函数,读取串口中所有数据,在上面可以看到其返回值是QByteArray类型ui->textBrowser->insertPlainText(temp);//调用insertPlainText()函数,是窗口上的文本浏览器中连续输出数据,而不是每次写数据前都清除以前//的数据,可以在Qt的帮助里查看这个函数的说明}这样我们便写完了所有的语句,最后只需要在mainwindow.h文件中加入相应的头文件,对象声明,函数声明即可。