首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

单片机程序架构4

单片机程序架构4

串口接收数据帧

串口接收时用中断方式的,这无可厚非。但如果你试图在中断服务程序中完成一帧数据的接收就麻烦大了。永远记住,中断服务函数越短越好,否则影响这个程序的

实时性能。一个数据帧一般包括若干个字节,我们需要判断一帧是否完成,校验是否正确。在这个过程中我们不能用软件延时,更不能用死循环等待等方式;

所以我们在串口接收中断函数中,只是把数据放置于一个缓冲队列中。

至于组成帧,以及检查帧的工作我们在主循环中解决,并且每次循环中我们只处理一个数据,每个字节数据的处理间隔的弹性比较大,因为我们已经缓存在了队列里面。

/*==========================================

功能:串口发送接收的时间事件

说明:放在大循环中每10ms一次

输出:none

输入:none

==========================================*/

void

UARTimeEvent(void)

{

if (TxTimer !=

0)//发送需要等待的时间递减

--TxTimer;

if (++RxTimer > RX__RESET)

//

RxCnt = 0;

//如果接受超时(即不完整的帧或者接收一帧完成),把接收的不完整帧覆盖

}

/*==========================================

功能:串口接收中断

说明:接收一个数据,存入缓存

输出:none

输入:none

==========================================*/

interrupt

[USART_RXC] void uart_rx_isr(void)

{

INT8U

status,data;

status = UCSRA;

data = UDR;

if ((status
&
(FRAMING_ERROR | PARITY_ERROR |
DATA_OVERRUN))==0){

RxBuf[RxBufWrIdx] =
data;

if (++RxBufWrIdx
== RX_BUFFER_SIZE) //接收数据于缓冲中

RxBufWrIdx =
0;

if (++RxBufCnt
== RX_BUFFER_SIZE){

RxBufCnt =

0;

//RxBufferOvf=1;

}

}

}


/*==========================================

功能:串口接收数据帧

说明:当非0输出时,收到一帧数据

放在大循环中执行

输出:==0:没有数据帧

!=0:数据帧命令字

输入:none

==========================================*/

INT8U

ChkRx(void)

{

INT8U dat;

INT8U cnt;

INT8U

sum;

INT8U ret;

ret = RX_NULL;

if (RxBufCnt !=

0){

RxTimer = 0;

//清接收计数时间,UARTimeEvent()中对于接收超时做了放弃整帧数据的处理

//Display();

cnt =

RxCnt;

dat = RxBuf[RxBufRdIdx]; // Get Char

if (++RxBufRdIdx
==
RX_BUFFER_SIZE)

RxBufRdIdx =

0;

Cli();

--RxBufCnt;

Sei();

Buf[cnt++] =

dat;

if (cnt >= _LEN)// 组成一帧

{

sum = 0;

for
(cnt
= 0;cnt < (_LEN - 1);cnt++)

sum+= Buf[cnt];

if (sum ==

dat)

ret = Buf[0];

cnt = 0;

}

RxCnt =

cnt;

}

return

ret;

}

以上的代码ChkRx()可以放于串口接收数据处理函数RxProcess()

中,然后放入主循环中执行即可。以上用一个计时变量RxTimer,很微妙的解决了接收帧超时的放弃帧处理,它没有用任何等待,而且主循环中每次只是接收一个字节数据,时间很短。
返回列表