用户名: 密码: 忘记密码? 注册

[转]Linux下串口编程心得

作者:  时间: 2010-12-01

Linux下串口编程心得

引用说明:这篇文章里面介绍了很经典的qt下解决串口通信的常识和资源。相当不错
 
(2009-02-18 20:23:56)
    最近一段时间,需要完成项目中关于Linux下使用串口的一个部分,现在开帖记录过程点滴。

    项目的要求是这样的,Qt应用程序主要完成数据采集和发送功能,原来采用的是把ARM板的串口设置城网口,然后通过拨号上网,通过socket编程实现数据的传输的。后来发现稳定性不高,于是换了一个第三方公司生产的DTU,希望直接往串口传输数据。
    一开始在google中海搜关键字“Qt串口编程”,得出的结论是:
    一、Qt自己的类中没有关于串口的类,不过有人做了一个第三方的类:qextserialport。可以在如下地址下载到:ftp://ftp.trolltech.com/contrib/qextserialport.tar.gz 或者http://qextserialport.sourceforge.net
    二、关于qextserialport,下载下来的文件中会自带比较详细的HTML文档介绍,不过都是英文哦!而且有版本对应,目前的认识是0.8或0.9是可以用于qt3的,之后的使用于qt4。
    三、以下文章是讲qextserial的编译的,不过好像用处不大。http://www.cnblogs.com/leaway/archive/2008/03/13/1104562.html
    四、也可以不用这个类,直接调用linux的系统函数。Linux中“万物皆文件”,所以串口也不例外。只要利用open()函数打开设备,用read()和write()函数读写串口,用close()关闭即可。另外,对于串口需要设置一些参数。
    五、继续往下搜,一篇号称“Linux下串口编程Bible”的文章《Serial Programming Guide for POSIX Operating Systems》浮出水面,不过照样是英文的。以下网址可以在线阅读或下载。
    http://www.easysw.com/~mike/serial/serial.html
    http: //digilander.libero.it/robang/rubrica/serial.htm
    http: //digilander.libero.it/robang/rubrica/serial.htm
    粗粗读过的确感觉不错。许多中文版本大都是部分翻译:http://www.ibm.com/developerworks/cn/linux/l-serials/index.html
    六、《Linux Serial Programming HOW-TO》也是另外一篇必读的文章,地址为
    http://fanqiang.chinaunix.net/a4/b7/20010502/110712.html
    http://www.vanemery.com/Linux/Serial/serial-console.html
    七、http://www.et2.tu-harburg.de/Mitarbeiter/Bauhan/software/serportE.html据说是一个用Qt写的和串口通讯的应用。没有测试过。
    八、http://www.oklinux.cn/html/Basic/jyjq/20070522/25995.html中是串口通信学习笔记,其中的参考文献可以看出基本的几个经典文章。
    九、http://blog.csdn.net/autofei/archive/2005/12/07/545836.aspx 串口编程的个人心得。
    十、http://www.xxlinux.com/linux/article/development/soft/20071029/11228.html串口编程分析。
     2009年2月16日9:43:27
     开始试着在Linux下编译下载的例子。
     [root@localhost qextserialport-0.9.0]# ls
Changes                   qextserialbase.cpp  qextserialport.pro
html                      qextserialbase.h    win_qextserialport.cpp
posix_qextserialport.cpp  qextserialport.cpp  win_qextserialport.h
posix_qextserialport.h    qextserialport.h
[root@localhost qextserialport-0.9.0]# vi qextserialport.pro
[root@localhost qextserialport-0.9.0]# qmake -o Makefile qextserialport.pro
[root@localhost qextserialport-0.9.0]# vi make
[root@localhost qextserialport-0.9.0]# vi Makefile
[root@localhost qextserialport-0.9.0]# make
g++ -c -pipe -Wall -W -g -D_REENTRANT -fPIC  -D_TTY_POSIX_ -DQT_THREAD_SUPPORT -I/usr/local/qt-x11-free-3.3.6/mkspecs/linux-g++ -I. -I/usr/include/freetype2 -I../../include -Imoc/ -o obj/qextserialbase.o qextserialbase.cpp
g++ -c -pipe -Wall -W -g -D_REENTRANT -fPIC  -D_TTY_POSIX_ -DQT_THREAD_SUPPORT -I/usr/local/qt-x11-free-3.3.6/mkspecs/linux-g++ -I. -I/usr/include/freetype2 -I../../include -Imoc/ -o obj/qextserialport.o qextserialport.cpp
g++ -c -pipe -Wall -W -g -D_REENTRANT -fPIC  -D_TTY_POSIX_ -DQT_THREAD_SUPPORT -I/usr/local/qt-x11-free-3.3.6/mkspecs/linux-g++ -I. -I/usr/include/freetype2 -I../../include -Imoc/ -o obj/posix_qextserialport.o posix_qextserialport.cpp
test -d lib/ || mkdir -p lib/
rm -f libqextserialport.so.1.0.0 libqextserialport.so libqextserialport.so.1 libqextserialport.so.1.0
g++ -Wl,-rpath,/usr/local/qt-x11-free-3.3.6/lib -shared -Wl,-soname,libqextserialport.so.1 -Wl,-rpath,/usr/local/qt-x11-free-3.3.6/zhf_work/qextserialport-0.9.0/lib -o libqextserialport.so.1.0.0 obj/qextserialbase.o obj/qextserialport.o obj/posix_qextserialport.o   -L/usr/local/qt-x11-free-3.3.6/lib -lqt-mt -lpthread
ln -s libqextserialport.so.1.0.0 libqextserialport.so
ln -s libqextserialport.so.1.0.0 libqextserialport.so.1
ln -s libqextserialport.so.1.0.0 libqextserialport.so.1.0
rm -f lib/libqextserialport.so.1.0.0
rm -f lib/libqextserialport.so
rm -f lib/libqextserialport.so.1
rm -f lib/libqextserialport.so.1.0
mv -f libqextserialport.so.1.0.0 libqextserialport.so libqextserialport.so.1 libqextserialport.so.1.0 lib/
 
   一下子轻易通过编译,还真的是不敢相信!
   不过后来发现这个根本没用,因为我需要做到是把这个现成的类添加到我的工程之中,而不是要用它的.o文件。编译通过只说明现在下载的版本是没有语法错误的哈哈。

  

200921619:46:21

搞了两天,几近崩溃,好在晚饭前终于曙光降临。我用Posix_qextserialport类实现了串口的写数据,看到数据接收到的一刻,突然感觉所有的事情都不再困难。而之前所有的努力也因为这一刻的到来而充满了意义。

必须清醒认识到,万里长征只走了一小步。之后需要实现的问题有:

一、做到向串口写数据和读数据,最后做个小界面,完善一下,直观一点。

二、与原有程序结合,实现原来的预想功能。

三、顺便研究调用第三方类和直接使用linux函数两种方式,总结成文。

 

200921621:15:03

阅读网上的《为Qt扩展QextSerialPort类》有感

无论是Win还是Lin,都是下载源码包,然后放到源码目录src下,然后qmake make,即可得到对应的库文件。在Win下是qextserialport.dll,qextserialport.prl,libqextserialport.a,

需要将第一个复制到Qt安装目录下的bin目录下,后面两个放在Qt安装目录的lib下。

而在Lin下会产生好几个文件,具体候补

 

然后需要在Qtinclude目录下拷贝有qextserialport.h等头文件,Qt4好像有QtGui目录,这个还没有研究过。

 

1.1后的版本有example,可以拷贝到硬盘中,Qt4好像里面的头文件包含可以用QextSerialPort

然后是qmake -project得到pro文件爱你,打开工程,加入

LIBS+= -l qextserialport

如果是win 加入DEFINES+= _TTY_WIN_QWT_DLL QT_DLL

如果是Lin,加入DEFINES+= _TTY_POSIX_

然后qmake

Make

正常会顺利,如果遇到问题再根据提示解决。



   2009年2月17日
   继续努力。今天定下的两条指导思想:
   1、要研究qextserialport的文档,因为它是为Qt编写的类,集成了Qt文档丰富的优点,而且风格是与Qt的其他类是完全类似的。
   2、要研究1.1版本的例子,虽然0.9版本没有例子,但是版本的延续是一脉相承的。所以看后续版本的例子也有一些启发。
 
   开始试着按照例子,写了一个小小程序,仅包含openport(),putch(),getch()和flush等几个动作,不过居然成功了,这给我巨大信心,感觉自己一定是可以做出来的。
   看得差不多了我就构思如何换掉原来程序通信模式而运用读写串口来完成通信。仔细一想,其实并不怎么难的。
   面向对象真的好处体现出来了!功能需要变化时候只需要改变相关部分的类而不用动其他的,甚至接口的改动都很少。我修改了client类和接口的参数以及一些小细节。然后就去试验了。
  没想到不行,连串口都打不开!
  这个成了一个大问题,程序方面不应该有太大问题啊,因为主要部分都是执行成功过的。那只能是怀疑文件系统问题,因为我一直没有搞明白的问题是为什么一个COM2可以当作网口来用!(文件系统中一直没找到相关的设置)。后来用了小梁的文件系统,试验了他的另一种方法对串口操作的程序,结果成功了。
  然后我尝试打开串口1,结果可以啊!
  调换了好多次之后,莫名其妙串口2也可以了,可是原因还没有找到。

  剩下的一个问题是数据的读取,读取是没有什么问题,问题是不知道以什么方式去读。是中断?中断需要触发啊,可是数据的来临有什么信号呢,不知道啊。只好用查询,查询不可能用while(1),否则程序啥也别干,就只能干这个了,显然不行。后来采用了一个定时器来查询,隔一段时间就过来巡逻一次。

 回想起来,今天大部分时间耗在了文件系统的更换上。有一点感悟是:做过的东西一定要备份,否则很惨,时间一长,你除了知道你做过之外就什么也不记得了!

  2009年2月18日20:44:16
  今天主要被两个个问题困扰!
  一个是乱码问题。
  原以为昨天解决了大部分问题今天就可以正常接收了,没想到接收到的全是乱码。后来想来想去觉得只有串口的波特率设置是可能造成影响的。可是我的发送端和接收端全是一样是9600啊。无奈,看到梁哥那个串口调试工具是115200,DNW也是,我就把波特率全部设置成了115200。
  果然可以了,而且另外一个发现是:只能是这一种,设置成其他的,一样都不行,高于115200也不行,真不知道波特率由什么决定的啦。不过通信中真是太重要了,一不匹配就什么也得不到。

 第二个问题是:当我传输的文本较大时(其实没有多大,只有2000多bytes),服务器就只能接收到前面一部分了,原来以为它分了多次也应该能够收到,但是就是没有!
  我想过了各种可能,并尝试了各种小试验验证,逐一排查。
  试验一:利用电脑的串口向DTU发送较长数据,发现接收正常,反过来也是正常的。
  这下我认定DTU肯定没有问题,出问题的肯定只有自己发送端的程序了。我查看了qestserialport的源代码,发现里面并没有给发送的大小设置限制。
  试验二:在发送端采用拆包发送机制,一次发送不超过1024,结果发现现象还是跟原来一样没变化。
  最后没办法,把qextserialport的父类,爷爷类,太爷爷类都翻出来看。发现其祖上居然是Qt中的QIODevice,这东西真是太好了,因为QSocket也是其同脉子孙,既然如此,可以用原来程序的思路。这样,我用出了最后一招(GOD,这招要是不管用,我真的没招了!):QString->QTextStream->QIODevice(Qtxtserialport)
   哈哈,可以了!
  
   从13号下午拿到模块,到现在已经过了五天,除了情人节没有工作之外总共用了四天多时间来解决这个问题。想想自己真的菜鸟,要换了牛人一下子功夫不久搞定了。
   不管那么多,牛人还不是从小牛仔长大的嘛!从零开始,日积月累,终会成功。
   在问题的解决过程中,我体会到了几点:
   1、要善于在网上查资料,不管中文英文,来者不拒都有有选择地仔细阅读。互联网会带给你很多!
   2、在程序方面自己要提高,可以多模仿外国的程序,规范写法。
   3、问题引导式的学习更有成效。平时没有什么事情可以给自己出一个问题,然后尝试找到解决办法。
 
   随后进行测试,郁闷,刚想说肯定没问题,结果一看出问题了!弹出了对话框,不过解决一下应该可以。DTU还是很不错,很稳定。