65.9K
CodeProject 正在变化。 阅读更多。
Home

带读线程的串口读写

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.10/5 (10投票s)

2010年5月31日

CPOL

4分钟阅读

viewsIcon

63192

downloadIcon

4351

一个简单的通信端口实现, 带有用于嵌入式系统的读取线程

引言

在运行实时操作系统的嵌入式系统中,经常需要与PC进行通信,通常是通过串口。嵌入式系统上的实时操作系统进行任务分时,可能无法响应PC(GUI程序/DOS界面程序)发出的请求。因此,如果PC程序能够发起请求,等待响应,并在PC串口上发生事件时捕获响应,那将非常有用。

背景

我曾使用过ARM7和ARM9的串口(UART & USART)接口。我经常使用串口FIFO的“非空”条件,即当一个字符或一批字符可用时,微控制器可能会被中断,并且数据可以根据硬件条件读取,而不是频繁地轮询端口寄存器。

我想,为什么不尝试看看PC的串口是否也能实现这一点呢?Windows是一个多任务多线程操作系统,所以它必须提供实现这一点的方法。是的,它提供了,并且这是帮助你实现这一点的应用程序。

Using the Code

你真正需要做的就是调用

OpenComPort( int port, int rate, int parity, int retries )  

函数,该函数使用CreateFile函数以重叠(异步)I/O模式打开指定的Comm.端口(通过intport参数指定)。

此应用程序遵循Microsoft知识库文章q115831http://support.microsoft.com/kb/115831),该文章允许你打开大于9的Comm端口号。指定的波特率、奇偶校验和其他串口参数将被填入已打开Comm.端口的DCB结构中。

然后...

if (!GetCommMask (hPort, &fdwEventMask)) //get current event mask
          fdwEventMask = 0;   

...使用(GetCommMask)函数获取(并清除/初始化)已经发生的任何事件。

现在,

 fdwEventMask |= EV_RXCHAR | EV_TXEMPTY | EV_BREAK | EV_ERR | 
		EV_RING | EV_RLSD | EV_CTS | EV_DSR  ;

 SetCommMask(hPort, fdwEventMask);      

fdwEventMask被初始化为所需的事件,并使用(SetCommMask)设置到事件寄存器中。当所需的/指定的事件发生时,Read线程将运行(如下文所述)。

点击events,查看各种串口事件的位掩码(在编写此com_port.cpp时参考了整个KB文章,请注意查看Table 1中的事件)。我在嵌入式系统中使用了类似以下的事件:

  • EV_RXCHAR(0x0001) - 接收到一个字符并放入输入缓冲区
  • EV_TXEMPTY(0x0004) - 输出缓冲区中的最后一个字符已发送

下一步是初始化临界区rxLockrxBuffer的内存。

此时,创建了Read线程。在RxThread中,初始化包括为接收数据设置一个OVERLAPPED结构commSync

使用(CreateEvent)函数创建一个事件commEvent,并将该事件同步到commSynchEvent(事件句柄)中。

使用以下方法等待Comm端口上的事件:

waitState = WaitCommEvent(hPort, &fdwEventMask, &commSync);  

引用:WaitCommEvent等待指定的通信设备上的事件发生。此函数监视的事件集包含在与设备句柄关联的事件掩码中。

事件发生后,会查找特定的事件,即EV_RXCHAR | EV_BREAK | EV_ERR | EV_TXEMPTY

if (fdwEventMask & (EV_RXCHAR | EV_BREAK | EV_ERR | EV_TXEMPTY))

注意:在我的应用程序中,EV_BREAKEV_ERR用于传输错误(例如:奇偶校验错误或硬件故障导致的通信丢失)。其他两个事件得到了广泛使用。

接收到的数据被传输到rxBuffer(进行了一些错误检查和数据大小检查)。

示例

呼叫

WriteComPort( char *sendString, unsigned char txCount ); 

函数,用于将字符数组写入嵌入式系统。要写入的数组应根据通信可能需要的任何协议来形成。在我的应用程序中,数据包包含一个SOF和一个EOF。

SOF是嵌入式系统的地址(如果启用了寻址)和/或字节计数。

EOF是除校验和之外的其余字节的模256校验和。

通常,写入一条消息后,嵌入式系统会做出响应,当数据到达PC的串口寄存器时,一个或所有指定的事件都会被生成。响应消息将在rxBuffer中可用。

可以使用ReadRxChar函数读取rxBuffer中的接收数据。可以使用for循环按以下方式读取数据块:

  for (int x = 128 ; x; --x )
   {
      if (ReadRxChar( &c ))
                return( (unsigned int)c );
      Sleep( 10 );
   } 

CloseComPort将关闭RxThread并关闭Comm.端口。comm_port.cpp中的其他函数可以根据需要使用。

历史

  • 2010年5月31日:首次发布
© . All rights reserved.