【HAL库】STM32F407----CAN通信----基本原理
【HAL库】STM32F407----CAN通信----电路图
【HAL库】STM32F407----CAN通信----中断详解
【HAL库】STM32CubeMX开发----STM32F407----CAN通信实验
在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时,根据标识符(CAN ID)的值决定软件是否需要该报文;如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。
为满足这一需求,bxCAN为应用程序提供了14个位宽可变的、可配置的过滤器组(13~0),以便只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。每个过滤器组x由2个32位寄存器,CAN_FxR0和CAN_FxR1组成。
STM32F407有两路CAN,所以有28个过滤器组,具体如下表:
CAN | 过滤器组 |
---|---|
CAN1 | 0 ~ 13 |
CAN2 | 14 ~ 27 |
在掩码模式下,标识符寄存器与掩码寄存器关联,用以指示标识符的哪些位必须匹配,哪些位无关。
传入标识符的所有位都必须与筛选器寄存器中指定的位匹配。
每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
消息接收到 FIFO 中后,即可供应用程序使用。
通常情况下,报文中的数据被拷贝到SRAM中;为了把数据拷贝到合适的位置,应用程序需要根据报文的标识符来辨别不同的数据。bxCAN提供了过滤器匹配序号,以简化这一辨别过程。
根据过滤器优先级规则,过滤器匹配序号和报文一起,被存入邮箱中。因此每个收到的报文,都有与它相关联的过滤器匹配序号。
过滤器匹配序号的使用方法有两种:
对于列表模式过滤器,软件不再需要比较标识符。
对于掩码模式过滤器,软件只须对需要的那些屏蔽位(必须匹配的位)进行比较即可。
筛选器编号与筛选器组的激活状态无关。此外,还将使用两个独立的编号方案,每个 FIFO 各一个。具体举例如下:
此图只是举例,具体配置不用按照此图。
根据过滤器的不同配置,有可能一个报文标识符能通过多个过滤器的过滤;在这种情况下,存放在接收邮箱中的过滤器匹配序号,根据下列优先级规则来确定:
过滤器组可以通过相应的CAN_FMR寄存器(CAN过滤器主控寄存器)配置。但是不是什么时候都可以直接配置,在配置一个过滤器组前,必须通过清除CAN_FAR寄存器(CAN过滤器激活寄存器)的FACT位,把它设置为禁用状态。然后才能设置或设置过滤器组的配置
以下是STM32F407----CAN过滤器----配置的具体实验内容和代码。
前期准备工作,请参考这篇文章:【HAL库】STM32CubeMX开发----STM32F407----CAN通信实验
实验内容: CAN通信波特率为 500K bps,将接收到的CAN_ID发送出来,发送帧ID为0x18888888,前4个字节数据为接收到的CAN_ID。
在STM32CubeMX生成【HAL库】程序中,没有关于过滤器相关的配置代码,如果不配置过滤器又无法接收数据,所以需要我们自己手写代码配置过滤器。
以下是 所有CAN帧ID都可以通过的过滤器 配置代码。
具体过滤器配置代码模板如下:
void CAN1_Filter_Bank(void)//过滤器
{
CAN_FilterTypeDef FilterConfig;
/*配置CAN过滤器*/
FilterConfig.FilterBank = 0; //过滤器组号
FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式:屏蔽位模式--CAN_FILTERMODE_IDMASK,列表模式--CAN_FILTERMODE_IDLIST
FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位
FilterConfig.FilterIdHigh = 0x0000; //32位ID
FilterConfig.FilterIdLow = 0x0000;
FilterConfig.FilterMaskIdHigh = 0x0000; //32位MASK
FilterConfig.FilterMaskIdLow = 0x0000;
FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
FilterConfig.FilterActivation = ENABLE; //激活滤波器0
FilterConfig.SlaveStartFilterBank = 14; //单CAN此参数无意义
//过滤器配置激活
if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
{
Error_Handler();
}
}
说明: 过滤器掩码模式:0不验证,1验证。所以屏蔽位都为0,就都不需要验证,所有CAN帧ID都可以接收了。
只有列表中存放的CAN_ID才可以被接收到。
在16位列表模式下,只能接收处理 标准帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放4个16位CAN_ID。
过滤器配置具体说明如下:
位 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
映射 | STID[10:0] | RTR | IDE | EXID[17:15]] | ||||||||||||
说明 | 11位标准帧CAN_ID | 帧类型: 0 数据帧 1 远程帧 |
标识符类型: 0 标准帧 1 扩展帧 |
无用数据 置0即可 |
||||||||||||
举例 | 0x101 | 0 | 0 | 0 | ||||||||||||
0x102 | 1 | 0 | 0 | |||||||||||||
0x103 | 0. | 0 | 0 | |||||||||||||
0x104 | 1 | 0 | 0 |
因为在16位列表模式下,只能接收处理 标准帧CAN_ID,所以IDE位都置0。
具体代码如下:
void CAN1_Filter_Bank(void)//过滤器、
{
//标准帧ID
uint16_t CanFilterListSTID0 = 0x101;
uint8_t CanFilterListRTR0 = 0x00; //帧类型:0x00数据帧,0x01远程帧
uint16_t CanFilterListSTID1 = 0x102;
uint8_t CanFilterListRTR1 = 0x01; //帧类型:0x00数据帧,0x01远程帧
uint16_t CanFilterListSTID2 = 0x103;
uint8_t CanFilterListRTR2 = 0x00; //帧类型:0x00数据帧,0x01远程帧
uint16_t CanFilterListSTID3 = 0x104;
uint8_t CanFilterListRTR3 = 0x01; //帧类型:0x00数据帧,0x01远程帧
CAN_FilterTypeDef FilterConfig;
/*配置CAN过滤器*/
FilterConfig.FilterBank = 0; //过滤器组号
FilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //过滤模式:列表模式--CAN_FILTERMODE_IDLIST
FilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //过滤器位宽:16位
FilterConfig.FilterIdHigh = (CanFilterListSTID0<<5)|(CanFilterListRTR0<<4); //ID
FilterConfig.FilterIdLow = (CanFilterListSTID1<<5)|(CanFilterListRTR1<<4);
FilterConfig.FilterMaskIdHigh = (CanFilterListSTID2<<5)|(CanFilterListRTR2<<4); //MASK
FilterConfig.FilterMaskIdLow = (CanFilterListSTID3<<5)|(CanFilterListRTR3<<4);
FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
FilterConfig.FilterActivation = ENABLE; //激活滤波器
FilterConfig.SlaveStartFilterBank = 14; //单CAN此参数无意义
//过滤器配置
if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
{
Error_Handler();
}
}
实验结果如下:
在32位列表模式下,可以接收处理 标准帧CAN_ID和 扩展帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放2个32位CAN_ID。
位 | 31 ~ 21 | 20 ~3 | 2 | 1 | 0 |
---|---|---|---|---|---|
映射 | STID[10:0] | EXID[17:0] | IDE | RTR | 0 |
说明 | 29位扩展帧CAN_ID | 标识符类型: 0 标准帧 1 扩展帧 |
帧类型: 0 数据帧 1 远程帧 |
0 | |
11位标准帧CAN_ID | 0 | ||||
举例 | 0x1B010F01 | 1 | 0 | 0 | |
0x701 | 0 | 0 | 1 | 0 |
具体代码如下:
void CAN1_Filter_Bank(void)//过滤器
{
//扩展帧ID
uint32_t CanFilterListEXID0 = 0x1B010F01;
uint8_t CanFilterListIDE0 = 0x01; //帧类型:0x00标准帧,0x01扩展帧
uint8_t CanFilterListRTR0 = 0x00; //帧类型:0x00数据帧,0x01远程帧
//标准帧ID
uint16_t CanFilterListSTID1 = 0x701;
uint8_t CanFilterListIDE1 = 0x00;//帧类型:0x00标准帧,0x01扩展帧
uint8_t CanFilterListRTR1 = 0x01;//帧类型:0x00数据帧,0x01远程帧
CAN_FilterTypeDef FilterConfig;
/*配置CAN过滤器*/
FilterConfig.FilterBank = 0; //过滤器组号
FilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //过滤模式:列表模式--CAN_FILTERMODE_IDLIST
FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位
FilterConfig.FilterIdHigh = (CanFilterListEXID0<<3)>>16; //ID
FilterConfig.FilterIdLow = (CanFilterListEXID0<<3)|(CanFilterListIDE0<<2)|(CanFilterListRTR0<<1);
FilterConfig.FilterMaskIdHigh = CanFilterListSTID1<<5; //MASK
FilterConfig.FilterMaskIdLow = (CanFilterListIDE1<<2)|(CanFilterListRTR1<<1);
FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
FilterConfig.FilterActivation = ENABLE; //激活滤波器
FilterConfig.SlaveStartFilterBank = 14; //单CAN此参数无意义
//过滤器配置
if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
{
Error_Handler();
}
}
实验结果如下:
由屏蔽码决定是否与验证CAN_ID哪几位做比较,只有与验证CAN_ID一致,才可以接收到。屏蔽码:0不验证,1验证。
掩码模式举例说明:
16进制 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|---|
屏蔽码 | 0xFC | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
验证码 | 0x79 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
可通过数据 | 0x78,0x79,0x7A,0x7B | 0 | 1 | 1 | 1 | 1 | 0 | x | x |
屏蔽码是1的位,必须与验证码一致才可通过。
屏蔽码是0的位,0和1皆可通过。
在16位掩码模式下,只能接收处理 标准帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放2个16位验证码和2个16位屏蔽码。
位 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
映射 | STID[10:0] | RTR | IDE | EXID[17:15]] | ||||||||||||
说明 | 11位标准帧CAN_ID | 帧类型: 0 数据帧 1 远程帧 |
标识符类型: 0 标准帧 1 扩展帧 |
无用数据 置0即可 |
||||||||||||
举例 | 屏蔽码0:0x7FC | 1 | 0 | 0 | ||||||||||||
验证码0:0x201 | 0 | 0 | 0 | |||||||||||||
可接收帧:0x200,0x201,0x202,0x203 只可接收数据帧 |
||||||||||||||||
屏蔽码1:0x7CF | 0 | 0 | 0 | |||||||||||||
验证码1:0x301 | 0 | 0 | 0 | |||||||||||||
可接收帧:0x301,0x311,0x321,0x331 可接收数据帧和远程帧 |
因为在16位列表模式下,只能接收处理 标准帧CAN_ID,所以IDE位都置0。
具体代码如下:
void CAN1_Filter_Bank(void)//过滤器
{
uint16_t CanFilterMaskSTID0 = 0x7FC;//屏蔽码:0不验证,1验证
uint8_t CanFilterMaskRTR0 = 0x01;//屏蔽码:0不验证,1验证
uint16_t CanFilterSTID0 = 0x201;
uint8_t CanFilterRTR0 = 0x00;//帧类型:0x00数据帧,0x01远程帧
uint16_t CanFilterMaskSTID1 = 0x7CF;//屏蔽码:0不验证,1验证
uint8_t CanFilterMaskRTR1 = 0x00;//屏蔽码:0不验证,1验证
uint16_t CanFilterSTID1 = 0x301;
uint8_t CanFilterRTR1 = 0x00;//帧类型:0x00数据帧,0x01远程帧
CAN_FilterTypeDef FilterConfig;
/*配置CAN过滤器*/
FilterConfig.FilterBank = 0; //过滤器组号
FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式:掩码模式--CAN_FILTERMODE_IDMASK
FilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //过滤器位宽:16位
FilterConfig.FilterIdHigh = (CanFilterSTID0<<5)|(CanFilterRTR0<<4); //ID
FilterConfig.FilterIdLow = (CanFilterSTID1<<5)|(CanFilterRTR1<<4);
FilterConfig.FilterMaskIdHigh = (CanFilterMaskSTID0<<5)|(CanFilterMaskRTR0<<4); //MASK
FilterConfig.FilterMaskIdLow = (CanFilterMaskSTID1<<5)|(CanFilterMaskRTR1<<4);
FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
FilterConfig.FilterActivation = ENABLE; //激活滤波器
FilterConfig.SlaveStartFilterBank = 14; //单CAN此参数无意义
//过滤器配置
if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
{
Error_Handler();
}
}
实验结果1如下:
可接收帧:0x200,0x201,0x202,0x203,只可接收数据帧。
实验结果2如下:
可接收帧:0x301,0x311,0x321,0x331,可接收数据帧和远程帧。
在32位列表模式下,可以接收处理 标准帧CAN_ID和 扩展帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放1个32位验证码和1个32位屏蔽码。
位 | 31 ~ 21 | 20 ~3 | 2 | 1 | 0 |
---|---|---|---|---|---|
映射 | STID[10:0] | EXID[17:0] | IDE | RTR | 0 |
说明 | 29位扩展帧CAN_ID | 标识符类型: 0 标准帧 1 扩展帧 |
帧类型: 0 数据帧 1 远程帧 |
0 | |
11位标准帧CAN_ID | 0 | ||||
举例 | 屏蔽码:0x1FFFFFFC | 1 | 1 | 0 | |
验证码:0x1B030F01 | 1 | 0 | 0 | ||
可接收帧:0x1B030F00,0x1B030F01,0x1B030F02,0x1B030F03 只可接收数据帧扩展帧 |
具体代码如下:
void CAN1_Filter_Bank(void)//过滤器
{
uint32_t CanFilterMaskEXID = 0x1FFFFFFC;//屏蔽码:0不验证,1验证
uint8_t CanFilterMaskIDE = 0x01;//屏蔽码:0不验证,1验证
uint8_t CanFilterMaskRTR = 0x01;//屏蔽码:0不验证,1验证
uint32_t CanFilterEXID = 0x1B030F01;
uint8_t CanFilterIDE= 0x01; //帧类型:0x00标准帧,0x01扩展帧
uint8_t CanFilterRTR= 0x00; //帧类型:0x00数据帧,0x01远程帧
CAN_FilterTypeDef FilterConfig;
/*配置CAN过滤器*/
FilterConfig.FilterBank = 0; //过滤器组号
FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式:掩码模式--CAN_FILTERMODE_IDMASK
FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位
FilterConfig.FilterIdHigh = (CanFilterEXID<<3)>>16; //ID
FilterConfig.FilterIdLow = (CanFilterEXID<<3)|(CanFilterIDE<<2)|(CanFilterRTR<<1);
FilterConfig.FilterMaskIdHigh = (CanFilterMaskEXID<<3)>>16; //MASK
FilterConfig.FilterMaskIdLow = (CanFilterMaskEXID<<3)|(CanFilterMaskIDE<<2)|(CanFilterMaskRTR<<1);
FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
FilterConfig.FilterActivation = ENABLE; //激活滤波器
FilterConfig.SlaveStartFilterBank = 14; //单CAN此参数无意义
//过滤器配置
if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
{
Error_Handler();
}
实验结果如下:
可接收帧:0x1B030F00,0x1B030F01,0x1B030F02,0x1B030F03,只可接收数据帧扩展帧。