[应用相关] 谈STM32的CAN过滤器

[复制链接]
2587|69
 楼主| l63t89 发表于 2022-4-30 20:06 | 显示全部楼层
引脚如下:

PD0: CAN1_Rx

PD1: CAN1_Tx

PG6: LED1

PG8: LED2

PI9:  LED3

PC7: LED4

61646626d2651cf596.png
 楼主| l63t89 发表于 2022-4-30 20:07 | 显示全部楼层
时钟树如下设置:
90496626d26897b47c.png
 楼主| l63t89 发表于 2022-4-30 20:08 | 显示全部楼层
在配置中的NVIC中,打开CAN1 RX0接收中断,如下图所示:
 楼主| l63t89 发表于 2022-4-30 20:11 | 显示全部楼层
 楼主| l63t89 发表于 2022-4-30 20:14 | 显示全部楼层
其他的没有什么特殊设置,生成工程后的main函数如下:
  1. int main(void)
  2. {

  3.   /* USER CODE BEGIN 1 */
  4.   static CanTxMsgTypeDef        TxMessage;
  5.   static CanRxMsgTypeDef        RxMessage;
  6.   /* USER CODE END 1 */

  7.   /* MCU Configuration----------------------------------------------------------*/

  8.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  9.   HAL_Init();

  10.   /* Configure the system clock */
  11.   SystemClock_Config();

  12.   /* Initialize all configured peripherals */
  13.   MX_GPIO_Init();
  14.   MX_CAN1_Init();

  15.   /* USER CODE BEGIN 2 */
  16.   hcan1.pTxMsg =&TxMessage;
  17.   hcan1.pRxMsg =&RxMessage;
  18.   CANFilterConfig_Scale32_IdList();                        //列表模式-32位宽
  19. //CANFilterConfig_Scale16_IdList();                        //列表模式-16位宽
  20. //CANFilterConfig_Scale32_IdMask_StandardIdOnly();        //掩码模式-32位宽(只有标准CAN ID)
  21. //CANFilterConfig_Scale32_IdMask_ExtendIdOnly();        //掩码模式-32位宽(只用扩展CAN ID)
  22. //CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix(); //掩码模式-32位宽(标准CANID与扩展CAN ID混合)
  23. //CANFilterConfig_Scale16_IdMask();                        //掩码模式-16位宽
  24.   HAL_CAN_Receive_IT(&hcan1,CAN_FIFO0);
  25.   /* USER CODE END 2 */

  26.   /* Infinite loop */
  27.   /* USER CODE BEGIN WHILE */
  28.   while (1)
  29.   {
  30.   /* USER CODE END WHILE */

  31.   /* USER CODE BEGIN 3 */
  32.   }
  33.   /* USER CODE END 3 */

  34. }
 楼主| l63t89 发表于 2022-4-30 20:16 | 显示全部楼层
如上代码所示,示例中将采用各种过滤器配置来演示,在测试时我们可以只保留一种配置,也可以全部打开,为了确保每种配置的准确性,这里建议只保留其中一种配置进行测试。
 楼主| l63t89 发表于 2022-4-30 20:18 | 显示全部楼层
另外,接收中断回调函数如下所示:
  1. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)
  2. {
  3.   if(hcan->pRxMsg->StdId ==0x321)
  4.   {
  5.     //handle the CAN message
  6.     HandleCANMessage(hcan->pRxMsg);                //处理接收到的CAN报文
  7.   }
  8.   if(hcan->pRxMsg->ExtId ==0x1800f001)
  9.   {
  10.      HandleCANMessage(hcan->pRxMsg);                //处理接收到的CAN报文
  11.   }
  12.   HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,GPIO_PIN_SET);    //若收到消息则闪烁下LED4
  13.   HAL_Delay(200);
  14.   HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,GPIO_PIN_RESET);  
  15.   HAL_CAN_Receive_IT(&hcan1,CAN_FIFO0);
  16. }
 楼主| l63t89 发表于 2022-4-30 21:40 | 显示全部楼层
接下来将分别介绍过滤器的4中工作模式以及所对应的代码示例。
 楼主| l63t89 发表于 2022-4-30 21:40 | 显示全部楼层
4.2.   32位宽的列表模式
48392626d3c57e56fa.png
 楼主| l63t89 发表于 2022-4-30 22:14 | 显示全部楼层
如上图所示,在32位宽的列表模式下,CAN_FxR1与CAN_FxR2都用来存储希望通过的CAN ID,由于是32位宽的,因此既可以存储标准CAN ID,也可以存储扩展CAN ID。注意看上图最底下的各位定义,可以看出,从右到左,首先,最低位是没有用的,然后是RTR,表示是否为远程帧,接着IDE,扩展帧标志,然后才是EXID[0:17]这18位扩展ID,最后才是STID[0:10]这11位标准ID,也就是前面所说的基本ID。在进行配置的时候,即将希望通过的CAN ID写入的时候,要注意各个位对号入座,即基本ID放到对应的STD[0:10],扩展ID对应放到EXID[0:17],若是扩展帧,则需要将IDE设为“1”,标准帧则为“0”,数据帧设RTR为“0”,远程帧设RTR为“1”。、
 楼主| l63t89 发表于 2022-4-30 22:14 | 显示全部楼层
示例代码如下:

  1. static void CANFilterConfig_Scale32_IdList(void)
  2. {
  3.   CAN_FilterConfTypeDef  sFilterConfig;
  4.   uint32_t StdId =0x321;                                //这里写入两个CAN ID,一个位标准CAN ID
  5.   uint32_t ExtId =0x1800f001;                        //一个位扩展CAN ID
  6.   
  7.   sFilterConfig.FilterNumber = 0;                                //使用过滤器0
  8.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;                //设为列表模式
  9.   sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;        //配置为32位宽
  10.   sFilterConfig.FilterIdHigh = StdId<<5;                        //基本ID放入到STID中
  11.   sFilterConfig.FilterIdLow = 0|CAN_ID_STD;                        //设置IDE位为0
  12.   sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff;
  13.   sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT;        //设置IDE位为1
  14.   sFilterConfig.FilterFIFOAssignment = 0;                        //接收到的报文放入到FIFO0中
  15.   sFilterConfig.FilterActivation = ENABLE;
  16.   sFilterConfig.BankNumber = 14;
  17.   
  18.   if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  19.   {
  20.     Error_Handler();
  21.   }
  22. }
 楼主| l63t89 发表于 2022-4-30 22:15 | 显示全部楼层
这里需要说明一下,由于我们使用的是cube库,在cube库中,CAN_FxR1与CAN_FxR2寄存器分别被拆成两段,CAN_FxR1寄存器的高16位对应着上面代码中的FilterIdHigh,低16位对应着FilterIdLow,而CAN_FxR2寄存器的高16位对应着FilterMaskIdHigh,低16位对应着FilterMaskIdLow,这个CAN_FilterConfTypeDef的的4个成员FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow,不应该单纯看其名字,被其名字误导,而应该就单纯地将这4个成员看成4个uint_16类型的变量x,y,m,n而已,后续其他示例也是同样理解,不再重复解释。这4个16位的变量其具体含义取决于当前过滤器工作与何种模式,比如当前32位宽的列表模式下,FilterIdHigh与FilterIdLow一起用来存放一个CAN ID,FilterMaskIdHigh与FilterMaskIdLow用来存放另一个CAN ID,不再表示其字面所示的mask含义,这点我们需要特别注意。
 楼主| l63t89 发表于 2022-4-30 22:16 | 显示全部楼层
在上述代码示例中,我们分别将标准CAN ID和扩展CAN ID放入到CAN_FxR1与CAN_FxR2寄存器中。对于标准CAN ID,对比 图11,由于标准CAN ID只拥有标准ID,所以,只需要将标准ID放入到高16位的STID[0:10]中,高16位最右边被EXID[13:17]占着,因此,需要将StdId左移5位才能刚好放入到CAN_FxR1的高16位中,于是有了:
  1. sFilterConfig.FilterIdHigh = StdId<<5;
 楼主| l63t89 发表于 2022-4-30 22:18 | 显示全部楼层
另一个扩展CAN ID ExtId类型,将其基本ID放入到STID中,扩展ID放入到EXID中,最后设置IDE位为1。就这样配置好了。
19608626d454409bca.png
 楼主| l63t89 发表于 2022-4-30 22:19 | 显示全部楼层
如上图所示,在16位宽的列表模式下,FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow这4个16位变量都是用来存储一个标准CAN ID,这样,就可以存放4个标准CAN ID了,需要注意地是,此种模式下,是不能处理扩展CANID,凡是需要过滤扩展CAN ID的,都是需要用到32位宽的模式。
 楼主| l63t89 发表于 2022-4-30 23:39 | 显示全部楼层
于是有以下代码示例:
  1. static void CANFilterConfig_Scale16_IdList(void)
  2. {
  3.   CAN_FilterConfTypeDef  sFilterConfig;
  4.   uint32_t StdId1 =0x123;                                                //这里采用4个标准CAN ID作为例子
  5.   uint32_t StdId2 =0x124;
  6.   uint32_t StdId3 =0x125;
  7.   uint32_t StdId4 =0x126;
  8.   
  9.   sFilterConfig.FilterNumber = 1;                                //使用过滤器1
  10.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;                //设为列表模式
  11.   sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;        //位宽设置为16位
  12.   sFilterConfig.FilterIdHigh = StdId1<<5;         //4个标准CAN ID分别放入到4个存储中
  13.   sFilterConfig.FilterIdLow = StdId2<<5;
  14.   sFilterConfig.FilterMaskIdHigh = StdId3<<5;
  15.   sFilterConfig.FilterMaskIdLow = StdId4<<5;
  16.   sFilterConfig.FilterFIFOAssignment = 0;                        //接收到的报文放入到FIFO0中
  17.   sFilterConfig.FilterActivation = ENABLE;
  18.   sFilterConfig.BankNumber = 14;
  19.   
  20.   if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  21.   {
  22.     Error_Handler();
  23.   }
  24. }
kiwis66 发表于 2022-5-5 09:33 | 显示全部楼层
一直没用过这功能,学习了
Uriah 发表于 2022-10-7 08:07 | 显示全部楼层

需要在做项目的过程中经历磨难
Bblythe 发表于 2022-10-7 11:06 | 显示全部楼层

结构化模块化的程序设计的思想,使最基本的要求
Pulitzer 发表于 2022-10-7 14:05 | 显示全部楼层

写程序不难,但是程序怎么样才能写的好,写的快,那是需要点经验积累的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部