向前进

——On My Way,From Office Boy

导航

串口通信(MSComm)开发过程记录(包含一个可以通信的比较基础的程序版本)

      我要做的东西是一个类似超级终端的、针对AT指令应用的串口工具,选项卡式界面,发送AT指令与数据卡通信,方便研发人员读写数据卡和测试人员测试,提高工作效率。
      先发两个图片:     
      

      接到这个任务首先要分析这个软件主要包括那两个部分,主要的技术难点是什么:软件包括界面的设计,串口通信编程两个部分。界面设计采用vc++6.0,可以不用客户端安装.net,用vc设计界面还是比较轻松地,只是时间问题;串口通信就完全是门外汉了,完全不懂怎样通过串口与数据卡通信,这个是最棘手的问题。关于AT指令也是完全不懂,也需要重点学习。
      分析清楚后,就是查阅资料了,首先要弄清楚串口通信的概念,原理,方法。查阅资料比较费时费事,但也是很关键的,找到好的资料可以更快地了解,更清晰地认识,更好地选择。搜资料有个问题就是,当你对你要搜的东西比不了解的时候,你都不知道要搜什么才能找到自己想要的资料,往往搜到的东西并不符合要求,比较费时。但这个也没办法,有点耐心吧。
      我最开始的疑惑是串口通信到底是什么,我用的数据卡是usb口啊。串口通信能对usb口操作吗。后来搞清楚了,是数据卡的驱动安装了虚拟串口,可以当成是普通串口来操作。那么pc的串口通信跟单片机串口通信有什么区别,需不需要了解串口通信协议,握手什么的。
      广泛阅读资料后就会知道PC串口通信无非就是设置串口、打开串口、通信、关闭串口这些操作。达到这个认识我经过了好久一段时间,这就是所谓的从繁到简吧。没做过所以不清楚,万事开头难,入门是要花很大力气的。
      对串口通信有了认识后,就要考虑有什么方法实现。选择方法之前就要先搞清楚有哪些方法可以选择。不懂vc就可能只知道自己编程实现。自己编程又怎么编呢,查了之后可能知道要用windows的API。但最好不要从自己想当然的方法开始做。我是菜鸟,所以我要先看看别人都用什么做的,就会知道串口通信可以用windows的API,MSComm控件(还有其他的串口通信控件),其他一些人开发提供的串口类(如CSerialPort类)等方法实现。
(可参www.enet.com.cn/article/2006/0216/A20060216501544.shtml和龚建伟的Vc++/Turbo C串口通信编程实践)
      方法少了不好,没的选。方法多了可以选自己相对熟悉一点,或者感觉简单一点的,但也会比较头疼,不知道到底改选哪个好。所以就需要对几种方法都有个认识,然后再比较选择。
      我选择的是MSComm控件的方法。之前根本不知道什么是控件,怎么使用。但网上这方面资料还挺多的,而且都说简单易用。就拿来试试喽。 
      编程的东西可以参考,但不能依赖,呵呵。一开始我就想拿龚建伟那本书的随书代码用,发现根本用不了。想到以前的一些经历,觉得别人提供的代码一般不能直接用,都有bug,还是要自己搞懂,修改人家的代码才行。不过这已经很节省时间了,至少框架有了,从头编起很痛苦哒!
      至于这个控件有多强大,确实是用过了才知道。先在论坛里查了很多,发现很多问到这个控件能不能进行虚拟串口通信。看了这些帖子有点心灰意冷。因为先是觉得控件用起来简单些,而且有现成的程序,呵呵。有看到有这么多问题,有人建议用别的控件的,还有建议用其他方法。至少没有说可以这么做。那我就更没谱啦,都想是不是要换个方案。不过我很懒,想想后觉得先硬着头皮做做吧。没做过就没有发言权,有时候是要靠自己的。我心里挺急的,时间有限啊,要一个月内把AT指令的串口通信工具做好。当然包括串口通信和界面编程两部分。都是一窍不通,从零开始。
      做下来感觉MSComm功能还是很强大的,虽然要依托于窗体才能使用。下面讲讲我在开发过程中遇到的问题。
      1、先是开发一个基于对话框的简单的串口通信程序。
      MSComm控件的介绍龚建伟那本书里有讲,我就偷偷懒啦。创建过程参照那本书。
      串口通信程序部分,首先是要配置串口,在对话框初始化函数OnInitDialog()中使用MSComm提供的get/set函数对可以很简单的完成配置,包括串口号,波特率,奇偶校验,数据位,输入输出缓冲区大小,输入模式(设为二进制方式)还有与事件event(达到某种条件后自动生成事件消息)有关的RThreshold、SThreshold。具体可查询龚书第三章MSComm控件属性、函数、事件部分的介绍。
      然后就是数据发送接收部分的编程,发送实在点击send按钮后,接收时在消息事件处理函数OnComm中。用龚书源程序发送后接收区并没有响应显示。为了解决这个问题可是费了大功夫了,龚书第一章、第三章我看了好几遍,然后思考会是哪的问题。串口到底设置好没,打开了没,数据发送成功了吗,怎么检查发送成功了,如果发送成功了为什么没有响应。我一开始用debug查看发送数据是否正确,因为控件的setoutput函数要求参数是variant类型的,用从sctring类型做转换。查看下来发现数据转换没有问题。就想,数据正确了,那到底发送了没有呢,如果发送了也能说明串口配置正确了吧。怎么查看呢。就用到了SThreshold和OnComm()。将SThreshold设置为1,也就是发送缓冲区空后产生事件,进入到OnComm中处理,在CommEvent==1中显示“数据已发送”。结果发现数据也发送成功了。那就更郁闷了,为什么没有返回呢,数据卡的问题?但数据卡可以用超级终端通信啊。想到AT指令的文档中的一个例子命令部分是这样写的:AT< CR>,超级终端中也按了回车键发送。这样看会不会是指令格式有问题呢。那个回车并不只是简单的把命令送进去,而是命令的一部分。当我试着加了\n字符串进去发现还是不行。只好去论坛里查了,找了好久才看到有个人说自己一开始怎么弄也不是不行,后来试着加了\r\n就可以了。我一试,果然ok,开心啦。后来又看到一篇文章,讲换行符的,写在我《AT指令集相关内容》一文中,解释了为什么要加\r\n。
      这一部分比较重要的两段代码是发送和接受的处理部分。都要进行类型转换,龚书中有。自己要理解。
     2、界面设计
      界面设计完成的比较快。先是查到可以用属性页做。然后就在借到的一本书上照着例程做了一个,只有一个属性页的。读读代码嘛,虽然不用自己设计了,但也不能太懒了,还是要搞清楚工程的各个文件,代码的各个部分。否则怎么知道怎么修改,在哪修改呢。很轻松的加了两个属性页上去。对对话框界面的工程的构成也认识的比较清楚了。这个是很重要的。
      还有后边界面完善的部分,之前只是做出个样子来,后边还要用到多个控件,用到变量和消息函数。这些都要自己体会,控件使用网上资料很多,想要控件实现某种属性功能网上都能找到。但自己要学会的是为控件添加变量和函数,尤其要区分变量是控制类型还是数值类型。区别自己去查吧,查了,自己动手做了就清楚了。还有为类添加消息处理函数。总之还是要自己做做。
      3、两个部分整合
      完成第一部分,我以为算是完成一半了。完成第二部分,我以为差不多可以了,只是串口通信和界面两部分的整合。当然这个整合我也已经预料到了会有问题存在。但实际上这一部分花了我更大的时间和精力。
      这一部分主要遇到两个难题,第一,如何在多属性页中如何应用MSComm,第二,多条AT指令同时发送和接受发生的数据混乱的问题。
      网上一致的看法是一个对话框对应一个MSComm控件。一个MSComm控件对应一个串口。有不少人也在问如何在属性页中使用MSComm,都说不行,要用别的方法。我当时差点吐血。要是真不行那我不是结束了,还怎么混啊。刚来实习第一个任务就完成不了。重新做用别的方法肯定来不及。没办法,硬着头皮做吧,感觉还有希望。
      想了想可能的解决办法:1)一个对话框用一个MSComm就用一个好了,我每个对话框都用一个,相当于都是单独操作的,但这些控件都是对同一个串口操作,页面切换的时候就把串口关闭,在另一页中重新打开。当时试的时候是失败了,由控件引起的一些不知原因的错误,不过现在想想这个方法应该也行的通,只不过那会还没有研究这么透彻,看到不行就换了另外一种方法;
      2)想到了龚书在MDI中应用MSComm的方法。这个方法是在单文本界面中应用控件,也就是脱离了对话框。当然这种方法只是看起来脱离了对话框,它其实还是把控件放到了一直没有用过的那个ABOUTBOX对话框中了,只是这种方法就要手动添加很多内容到文本view的对象中。这样才能在文本界面中使用控件。基于这种方法,我们也可以试着只在一个对话框中加入MSComm控件,而在其他属性页中都是采用类似MDI例子中的手动方法创建MSComm,而不是拖放一个控件到对话框中。手动方法创建我认为最主要是因为有m_MSComm.Create(NULL,0,CRect(0,0,0,0),this,IDC_MSCOMM1)这个语句。这样我们就已经可以在各个属性页中使用了。但多个页面中使用同一个控件会有很多问题存在,我举两个方面吧,一是在一个页面中打开串口后退出时一定要关闭串口,否则切换到另一个页面会出错;而是每个属性页都要重新配置串口,否则也会出错,并不是在一个属性页中设置好了其他属性页就不用设置了;现在可以解释下为什么一定要关闭串口,因为串口打开后就不能再对串口重新设置,这样会出错。比如打开串口后在另一个属性页中还是要重新配置串口,比如写这个语句吧setcommport(),不写的话默认就是1,写了又会出现assertion错误,就是因为没关串口就更改串口属性了。
      还有一个问题是多了指令发送的问题。要学会用debug观察数据和运行。我是用了一种发一条指令收一条相应的方法,在oncomm的接收缓冲事件处理中再调用发送指令。而不是全部发完再接收。这样接收的数据顺序是混乱的。当然可能有其他更好的解决方法了,累了,后来就没试。这里要注意一个问题,就是时延的问题,多条指令一起发送的话就一定要加时延。我这个方法到是可以不用,不过感觉不爽,不是标准的解决方法。
      4、细节、查漏、代码规范
      这一步应该算是接近大功告成了吧,呵呵,别急,事情还麻烦着呢。界面的布局和美化,代码的优化和规范,这些都是必不可少的。尤其在代码这一块,格式什么的还很不成熟,一到命名就头疼,变量就是m、n、p什么的,代码也是能在一个函数里边就在一个函数里边,喜欢扎堆。被主管给批了。但最铭心刻骨的就是要做到没有bug。因为之前觉得能实现功能就好了,至于那些bug让用户在操作的时候规范些就行了。就老想偷懒。但是没办法,还是被逼着要解决一个个出现的bug。一开始觉得麻烦,后来觉得挺有意思的,每解决一个就很开心。直到最后一个bug都没有了,就一个感觉:编一个能实现一定功能的软件不难,编一个没有bug软件才有成就感,呵呵。
      自己的三大收获:MSDN、Debug、Nobug
贴个程序吧,给大家提供一点方便,最基础的一个例子,需要修改com号:
串口号自己改下,一开始做的一个东西,可以通信的

posted on 2009-08-24 15:31  向前进  阅读(3123)  评论(2编辑  收藏  举报