VC串口通信新解

更新时间:2023-11-28 07:00:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

VC串口通信新解

VC串口通信是一古老的话题,本文主要着重于PC与单片机的串口通信。随着硬件技术的发展,尤其是单片机的通信能力越来越强,过往很多年非常经典的、工作得很好的串口程序,在结合硬件特点后,能效率更高。

同样是UART口,PC与早期的单片机是不对等的,PC端UART controller + DMA ,只用开个读写缓冲,收发基本是全自动的,有完善的流控机制。

单片机早期的大多是UART控制器,无硬件流控(可用GPIO仿),UART也不支持DMA。 软件上常用查询、中断(效率高一些),没有DMA,还是要软件来搬运数据。近年来,单片机的UART通信能力不断增强,基本与PC的UART对等,比如TI 的MSP430、CC2530等,片上支持UART+DMA,支持硬件流控,功能强大。 有意思的是,有些笔记本上省去了UART口。但UART口对于上下位机应用,尤其在工控行业有广泛的应用。

早期的C语言,可直接操作端口,能象单片机那样来操作UART口,软件上降格与单片机对等,程序工作很稳定。

VC编写的串口程序,网上有很多,比如串口助手,很经典、适应性很强,不怎么挑下位单片机,不管单片机支持DMA+UART与否,都可稳定工作。

单片机支持UART +DMA 最大的意义就是在发送一串字节时,

字节间的interval是可控的,这样就非常有利于interval_timeout的实施。只要字节间隔小于interval_timeout, 就认为是同属于一个数据幀。这样就便于通信协议的实施。当然采用定时中断也能实现,如果只是偶尔配置一下下位单片机参数,数据量不大,没问题。若用于下位机周期性的上报数椐,定时中断就太频繁,再加上下位机若同时是一网关,就影响吞吐量。

说到这里,着重提一下PC与单片机通信的数据幀的实现: 数据格式有二进制和ASCII码两种,如果是ASCII码格是式,要简单许多,很容易定义一个专用的数据幀开始标志,相应地对字节间的interval要求比较宽松。

对于二进制格式,有两种方法:

a: 同样需要一个标志字节,比如为0xFE, 对于发送方,同一幀内其它字节,碰巧等于0xFE的,变换位0xFD 0xDE。等于0xFD的,变换为0xFD 0xDD。对字节间的间隔要求较宽松,适用于早期不支持UART+DMA的单片机。

b: 用字节间的interval_timeout 来划分不同的数据帧。这种方法需要支持UART+DMA的单片机。

以下主要是支持UART+DMA的单片机与VC写的串口程序之间的配合:

首先,对于单片机要开启DMA+UART工作模式,开辟收发缓冲区(一两百个字节是没问题的)。对单片机的数据帧格式无特殊的要求,可以定义一个帧开始标志字,只起辐助帧划分作用。对Binary

&ASCII也是透明的,要发送的数据帧放到缓冲区即可,充分发挥硬件处理能力。

对于上位机PC来说,用VC利用Win32 API编写串口通信程序,一些常规的选项如baud, parity, stop etc 就不说了,有几个关键点如下:

1、 超时设定,具体就是COMMTIMEOUTS

m_CommTimeouts .ReadIntervalTimeout = 1;

m_CommTimeouts.ReadTotalTimeoutMultiplier = 0;

m_CommTimeouts.ReadTotalTimeoutConstant = 0; m_CommTimeouts.WriteTotalTimeoutMultiplier = 0; m_CommTimeouts.WriteTotalTimeoutConstant = 0; 也就说接收字节间超时为1ms。

2、 串口的overlapped & non-overlapped操作

由于ReadIntervalTimeout = 1ms, 是同步还是异步操作主要取决于ReadFile()一次读取的数据帧字节数,数据帧很短,几个字节,同步ReadFile()也能很快返回(比如5bytes, 1/9600 *10 *5 s)。就是20几个字节,对ReadFile()所在thread的响应也问题不大。 偏好采用异步模式。

3、 ReadFile() API 与 UART硬件的同步:

说是和 UART 硬件的同步,这个“硬件”也是比较抽象的概念,早期的C操作UART端口还是很具体的。现在很多笔记本已省掉UART口, 可用USB转UART,更安全支持热插拔。ReadFile()与真正的

UART硬件间又隔了一层。

简单讲,上位机的VC串口程序开始运行后,清收发缓冲区,一般收发各对应一个 thread, 以接收thread为例:thread与PC上众多的threads 分时操作,写得好的串口接收thread,不管wait什么,都是主动让出时间片。Thread是在一些不连续的时间窗口内操作串口,而UART口数据帧的到达是随机的。这就需要FIFO缓冲,而ReadFile()正好又没有interval_timeout超时, 系统把FIFO中的不断涌入的字节搬到ReadFile()指定的缓冲区中,下位机一个数据帧发完后,FIFO不再涌入字节,时长大于interval_timeout后,同步操作是ReadFile()返回,异步操作是WaitForMultipleObjects()返回,完成一个数据帧的读取。下面结合VC接收thread内代码实例片段: // if no read is outstanding, then issue another one if (!fWaitingOnRead) {

if (!ReadFile(UART_handle, lpBuf, MAX_FRAME_SIZE+10, &dwRead, &osReader)) { if (GetLastError() != ERROR_IO_PENDING) // read not delayed? ErrorInComm(\);

fWaitingOnRead = TRUE; }

else { // read completed immediately

if ((dwRead != MAX_READ_BUFFER) && SHOWTIMEOUTS(TTYInfo)) UpdateStatus(\); if (dwRead)

Frame_process(hTTY, lpBuf, dwRead); } }

………

if (fWaitingOnRead ) {

dwRes = WaitForMultipleObjects(NUM_READSTAT_HANDLES, hArray, FALSE,

STATUS_CHECK_TIMEOUT);

switch(dwRes) {

// read completed case WAIT_OBJECT_0:

if (!GetOverlappedResult(UART_handle, &osReader, &dwRead, FALSE)) { if (GetLastError() == ERROR_OPERATION_ABORTED) UpdateStatus(\); else

ErrorInComm(\); }

else { // read completed successfully

if ((dwRead != MAX_READ_BUFFER) && SHOWTIMEOUTS(TTYInfo)) UpdateStatus(\); if (dwRead)

Frame_process(hTTY, lpBuf, dwRead); }

fWaitingOnRead = FALSE; break; …………..

以上代码中

fWaitingOnRead 保证在上一个overlapped reading 完成后,马上再开始下一个。 主干就是 :

A: ReadFile(UART_handle , buffer_start, max_frame_size+10, ….)

注意readfile一次读取的预设值为 max_frame_size+10

B: WaitForMultipleObjects() 》thread休息》 thread switch

如果没有字节到达,thread就一直阻塞在WaitForMultipleObjects(), 虽然ReadIntervalTimeout =1ms,但要等到收到一个字节才触发。

如果有下位机DMA+UART 上传的数据帧首字节到达,一个数据帧收完前不会超时,下位机发完一幀,静默超1ms , 上位机readfile 超时,switch back到接收thread》C:

C: GetOverlappedResult(UART_handle, &osReader, &dwRead, FALSE) Frame_process() 返回 A:

4、通信的完整性

通过以上VC代码很简洁地实现了PC与单片机间的数据帧格式的通信,实测也很稳定。 也不需要VC中,UART DCB中提到的软、硬件流控,各种FRAME、PARITY 校验也可关掉。通过在数据帧的末尾追加一XOR checksum来验证数据帧完整性。

对数据完整性要求很高的话,比如工控场合,可在数据帧中采用两字节的CRC校验码。 5、 效率:

上面的VC代码,看上去平淡无奇,普通的overlapped read模式,与工作于UART+DMA的下位单片机通信时,很稳定。 上、下位机都最大限度地发挥了硬件的潜力。

本文来源:https://www.bwwdw.com/article/7g4t.html

Top