您好,欢迎来到爱够旅游网。
搜索
您的当前位置:首页一种多串口多线程数据采集方法的设计与应用

一种多串口多线程数据采集方法的设计与应用

来源:爱够旅游网
第9卷第2期 职教与经济研究 Vocational Education and Economic Research Vo1.9 No.2 20 1 1年6月 Jun.,20 1 1 一种多串口多线程数据采集方法的设计与应用 胡双炎 (娄底职业技术学院,湖南娄底417000) 摘要:本文设计和实现了一种基于多串口多线程的方法,可以把多个下位机采集的信号实时的显示到中心检测计 算机上,从而能足不出户就能监测到分布在各处的下位机的情况。本方法已经应用在交通信号灯采集系统中和矿井安全 检测系统中,并取得较好的效果。 关键词:多串口;多线程;下位机;交通信号灯采集系统 中图分类号:TP393 文献标识码:A 文章编号:(2011)02—0054—05 On the Design and Application of a Collecting Method Based on Multi——serial Port and Multithreading HU Shuang——yan (Loudi Vocational&Technical College,Loudi Hunan 417000) Abstract:This paper designs and implements a method based O1"1 multi—serial port and muhithreading,which can display many sub—machines signals to the inspecting computer of the center.Thus the Sub—machines situation can be monitored in real time at office house.This method has been applied to the traffic lights collecting systems and the mine safety inspection system,which has achieved good results. Key words:Multi—serial Port;Muhithreading;Sub—machines;the Collecting System of Traffic Lights Signal 1 引言 头,带针孔的俗称母头)。如果你仔细观察,端子上 也有很小的数字做标示。第一个母头的2 3 5号,分 计算机与单片机的通信一般是通过串口进行 别连接着另一母头的3 2 5号(请注意2和3是交 的,其中计算机称为上位机,单片机称为下位机。上 错的。所以,延长完毕,你可以用万用表检测一下, 位机与下位机通过串口线连接起来,一般长度不超 一个母头的2是否连接的是另一个母头的3)。 过3米,当然也可以通过延长串口连接线的方法来 有许多学者研究过基于串口的通信,其中32位 解决。但是延长线最远不能超过13米,超过13米 下串口通信程序可以用两种方法实现:利用ActiveX 有可能有时会通讯不稳定,尽量避开强电等干扰源 控件;使用API通信函数。使用AetiveX控件(如微 走线。如果超过13米,必须使用其它的中继技术来 软公司的MSComm控件),程序实现非常简单,结构 缺点是欠灵活,访问速度比较慢;使用API通 解决,如借助光端机来使传输距离更大。串口数据 清晰,线两头的端子均为母头(9针插头上带针的俗称公 信函数的优缺点则基本上相反,使用比较灵活,访问 收稿日期:2011—04—19 作者简介:胡双炎(1974一),男,湖南双峰人,硕士研究生,娄底职业技术学院电子信息工程系讲师,主要从事软件工程研究。 总第30期 胡双炎:一种多串口多线程数据采集方法的设计与应用 BOOL closePort(); //关闭串口操作. //打开串13操作. .55. 速度比较快,但是程序实现比较复杂。 文献[1]中作者主要从原理上面说明了串口通 信的本质,并且举了一些简单的例子来应用,对于串 口通信的初学者很有参考价值。 文献[2]中作者运用Win32的API函数和c+ +类的面向对象思想封装了一个串口类CSerialPort, BOOL openPort(DCB dcb, const char portName=”COM1”); //定义串口变 量名称,缺省为”COM1”. _//读串口通信数据. //读串口数据的输 BOOL readscc(char inputData, 入缓冲区 这样就增加了对串口操作的透明度,提高了串口传 coust unsigned int&sizeBuffer, unsigned long&length); //缓冲区最大长度 //实际接收缓冲区数据的长 输数据的可靠性,但是主要针对单个串口的情况,对 于多串口的操作还有待优化。 文献[3]中作者主要把多线程技术应用于串口 通信,解决了界面线程与串口通信线程的并发操作 问题。 文献[4]中作者讲解了一个多串口多线程数据 采集软件的设计与实现,对于多个串口同时传输数 据的场合是很有参考价值的。 本论文在参考以上文献的基础上,尤其是文献 [4]的基础上,提出了一种多串口多线程数据采集的 设计方法,然后在VC++中,运用面向对象方法设 计了一个基于Win32的API的串口封装类CSeria一 1Ex,然后基于多线程父类CWinThread设计了子类 CSerialThread,在子类中运用了CSerialEx来进行多 线程多串口的通信,然后封装成DLL组件文件,方便 升级与维护。与文献[4]的主要区别是:自己把串口 操作封装成类,设计了自定义的多线程类CSeri— alThread,考虑到升级和维护问题,把所有的功能封 装成DLL组件。下面详细对设计和实现过程进行 论述: 2设计自定义串口操作类CSerialEx 为了提高灵活 和访问速度,串口操作类CSe— rialEx封装了Win32 API访问串口的函数,具体如 下:CSerialEx类的定义: class CSerialEx {public: CSerialEx(); virtual—CSerialEx();public: void setStatusPort(BOOL on_off); //设置串口是否打 开或关闭. 度. //向串口写数据 BOOL write_scc(LPCVOID data, //写数据的缓冲区 指针 const unsigned int&sizeBuffer, //写缓冲区的最大 长度 unsigned long&length); //写缓冲区的实际长度. HANDLE getHandlePort(); //获取串口的句柄 BOOL getStatusPort(); //获取串口的打开状态. private: BOOL statusPort一; //串口的打开状态. HANDLE handlePort一; //串IS1的旬柄. DCB config_; //串口通信的结构变量. }; CSerialEx类的实现过程为: 构造函数为:CSerialEx::CSerialEx() . :statusPort一(FALSE),//串口初始为关闭 handlePort一(NULL)//串口句柄初始为空 t //串口通信的结构变量的初始值. config._ByteSize:8; //串口的数据位为8位. config._StopBits=ONESTOPBIT; //串lYl的停止位为 1位. config.Parity=NOPARITY; //设置奇偶校验位为没 有校验位 config._BaudRate=CBR一9600; //设置波特率为 960o位/秒 } 读串13数据的函数:BOOL CSerialEx::read scc(char¥inputData, const unsigned int&sizeBuffer, unsigned long&length) }//调用API函数ReadFile读串口数据 ・56・ 职教与经济研究 总第30期 if(ReadFile(handlePort一,//串口的句柄 inputData, //读缓冲区 sizeBuffer, //读缓冲区的最大长度 &length, //读缓冲区的实际长度 NULL)==0) //是否异步读取数据 { AfxMessageBox(‘‘读串口数据遇到问题。”); return FALSE; } if(1ength>0) { inputData[1ength]=NULL;//设置缓冲区的结束标记. return TRUE; } return TRUE; } 写串口数据的函数:BOOL CSerialEx::write—SCC(LPCVOID outputData,//写缓冲区的 指针 const unsigned int&sizeBuffer,// 写缓冲区的最大长度 unsigned long&length)//写缓冲 区的实际长度 { if(1ength>o)// ̄n果有要写入串口的数据 }//调用写文件函数向串口写数据 if(WriteFile(handlePort一,//串口的句柄 outputData, //写缓冲区指针 sizeBuffer, //写缓冲区的最大长度 &length, //写缓冲区的实际长度 NULL)==0) //是否支持异步读取 { AfxMessageBox(“向串口写数据遇到问题.”); return FALSE; } retum TRUE; } return FALSE; } 打开串口openPort和关闭串口closePort的函数就不列 出了。 3设计自定义多线程操作串口类CSerialThread 类CSeriaiThread的定义为:class CSerilaThread:public CWin Thread { DECLARE—DYNCREATE(CSerialThread) protected: CSerialThread(); //保护构造函数 //Attributes public: CSerialEx m_SerilaEx;//定义串口类的变量 DCB configSerila一;//定义串口的参数结构变量 CView p View;//定义数据要显示的视图 //Operations public: //Overrides //ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CSerialThread) public: virtual BOOL Initlnstance(); virtual int Exitlnstance(); virtual int Run(); //}}AFX—VIRTUAL //Implementation protected: virtual~CSerialThread(); //Generated message map functions //{{AFX_MSG(CSerialThread) //NOTE~the ClassWizald will add and remove member functions here. //}}AFX_MSG DECLARE—MESSAGE—MAP() }; 类CSerialThread的实现过程为: 线程的初始化函数为:BOOL CSerialThread::lnitln. stance() { configSerial.一ByteSize=8;//串口的数据位为8位. 总第30期 configSerial一胡双炎:一种多串口多线程数据采集方法的设计与应用 ..57. StopBits=ONESTOPBIT;//串口的停止 位为1位. configSerial一.4在视图类中调用CSerialThread Parity=NOPARITY;//设置奇偶校验位 4.1视图类中要做的工作 为没有校验位 configSerial一在VC++的视图类中定义指针变量:CSeri— .BaudRate:CBR一9600;//设置波特率 alThread serialProcess; 为9600位/秒 在视图类的初始函数OnlnitialUpdate()初始化 VERIFY(m—SerialEx.openPo ̄(configSerial一));//打开 串口 指针变量: return TRUE; serialProcess=(CSerialThread )::AfXBe- } ginThread(RUNTIME—CLASS(CSerialThread)); 线程的运行函数为:int CSerialThread::Run() serialProcess一>p~View=this;//把视图对象 ; 指针传人线程中,方便显示线程中的数据 CTrafficView pView=(CTraffieView )pView;// 在视图类中定义函数OnReceiveData来把线程 得到视图类,方便把接收的串口数据显示其上 中接收的数据显示到视图界面中: char mess[MAX—MESSAGE];//定义接收缓冲区 OnReceiveData(char buff,int length)//buff unsigned int lenBuff=MAX—MESSAGE;//定义接收缓 是接收数据的缓冲区,length指缓冲区的长度 冲区的长度变量 4.2视图类中的执行过程 unsigned long lenMessage;//定义每次实际接收缓冲区 当程序运行时,视图类中的初始函数OnInitia- 的长度变量 1Update会自动调用,就启动线程serialProcess,然后 while(1)//为了不断接收串口数据,这里定义了一个 线程中的Run运行函数就不断运行,接收所打开的 死循环 { 串口(第一个串口是”COM1”)的数据,并调用视图 if(m—SerialEx.read—see(mess,lenBuff,lenMessage) 中的函数OnReceiveData(char:l:buff,int length) =:TRUE)//3%果接收到串口数据 来把接收的数据显示到视图界面中。 { 4.3 同时接收多串口数据的显示 if(1enMessage>0)//接收到了串口的数据长度必 4.2节只是启动了一个线程来接收一个串口 须大于0 的返回数据,如果要同时接收多个串口的数据,则 { 可以在视图类中创建一个线程数组对象,具体过程 pView一>OnReceiveData(iness,lenMessage);//实 如下: 时把接收到数据数组显示到视图中 在VC++的视图类中定义指针数组变量: l CSerialThread:}:serialProcess[MAX—PORTS];  }//其中MAX—PORTS为总的串口数量 else 在视图类的初始函数OnlnitialUpdate()初始化 { break;//如果没有从串口接收到数据就接收本次线程 指针变量: } f0r(int i=0;i<MAX—PORTS;i++){ } serialProeess  Ii!=(CSerialThread )::AfXBe— return CWinThread::Run();//调用MFC缺省线程的运行 ginThread(RUNTIME—CLASS(CSerialThread)); 函数 serialProcess[i]一>p_View:this;//把视图对 } 象指针传入线程中,方便显示线程中的数据 ・58・ } 职教与经济研究 总第30期 还有一个问题也值得研究,当同时有3O路交 在视图类中定义函数OnReceiveData来把线程 通信号数据返回来,如果同时显示到视图界面上 中接收的数据显示到视图界面中: OnReceiveData(char 面,比较闪。这时可以从两个方面来减轻闪烁的程 buff,int length)//buff 度:(1)在视图区中采取双缓冲区技术来显示数据 是接收数据的缓冲区,length指缓冲区的长度 (即先把要显示的数据加载到缓冲区中,最后一次 注意:在多线程数据中的OnReceiveData函数 显示出来);(2)其实每个路口返回的红绿灯信号 中要用同步信号量(或者临界区)保证各个串口返 大部分时问是相同的,只是在红灯变绿灯、绿灯变 回的数据不会混到一起。 4.4 当串口数量超过9以后的注意事项 当串口小于10时,打开串口的通用过程为: openPon(dcb,“COMn”);//其中n的取值为 1到9 当串口大于9以后,打开串口的通用过程为: openPo ̄(dcb,“\\.\COMn”);//其中n的取 值为9之后的整数 如果要打开串口”COMIO”,如果用openPo ̄ (dcb,”COMIO”);就会出错,提示说不能打开串口 COMIO。如果改成openPo ̄(dcb,”\\.\COMIO”); 就能成功,这是经过多次的实验才找出的规律。 5小结 把上面开发的多串口多线程数据采集方法用 于交通信号灯信号数据采集过程中,如果在一台中 心端电脑上面同时采集的交通路口数量小于30 个,能实时的接收数据并解析显示到视图界面。当 超过30个时,软件运行速度有些缓慢,有时接收的 数据错误率比较高。此时必须再买一台电脑来接 收超过30个以上的返回的数据。 红灯或黄闪的时候返回的数据才有变化,其它时间 都是不变的,找到了这个规律,界面上面要改变显 示数据的频率就降低了许多,对界面刷新频率就比 较低了。 当然本文中所设计的多串口多线程采集数据 的方法也可以应用于其它场合,如已经应用于矿井 安全检{=910系统中,一台中心计算机能通过多串口同 时检测一个矿井中多处的安全通道的情况,从而确 保各通道的安全。最后可以根据实际情况进行修 改,或者做成Dll组件,就更加方便使用了。 参考文献: [1]李现勇.Visual C++串口通信技术与工程实践[M].北 京:人民邮电出版社,2002. [2]任丽红,张晓燕.在VC++中开发串I3"类及串口通信 应用程序[J].北京石油化工学院学报,2001,(09). [3]尹德春.多线程技术在串口通信中的应用[J].微计算 机信息,2005,(08). [4]李勇.一个多串口多线程数据采集系统软件的设计与 实现[J].微计算机信息,2006,(16). (责任编辑:刘康民) 

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- igbc.cn 版权所有 湘ICP备2023023988号-5

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务