Qt 串行通讯161109.docx

上传人:b****5 文档编号:7268884 上传时间:2023-01-22 格式:DOCX 页数:12 大小:135.83KB
下载 相关 举报
Qt 串行通讯161109.docx_第1页
第1页 / 共12页
Qt 串行通讯161109.docx_第2页
第2页 / 共12页
Qt 串行通讯161109.docx_第3页
第3页 / 共12页
Qt 串行通讯161109.docx_第4页
第4页 / 共12页
Qt 串行通讯161109.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

Qt 串行通讯161109.docx

《Qt 串行通讯161109.docx》由会员分享,可在线阅读,更多相关《Qt 串行通讯161109.docx(12页珍藏版)》请在冰豆网上搜索。

Qt 串行通讯161109.docx

Qt串行通讯161109

Qt串行通讯

Hanford

2016年11月09日

目录

第1章Qt串行通讯1

1.1配置.pro文件1

1.2查询串口信息1

1.3配置、打开串口3

1.4setRequestToSend在Windows上的BUG5

1.5读取串口数据6

1.6发送串口数据7

1.7同步读取7

1.8本文示例代码8

1.9Qt示例代码10

第1章Qt串行通讯

最近要在Android手机上开发串行通讯程序,为此学习了一下Qt的串行通讯。

本文中,Qt的版本为5.7.0。

1.1配置.pro文件

使用Qt5.7.0创建“QtWidgetsApplication”类型的项目,然后修改.pro文件,如下图所示:

图1.1

给变量QT增加serialport,说明程序里将使用串行通讯相关的类。

1.2查询串口信息

本节将通过代码查找系统里的串口,然后填入下图所示的下拉列表框中。

图1.2

函数QSerialPortInfo:

:

availablePorts会返回系统所有的串口,它的使用请参考如下代码:

#include

#include

std:

:

mapmapPort;

QStringsPort;

intnPort;

foreach(constQSerialPortInfo&info,QSerialPortInfo:

:

availablePorts())

{//foreach遍历QSerialPortInfo:

:

availablePorts()的返回值

sPort=info.portName();//串口名称,如:

COM5

nPort=GetIntInStr(sPort);//根据串口名称获取串口号,如:

5

if(nPort>=0)

{

mapPort[nPort]=sPort;//根据串口号排序,加入map

}

}

函数GetIntInStr根据串口名称(如COM5)获取串口号(如:

5),其代码如下:

/***************************************************************\

从字符串里提取整数

s[in]字符串

返回:

提取出来的整数,-1表示错误

\***************************************************************/

intGetIntInStr(constQString&s)

{

boolbOK=false;//是否发现了数字

intn=0;

intnLenS=s.length();//字符串长度

ushortc=0;

for(inti=0;i

{

c=s[i].unicode();

if(c>='0'&&c<='9')

{

bOK=true;

n=n*10+(c-'0');

}

}

if(!

bOK)

{

n=-1;//没有数字,返回-1

}

returnn;

}

根据std:

:

mapmapPort填充下拉列表框QComboBoxcboPort的代码如下:

ui->cboPort->clear();

for(std:

:

map:

:

iteratorit=mapPort.begin();

it!

=mapPort.end();++it)

{

ui->cboPort->addItem(it->second);

}

1.3配置、打开串口

配置、打开串口的代码如下:

#include

m_port=newQSerialPort();

m_port->setPortName("COM1");//打开COM1

m_port->setBaudRate(9600);//波特率:

9600

m_port->setParity(QSerialPort:

:

NoParity);//校验法:

m_port->setDataBits(QSerialPort:

:

Data8);//数据位:

8

m_port->setStopBits(QSerialPort:

:

OneStop);//停止位:

1

m_port->setFlowControl(QSerialPort:

:

NoFlowControl);//流控制:

if(m_port->open(QIODevice:

:

ReadWrite))

{//成功打开串口

m_port->setRequestToSend(true);//设置RTS为高电平

m_port->setDataTerminalReady(true);//设置DTR为高电平

}

首先new一个QSerialPort对象,然后设置该对象的串行通讯参数,最后调用QSerialPort:

:

open函数打开串口。

这里需要说明一下流控制。

通讯的双方A和B,假如A给B发送数据时,B反应过慢,A不管不顾的不停发送数据,结果会导致数据丢失。

为了防止这种情况发生,可使用流控制(也叫握手)。

软件流控制(XON/XOFF):

通讯的一方(B)如果不能及时处理串口数据,会给对方(A)发送XOFF字符,对方接收到这个字符后,会停止发送数据;B不再忙的时候,会给A发送XON字符,A接收到这个字符后,会接着发送数据。

软件流控制最大的问题就是不能传输XON和XOFF。

硬件流控制(RTS/CTS):

硬件流控制需要按下图连接两个串口设备的RTS和CTS。

图1.3

通讯的一方(B)如果不能及时处理串口数据,会设置自己的RTS为低电平,B的RTS连着对方(A)的CTS,A发现自己的CTS为低电平,将停止发送数据;B不再忙的时候,会设置自己的RTS为高电平,A发现自己的CTS为高电平,将接着发送数据。

上面的代码中,设置流控制为无,其含义为:

不管对方是否能够反应过来,这边只管发送数据。

当流控制为硬件时,系统会自动管理RTS和DTR的状态。

否则,应该设置RTS和DTR为高电平,通知对方可以发送串口数据了。

1.4setRequestToSend在Windows上的BUG

经测试,流控制为无时,调用m_port->setRequestToSend(true);是没有任何效果的。

下面的Qt源代码节选自文件C:

\Qt\Qt5.7.0\5.7\Src\qtserialport\src\serialport\qserialport_win.cpp(C:

\Qt\Qt5.7.0是Qt的安装目录)

boolQSerialPortPrivate:

:

setRequestToSend(boolset)

{

if(!

:

:

EscapeCommFunction(handle,set?

SETRTS:

CLRRTS)){

setError(getSystemError());

returnfalse;

}

returntrue;

}

上面的代码调用EscapeCommFunction(handle,SETRTS)似乎没什么问题,但是请看下面的代码:

boolQSerialPortPrivate:

:

setFlowControl(QSerialPort:

:

FlowControlflowControl)

{

.........

dcb.fRtsControl=RTS_CONTROL_DISABLE;

switch(flowControl){

caseQSerialPort:

:

NoFlowControl:

break;

caseQSerialPort:

:

SoftwareControl:

break;

caseQSerialPort:

:

HardwareControl:

dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;

break;

.........

硬件流控制时dcb.fRtsControl为RTS_CONTROL_HANDSHAKE,这个没问题。

问题出在dcb.fRtsControl=RTS_CONTROL_DISABLE上,它直接禁用了RTS,所以EscapeCommFunction(handle,SETRTS)并不能设置RTS为高电平。

那么m_port->setDataTerminalReady(true)为什么又是正常的呢?

看代码:

boolQSerialPortPrivate:

:

setDataTerminalReady(boolset)

{

.........

dcb.fDtrControl=set?

DTR_CONTROL_ENABLE:

DTR_CONTROL_DISABLE;

.........

}

set为true时,dcb.fDtrControl为DTR_CONTROL_ENABLE,所以可以设置DTR为高电平。

1.5读取串口数据

m_port->readAll(QIODevice:

:

readAll)用来读取串口数据。

不过,它是异步执行的。

什么是异步呢?

那就是即使对方还没有发送串口数据,m_port->readAll也会立即返回,而不是傻傻的等着对方发送数据过来后再返回。

既然是异步的,那么何时读取串口数据就成为了关键。

Qt提供的方案就是使用信号、槽。

connect(m_port,SIGNAL(readyRead()),this,SLOT(slotReadData()));

当对方发送串口数据后,将触发m_port的信号QIODevice:

:

readyRead。

上面的代码将信号readyRead与槽函数slotReadData连接了起来,因此槽函数slotReadData将被调用,其代码如下:

voidWidget:

:

slotReadData()

{

QByteArraydata;

constintnMax=64*1024;

for(;;)

{

data=m_port->readAll();//读取串口数据

if(data.isEmpty())

{//没有读取到串口数据就退出循环

break;

}

//读取到的串口数据,加入到QByteArraym_dataCom

m_dataCom.append(data);

if(m_dataCom.size()>nMax)

{//防止m_dataCom过长

m_dataCom=m_dataCom.right(nMax);

}

}

ui->txtRecv->setText(m_dataCom);//将m_dataCom显示到文本框

ui->txtRecv->moveCursor(QTextCursor:

:

End);//移动文本框内的插入符

}

1.6发送串口数据

m_port->write(QIODevice:

:

write)用来发送串口数据,不过它也是异步的。

也就是说:

代码m_port->write("123");会立即返回,至于数据"123"何时会发送给对方,那是操作系统的事情。

操作系统不忙的时候,才会做此项工作。

参考如下代码:

charszData[32];

strcpy(szData,"123");

m_port->write(szData);

m_port->write(szData);这行代码会立即返回。

操作系统在空闲时才会将szData里的数据发送给对方。

问题是:

m_port->write返回后,变量szData有可能已经被析构掉了,此时操作系统再访问szData所指向的内存,结果不可预料。

为此,需要改进上述代码,将异步通讯更改为同步通讯:

charszData[32];

strcpy(szData,"123");

m_port->write(szData);

m_port->waitForBytesWritten(5000);

就增加了一行代码m_port->waitForBytesWritten(5000);其含义为:

操作系统把串口数据szData发送出去后,m_port->waitForBytesWritten才会返回。

不过,总不能无限制等下去吧?

5000就是等待时间的最大值,其单位为毫秒,5000毫秒就是5秒。

1.7同步读取

异步通讯的效率比较高,但是代码结构比较复杂。

有时,需要同步读取。

如:

给对方发送字符串Volt,对方回应电压值5。

代码会这么写:

m_port->write("Volt");

m_port->waitForBytesWritten(5000);

QByteArraydata;

for(;;)

{

data=m_port->readAll();//读取串口数据

if(!

data.isEmpty())

{//读到数据了,退出循环

break;

}

}

通过一个无限循环,将异步读取变成了同步读取。

不过,上述代码运行时,CPU占用率将会达到100%(单核CPU)。

为此,需要改进代码:

m_port->write("Volt");

m_port->waitForBytesWritten(5000);

QByteArraydata;

while(m_port->waitForReadyRead(3000))

{

data=m_port->readAll();//读取串口数据

if(!

data.isEmpty())

{//读到数据了,退出循环

break;

}

}

修改了一行代码m_port->waitForReadyRead(3000),其含义为等待对方发送串口数据过来。

如果对方发送串口数据过来了,它返回true,然后使用m_port->readAll读取串口数据;如果对方在3秒内都没有发送串口数据过来,它返回false,退出循环。

1.8本文示例代码

本文示例代码已上传至git服务器,具体如下:

为了便于测试,可使用VirtualSerialPortDriver7.1创建一个串口对COM100、COM200,如下图所示:

图1.4

上图的COM100、COM200是虚拟出来的。

COM100发送的数据将会被COM200接收到,反之亦然。

下图是测试界面:

图1.5

本文示例代码打开了COM100,另一个串行通讯程序打开了COM200。

两者可以相互发送数据。

1.9Qt示例代码

安装完Qt5.7.0后,Qt串行通讯的示例代码也被安装了,如下图所示:

图1.6

C:

\Qt\Qt5.7.0是笔者安装Qt5.7.0时的安装目录。

需要进一步了解Qt串行通讯的可查看这些示例。

如:

creaderasync表示异步读取;creadersync表示同步读取……更多信息查看Qt帮助。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1