在嵌入式项目开发中,经常会涉及到数据的交互。比如汽车电子产品中的CAN通信,数据的收发经常是偶发的,一般有事件产生,就会回触发一些网络数据,这些网络数据在总线上往往是偶尔产生的,而且可能会集中触发。但是对于单个处理器,是不能及时处理多个集中触发的任务的,因此必须要借助数据缓冲技术。当然首先需要硬件资源支持,再才能通过软件依次处理这些缓冲数据。
我们先来看一下CAN总线系统:
我们还是以实际项目举例,比如选用NXP KEA128的单片机,其CAN接收、发送缓冲区特性描述如下:
• 采用FIFO 存储方案的5个接收缓冲区
• 3 个发送缓冲区,采用“本地优先级”概念进行内部排序
这里相当于接收有5个缓冲区,发送有3个缓冲区。接收一般多于发送,因为发送是主动的,可控的;而接收是被动的,不可控的。
接收报文缓冲采用如下的结构:
从Rx0到Rx4,采用FIFO也就是先进先出的原则。硬件接收缓冲器有5个,也就是说这款处理器,在一个处理周期内,底层最多存放5个数据帧,也就是说同一时间内只能接收5个数据帧,多了就会被覆盖掉。
接收报文中断函数
-
void MSCAN_RX_Handler(
void)
-
{
-
stMsgBuf * pBuf;
-
......
-
-
pBuf = &(RxMsgBuf[RMB_i]);
-
-
pBuf->Dat[
0] = MSCAN_REDSR0;
-
pBuf->Dat[
1] = MSCAN_REDSR1;
-
pBuf->Dat[
2] = MSCAN_REDSR2;
-
pBuf->Dat[
3] = MSCAN_REDSR3;
-
pBuf->Dat[
4] = MSCAN_REDSR4;
-
pBuf->Dat[
5] = MSCAN_REDSR5;
-
pBuf->Dat[
6] = MSCAN_REDSR6;
-
pBuf->Dat[
7] = MSCAN_REDSR7;
-
pBuf->DatLen = (MSCAN_RDLR &
0x0F);
-
pBuf->IDReg[
0] = MSCAN_RSIDR0;
-
pBuf->IDReg[
1] = MSCAN_RSIDR1;
-
-
RMB_i++;
-
if (RMB_i >=
5)
-
{
-
RMB_i =
0;
-
}
-
......
-
}
依靠中断函数接收到的所有报文,尽量要在一个时间片里全部处理完成。如果处理不完,就必须用到二级缓存,二级缓存的空间可以比实际硬件缓存空间定义得大一点。比如这里的RxMsgBuf[RMB_i],可以定义8到16个缓冲空间。那么接收中断函数就可以改成:
-
void MSCAN_RX_Handler(
void)
-
{
-
stMsgBuf * p2Buf;
-
......
-
-
p2Buf = &(RxMsg2Buf[RM2B_i]);
-
-
p2Buf->Dat[
0] = MSCAN_REDSR0;
-
p2Buf->Dat[
1] = MSCAN_REDSR1;
-
p2Buf->Dat[
2] = MSCAN_REDSR2;
-
p2Buf->Dat[
3] = MSCAN_REDSR3;
-
p2Buf->Dat[
4] = MSCAN_REDSR4;
-
p2Buf->Dat[
5] = MSCAN_REDSR5;
-
p2Buf->Dat[
6] = MSCAN_REDSR6;
-
p2Buf->Dat[
7] = MSCAN_REDSR7;
-
p2Buf->DatLen = (MSCAN_RDLR &
0x0F);
-
p2Buf->IDReg[
0] = MSCAN_RSIDR0;
-
p2Buf->IDReg[
1] = MSCAN_RSIDR1;
-
-
RM2B_i++;
-
if (RM2B_i >=
16)
-
{
-
RM2B_i =
0;
-
}
-
......
-
}
这里的“二级缓存”,实际上是一个纯软件概念。就是为了解决如果一个时间片处理不完当前收到的所有报文,是可以累积到下个时间片再处理的。中断函数只负责把收到的报文往二级缓存里放,当然这里放满了16个的话,也会产生二级缓存溢出,所以应用层的处理函数也需要及时去提取报文做处理。
与之相对应的发送报文缓冲采用如下的结构:
其实和接收报文的缓冲原理上差不多,只是优先级可以自己配置。相对接收实现起来会比较简单,也不需要建立二级缓存,因为完全可以自己控制发送流量。
原文:https://www.toutiao.com/i6951918761750315553/
转载:https://blog.csdn.net/daocaokafei/article/details/116245767