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

[复制链接]
2584|69
 楼主| l63t89 发表于 2022-4-30 19:46 | 显示全部楼层
从上图对比扩展CAN报文与标准CAN报文,发现在仲裁域部分,扩展CAN报文的CAN ID包含了base Identifier与extension Identifier,即基本ID与扩展ID,而标准CAN报文的CAN ID部分只包含基本ID,扩展ID(ID0~ID17)被放在基本ID的右方,也就是说,属于低位。知道这些有什么用呢?至少我们可以得到这两条信息:
 楼主| l63t89 发表于 2022-4-30 19:52 | 显示全部楼层
标准ID一般小于或等于<=0x7FF(11位),只包含基本ID。
对于扩展CAN的低18位为扩展ID,高11位为基本ID。
 楼主| l63t89 发表于 2022-4-30 19:53 | 显示全部楼层
例如标准CAN ID 0x7E1,二进制展开为0b 0[111 1110 0001] ,只有中括号内的11位才有效,其全部是基本ID。
 楼主| l63t89 发表于 2022-4-30 19:54 | 显示全部楼层
再例如扩展CAN ID 0x1835f107,二进制展开为0b 000[1 1000 0011 10][01 11110001 0000 0111],只有红色中括号和绿色中括号内的位才有效,总共29位,左边红色中括号中的11位为基本ID,右边绿色中括号内的18位为扩展ID,请记住这个信息!知道这个之后,我们可以很方便地将一个CANID拆分成基本ID和扩展ID,这个也将在后续的内容中多次用到,再次留意一下,扩展ID是位于基本ID的右方,在扩展CAN ID的构成中,扩展ID位于低18位,而基本ID位于高11位,于是要获取一个扩展CANID的基本ID,就只需要将这个CANID右移18位(这种算法后续将多次用到,请务必记住!)。
 楼主| l63t89 发表于 2022-4-30 19:55 | 显示全部楼层
3. bxCAN的过滤器的解决方案
终于进入到正题了!前面已经介绍了过滤器的列表模式与掩码模式,以及掩码模式下的屏蔽码与验证码的含义,还介绍了标准CAN ID与扩展CAN ID的组成部分。现在我们终于要站在bxCAN的角度来分析其过滤方案。
 楼主| l63t89 发表于 2022-4-30 19:55 | 显示全部楼层
首先过滤模式分列表模式和掩码模式,因此,对于没有过滤器,我们需要这么一个位来标记,用户可以通过设置这个位来标记他到底是想要这个过滤器工作在列表模式下还是掩码模式,于是,这个表示过滤模式的位就定义在CAN_FM1R寄存器中的FBMx位上,如下图:
94660626d23ac1b253.png
图5 CAN过滤器模式寄存器CAN_FM1R定义

 楼主| l63t89 发表于 2022-4-30 19:57 | 显示全部楼层
这里以STM32F407为例,bxCAN共有28个过滤器,于是上图的每一个位对应地表示这28个过滤器的工作模式,供用户设置。”0”表示掩码模式,”1”表示列表模式。
 楼主| l63t89 发表于 2022-4-30 19:57 | 显示全部楼层
另外,我们知道了标准CAN ID位11位,而扩展CAN ID有29位,对于标准的CAN ID来说,我们有一个16位的寄存器来处理他足够了,相应地,扩展CAN ID,我们就必须使用32位的寄存器来处理它,而在实际应用中,根据需求,我们可能自始至终都只需要处理11位的CAN ID。对于资源严重紧张的MCU环境来说,本着不浪费的原则,这里最好能有另外一个标志用告诉过滤器是否需要处理32位的CAN ID。于是,bxCAN处于这种考虑,也设置了这么一个寄存器CAN_FS1R来表示CAN ID的位宽,如下图所示:
89056626d2423ea181.png
 楼主| l63t89 发表于 2022-4-30 19:58 | 显示全部楼层
如上图,每一个位对应着bxCAN中28个过滤器的位宽,这个需要用户来设置。

于是根据模式与位宽的设置,我们共可以得出4中不同的组合:32位宽的列表模式,16位宽的列表模式,32位宽掩码模式,16位宽的掩码模式。
 楼主| l63t89 发表于 2022-4-30 20:00 | 显示全部楼层
如下图所示:
49631626d24c342581.png
 楼主| l63t89 发表于 2022-4-30 20:02 | 显示全部楼层
在bxCAN中,每个过滤器都存在这么两个寄存器CAN_FxR1和CAN_FxR2,这两个寄存器都是32位的,他的定义并不是固定的,针对不同的工作模式组合他的定义是不一样的,如列表模式-32位宽模式下,这两个寄存器的各位定义都是一样的,都用来存储某个具体的期望通过的CAN ID,这样就可以存入2个期望通过的CAN ID(标准CAN ID和扩展CAN ID均可);若在掩码模式-32位宽模式下时,则CAN_FxR1用做32位宽的验证码,而CAN_FxR2则用作32位宽的屏蔽码。在16位宽时,CAN_FxR1和CAN_FxR2都要各自拆分成两个16位宽的寄存器来使用,在列表模式-16位宽模式下,CAN_FxR1和CAN_FxR2定义一样,且各自拆成两个,则总共可以写入4个标准CAN ID,若在16位宽的掩码模式下,则可以当做2对验证码+屏蔽码组合来用,但它只能对标准CAN ID进行过滤。这个就是bxCAN过滤器的解决方案,它采用了这4种工作模式。
 楼主| l63t89 发表于 2022-4-30 20:04 | 显示全部楼层
本着从易到难得目的,下面我们将依次介绍如何使用bxCAN的这4种工作模式并给出对应的代码示例.
 楼主| l63t89 发表于 2022-4-30 20:06 | 显示全部楼层
4. 应用实例
4.1.   工程建立及主体代码
本文硬件采用STM3240G-EVAL评估板和ZLG的USBCAN-2E-U及其配套的软件工具CANTest来实现对MCU进行CAN报文的发送。工程使用STM32CubeMx自动生成:

 楼主| 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. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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