应时间要求较严格,可采用事件驱动 I/O 读写,Windows 定义了 9 种串口通信事件,较 常用的有: ---- EV_RXCHAR: 接收到一个字节,并放入输入缓冲区。 ---- EV_TXEMPTY: 输出缓冲区中的最后一个字符发送出去。 ---- EV_RXFLAG: 接收到事件字符(DCB 结构中 EvtChar 成员),放入输入缓冲区。 ---- 在用 SetCommMask()指定了有用的事件后,应用程序可调用 WaitCommEvent()来等待事件的发生。 SetCommMask(hComm,0)可使 WaitCommEvent()中止。 ---- 方法三 多线程下实现串行通信 ---- 方法一,二适用于单线程通信。在很多工业控制
系统中,常通过扩展串口连接多个外设,各外设发送数据 的重复频率不同,要求后台实时无差错捕捉,采集,处理,记录各端口数据,这就需要在自定义的串行通信类中 创建端口监视线程,以便在指定的事件发生时向相关的窗口发送通知
消息。 ---- 线程的基本概念可详见 VC++参考书目, Windows 内部的抢先调度程序在活动的线程之间分配 CPU 时间, Win 32 区分两种不同类型的线程,一种是用户界面线程 UI(User Interface Thread),它包含消息循环或消息泵, 用于处理接收到的消息;另一种是工作线程(Work Thread),它没有消息循环,用于执行后台任务。用于监视 串口事件的线程即为工作线程。 ---- 多线程通信类的编写在端口的配置,连接部分与单线程通信类相同,在端口配置完毕后,最重要的是根据 实际情况,建立多线程之间的同步对象,如信号灯,临界区,事件等,相关细节可参考 VC++ 中的同步类。
---- 一切就绪后即可启动
工作线程:
CWinThrea *CommThread = AfxBeginThread(CommWatchThread, m_pTTYInfo, 优先级 (UINT) 0, //
// 线程函数名 (LPVOID) // 设置线程
// 传递的参数 THREAD_PRIORITY_ABOVE_NORMAL, // 最大堆栈大小 (DWORD)
CREATE_SUSPENDED , 志
创建标志 (LPSECURITY_ATTRIBUTES) NULL);
//
安全性标
---- 同时,在串口事件监视线程中:
if(WaitCommEvent(pTTYInfo->idComDev,&;dwEvtMask,NULL)) pTTYInfo->dwEvtMask )== pTTYInfo->dwEvtMask) { WaitForSingleObject(pTTYInfo->hPostEvent,0xFFFFFFFF); // 置同步事件对象为非信号态 息 } }
{ if((dwEvtMask
&;
ResetEvent(pTTYInfo->hPostEvent); // 发送通知消
::PostMessage(CSampleView,ID_COM1_DATA,0,0);
---- 用 PostMessage()向指定窗口的消息队列发送通知消息,相应地,需要在该窗口建立消息与成员函数间的 映射,用 ON_MESSAGE 将消息与成员函数名关联。
BEGIN_MESSAGE_MAP(CSampleView, CView) //{{AFX_MSG_MAP(CSampleView)ON_MESSAGE(ID_COM1_DATA, OnProcessCom1Data) OnProcessCom2Data) ON_MESSAGE(ID_COM2_DATA, .....//}}AFX_MSG_MAPEND_MESSAGE_MAP()
---- 然后在各成员函数中完成对各串口数据的接收处理,但必须保证在下一次监测到有数据到来之前,能够完 成所有的中间处理工作。否则将造成数据的捕捉错误。 ---- 多线程的实现可以使得各端口独立,准确地实现串行通信,使串口通信具有更广泛的灵活性与严格性,且 充分利用了 CPU 时间。但在具体的实时监控系统中如何协调多个线程,线程之间以何种方式实现同步也是在多 线程串行通信程序实现的难点。 ---- 以 VC++ 6.0