笔者来聊聊can的认识以及can接收数据的驱动编写
Can的特性就不多说了,主要来聊聊can的一些标识符以及收发状态。can有一套收发机制,发送和接收都有硬件缓存,叫邮箱,通过下面的图可以看出,下面这张图很经典,被各大网站和博客上面引用。
发送时,有三个报文邮箱缓存,接收时有两个fifo缓存,每个fifo有三个邮箱。
从上面图还可以看出,can数据接收到fifo,是经过滤波器过滤才可以到fifo,总共有27个过滤器(互联型,其他只有13个)每个标识符经过一个滤波器后就可以到接收fifo。
3个发送报文缓存邮箱,发送时如果有之前的报文没发送出去,会缓存在邮箱里面,等待发送。
之所以用邮箱,是因为邮箱不仅可以有优先级发送,也可以顺序发送(fifo)
发送时的几个状态:
can总线上面一般会有多个设备,那么总线上的数据,多个设备都会收到,那么就需要指明“地址”进行过滤掉其他数据。
can里面一般会用标识符规则来过滤数据,会根据此标识符确定是否接收该数据,一般不说标识符是can的节点,因为标识符可修改,或者该标识符可以过滤筛选一组can数据,
过滤通常有两种方法,标识符列表模式,标识符掩码模式
换句话说:筛选一组标识符,则选用掩码模式,筛选特定标识符,则选用标识符列表模式。
每个过滤器有两个寄存器可用,均是32位,可以拆分为2个16位的寄存器来使用,则相当于多了1过滤器来使用。
初步看上面这张表,笔者也看的不是很懂,后面仔细研究过后,其实这是一个过滤器的多种配置,
然后接下来这张表就可以看懂了。多个过滤器的一种配置方式,以及编号,该编号可以再收到数据的时候打印出来,可以判断是哪个过滤器接收到的数据。
注意:
typedef struct
{
uint32 t stdid;
uint32 t ExtId;
uint8 t IDE;
uint8 t RTR;
uint8 t DLC;
uint8 t Data[8];
uint8 t FMI;
}CanRxMsg;
/* CanRxMsg.FMI 就是指示了哪个过滤器的过滤出来的该数据,
接收时上述已经提过,有两个fifo,每个fifo有3个邮箱,那么总共可以存储6个报文(硬件存储)。
共有三个状态:有报文,报文满,报文溢出。
FMP:指示了当前有多少报文
FOVR:指示是否溢出,
需要注意的是:
can中断接收数据
CanRxMsg Can1RxMessage;
u8 can1_data_flag;
u8 can1_data_len;
u8 can1_broadcast_flag;
void CAN1_RX0_IROHandler(void)
{
/*receive a can messaae*/
CAN_Receive(CAN1,CAN FIFO,&Can1RxMessage);
can1_data_flag = TRUE;
can1_data_len = Can1RxMessage.DLC;
/*check if is broadcast data */
if(CAN_BROADCAST_CMD== Can1RxMessage.ExtId )
can1_broadcast_flag = TRUE;
else
can1_broadcast_flag = FALSE:
}
CAN_EIFORelease(CAN1, CAN_FIFO):
CAN_IT_Config(CAN1, CAN_IT_FMP0, DISABLE);
}
上面驱动程序只是一个简单的示例来接收can的程序,其有以下缺点:
软件fifo接收数据。
CanRxMsg Can1RxMessage;
u8 can_fifo_index ;
u8 can_rx_fifo[1024];
u8 can1_data_flag ;
u8 can1_broadcast_flag ;
void CAN1_RX0_IRQHandler(void)
{
if(CAN_GetFlagstatus(CAN1,CAN_FLAG_FOV0))
printf("OVER CAN\r\n");
u8 fifo_count;/* 3 hardware fifo for can rx */
for(fifo_count=0; fifo_count<3; fifo_count++)
{
if(CAN_GetFlagstatus(CAN1,CAN_FLAG_FMPO))
{
/*receive a can data*/
if(can_fifo_index >= CAN_RX_FIFO_MAX_SIZE) /*1024*/
{
printf("over 1k \r\n");
CAN_ITConfig(CAN1, CAN_IT_FMPO, DISABLE);
break;
}
else
{
CAN Receive(CAN1, CAN FIFO, &Can1RxMessage);
memcpy(&can_rx_fifo[can_fifo_index], (u8 *)8Can1RxMessage.Data[0], Can1RxMessage.DLC);
can_fifo_index += Can1RxMessage.DLC;
CAN_FIFORelease(CAN1,CAN_FIFOO);
}
can1_data_flag = TRUE;
/*check if is broadcast data */
if(CAN_BROADCAST_CMD == Can1RxMessage.ExtId)
can1_broadcast_flag = TRUE;
else
can1_broadcast_flag = FALSE:
}
else
break;
}
}
以上代码也只是demo,相应的错误处理没有增加,在溢出时,只是增加了打印,比如可以增加标志位,然后将其传递出去。