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

前段时间写了一个关于WiMi-Net简要的收发码以及CRC校验的博客(http://blog.csdn.net/u011348999/article/details/16803829

然后一直说把QT串口与WiMi-net的联机调试做一个总结。。结果一直拖到现在,人太懒了真不是件好事。。好了废话少说,我们进入正题。

 

我用的是广泛通用的yafeilinux所做的QT串口第三方类。没有看过这个教程的可以先移步到http://blog.csdn.net/yafeilinux/article/details/5741706

这个教程所提及的串口初始化以及字符串发送我在此就略去不提了。

 

现在我们从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码再发一遍。。。

Linux下QT串口通过无线模块收发十六进制数据_第1张图片

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的博客  http://blog.csdn.net/u011348999/article/details/17008515***************

*********************************************************转载请注明出处************************************************************/

 

 






 




你可能感兴趣的:(linux,qt,十六进制,串口通信,无线模块)