串口接收数据帧
串口接收时用中断方式的,这无可厚非。但如果你试图在中断服务程序中完成一帧数据的接收就麻烦大了。永远记住,中断服务函数越短越好,否则影响这个程序的
实时性能。一个数据帧一般包括若干个字节,我们需要判断一帧是否完成,校验是否正确。在这个过程中我们不能用软件延时,更不能用死循环等待等方式;
所以我们在串口接收中断函数中,只是把数据放置于一个缓冲队列中。
至于组成帧,以及检查帧的工作我们在主循环中解决,并且每次循环中我们只处理一个数据,每个字节数据的处理间隔的弹性比较大,因为我们已经缓存在了队列里面。
/*==========================================
功能:串口发送接收的时间事件
说明:放在大循环中每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,很微妙的解决了接收帧超时的放弃帧处理,它没有用任何等待,而且主循环中每次只是接收一个字节数据,时间很短。 |