现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

Linux下QT串口通过无线模块收发十六进制数据

2014-09-29 05:20 工业·编程 ⁄ 共 3009字 ⁄ 字号 暂无评论

本文用的是广泛通用的yafeilinux所做的QT串口第三方类。没有看过这个教程的可以先移步。这个教程所提及的串口初始化以及字符串发送我在此就略去不提了。

现在我们从yafeilinux教程中

myCom->write(ui->lineEdit->text().toAscii());

这句串口发送语句展开来讲。

可以看到,Write函数这个参数ui->lineEdit->text().toAscii()实际返回了一个QByteArray值。那么,这个基于QIODevice类的write函数除了能够接受QByteArray作为传入参数,还有其他的重载形式没有呢?来看看QIOdevice.h中对write函数怎么定义的:

qint64 write(const char *data, qint64 len); 

qint64 write(const char *data); 

inline qint64 write(const QByteArray &data) 

{ return write(data.constData(), data.size()); } 

可以看到该函数接受一个char型指针作为输入,第二个可选参数为发送数据的长度。
另外还有一个内联函数接受一个QByteArray类的指针,而它只是调用了QByteArray类的constData函数,将这个QByteArray的首地址作为一个const char*返回。

好了,到这里我们对这个Write()函数有了个大概的印象了。现在把它放在一边,我们先来看看在发送数据前对数据的处理方式。

我这里的无线模块使用的是微网高通(北京)公司的WiMi-net,无线模块都大同小异,包括使用特别广泛的zigbee无线模块,它们收发数据都遵循一个特定的数据格式,包括一个统一的帧头(WiMi-net是0xAA);几个命令字(用来确定该帧具体的作用是对模块进行操作还是收发数据等等);一个iAmount存放该帧有效数据的字节数;十六位的CRC校验字;以及自定义的数据位等等。

在前一篇博文中以及介绍了WiMi-net添加CRC校验码的代码,这个Add_Crc接收一个unsigned char[]作为形参输入,为什么不使用char型数组输入的原因是在之后参与计算的过程中char型字符所带的符号位会造成最终的CRC返回结果出错。

那么来看下数据的转换以及发送代码吧~:

QString str; 

QList<QString> SerialSendlist; 

SerialSendlist << ui->IDLine->text()<<","

<<ui->XLine->text()<<","

<<ui->YLine->text()<<","

<<ui->HLine->text()<<","

<<ui->FLine->text()<<","

<<ui->BLine->text()<<","

<<ui->ALine->text()<<","

<<ui->RPLine->text()<<","

<<ui->RLLine->text(); 

 

unsigned char Test[64] = {0XAA, 0X1D, 0XFF, 0XFF, 0X03, 0X01};//帧头

for(int i = 0; i < 17; i++){         //QString转char*

    str.append(SerialSendlist.at(i)); 

for(int i = 0; i < str.length(); i++){ 

    Test[i+9] = *qPrintable(str.mid(i,1)); 

Test[6] = str.length(); 

if(Add_Crc(Test)){ 

    myCom->write((char*)Test); 

首先我们使用一个QList<QString>取出了我们需要发送的QString类型的数据,然后存放在一个QString中,并以","隔开。

之后我们定义一个unsigned char型数组,里面预先写入了固定的同步字符,以广播形式发送数据等操作字符。

然后我们利用循环以及宏函数qPrintable将str中的每个字符以其十六进制存入Test[]中。Test[6]中存放的是数据长度。

写串口数据,最简单的一句,myCom->write((char*)Test);却花了我最多的功夫。。。

因为当时天真的认为unsigned char*强制转换到char*的会丢失数据,所以引入了一个QByteArray类的中间变量。

发送代码类似

if(Add_Crc(Test)){ 

for(int i = 0; i < str.length() + 0X09; i++){ 

SendStr.append(Test[i]); 

myCom->write(SendStr); 

但是这样做会有一个特别奇怪的问题,即,这段代码在PC机上向外发送数据没有问题,而开发板的linux端发出来的数据会将这些十六进制数当做字符串转成ASCii码再发一遍。。。

Written data下面是PC机发出的数据,这种帧是可以被无线模块识别并发送出去的。而Read data下面的数据则是开发板发出来的数据,它在正常帧的数据前面加了一长串,就是将这帧十六进制当做字符串转成的ASCii码。

这个问题我在贴吧里面提出并进行了讨论(详见http://tieba.baidu.com/p/2719228495)但没有得到一个理想的答案,如果有知道这个缘由的朋友还望指点一二~鄙人感激不尽~

之后偶然看到一篇帖子中关于unsigned char与char转换的讨论,才想到,当作为ASCII码发送送时,unsigned char 与char 是没有区别的。他们都占一个字节,而我们并不需要去在意0XAA是-86还是170。
因此才有了这一行:myCom->write((char*)Test);(注意,如果Test[]中有0x00,系统会认为它是“/0”后面的数据会被截断。)

然后通过开发板与PC机通信发现Linux端发送的数据已经正常了。我满怀信心地将串口线插到WiMi-net上,结果什么数据都收不到!!这是什么情况?我又迷糊了。程序没有问题,数据没有问题,那问题一定出在硬件上了!!

在搜索到这篇博文的时候(http://www.cnblogs.com/qmlm8844/archive/2011/08/30/2159299.html),我恍然大悟了(再次感谢伟大的博客)。

RS232串口是全双工通信的,接收与发送数据可以同时进行,所以接收和发送有各自的数据线。从表1可以看到,2是接收线,3是发送线。

表1 RS232接口定义(9芯) 

针脚

定义

符号

1

载波检测

DCD

2

接收数据

RXD

3

发送数据

TXD

4

数据终端准备好

DTR

5

信号地

SG

6

数据准备好

DSR

7

请求发送

RTS

8

清除发送

CTS

9

振铃提示

RI

由于开发板和Wimi-net上的串口都是母头的,所以要用公-公串口线。而一般的公-公串口线都是1-1,2-2.。。针针对应的,那么,开发板数据从3脚出来,却发送到Wimi-net的发送脚(3脚)去了!!这要是能通信成功就奇了怪了列。。。。

再换了2X3的交叉串口线后。终于全系统调试成功,过程虽不算艰辛,但确实不断波折,记录在此,希望能给有相关疑问的朋友一个思路就好。

好了,今天的记录就先到这里吧~

作者:cloud_castle

给我留言

留言无头像?