[技术问答] CAN硬件过滤通道设置方法

[复制链接]
456|6
 楼主 | 2019-12-3 13:46 | 显示全部楼层 |阅读模式
本帖最后由 JasonLee27 于 2019-12-3 13:46 编辑

硬件环境: 通用开发板,ATC-LINK
软件环境:keil 5.23

我看很多人都不太了解CAN的硬件过滤机制以及设置方法,这里专门拿出来讲一下,其实芯片虽然不同,但过滤的原理都是大同小异,都是通过设置过滤ID以及ID掩码来选择接收的ID。


为了简单方便,我就直接用范例里面的CAN_sample来修改,首先把范例里面设置过滤的代码注释掉:
  1. #if 0
  2.         #if (RECV_FRM_KIND_SEL == ONLY_RECV_STD_FRM)
  3.         CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID1);//ʹÓÃCODEģʽֻ½ÓÊÕSTDÖ¡
  4.         CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID2);//ʹÓÃCODEģʽֻ½ÓÊÕSTDÖ¡
  5.         #endif
  6.         #if (RECV_FRM_KIND_SEL == ONLY_RECV_EXT_FRM)
  7.         CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID11);//ʹÓÃCODEģʽֻ½ÓÊÕEXTÖ¡
  8.         CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID12);//ʹÓÃCODEģʽֻ½ÓÊÕEXTÖ¡
  9.         #endif
  10.         #if (RECV_FRM_KIND_SEL == RECV_STD_EXT_BOTH_FRM)
  11.         CAN_SetFilterParam( 0, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID1 & CAN1_RECV_DATA_ID11));//ʹÓÃMASKģʽ½ÓÊÕÁ½ÖÖÖ¡
  12.         CAN_SetFilterParam( 1, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID2 & CAN1_RECV_DATA_ID12));//ʹÓÃMASKģʽ½ÓÊÕÁ½ÖÖÖ¡
  13.         #endif
  14. #else
  15.     ///自己的过滤代码
  16. #endif
复制代码
我们将通过直接赋值的方式,更加直观的了解硬件过滤的工作原理。
首先我们要找到用于设置过滤通道的tab变量 g_canFilterTab,硬件过滤通道总共有16个,所以这个tab数组也是16。
  1. typedef struct
  2. {
  3.     uint8_t index;                 ///< Filter index
  4.     uint8_t enable;                ///< Enable or disable
  5.     uint32_t code;                 ///< Code data
  6.     uint32_t mask;                 ///< Mask data
  7. } CAN_FilterControl;
复制代码
再看下这个tab的结构体,里面有4个成员,index表示对应的硬件通道号,从0~15顺序排列,enable表示对应的硬件通道是否使能。这里要注意,所有的报文接收都必须经过硬件过滤通道,所以,至少要打开一路硬件通道,否则就一个报文也收不到了,你可以测试一下再不使能任一通道的情况下,你用CAN盒发任何报文,芯片都无法接收,这些是论坛里之前有网友遇到过的问题,特此提出来。
那为什么代码直接不设置硬件过滤反而可以接收呢?
  1. int32_t CAN_Initialize(CAN_Type *CANx, CAN_Config *config, const CAN_BaudrateConfig *baudrate)
  2. {
  3.     uint8_t canIndex = GetCanIndex(CANx), i = 0;
  4.     CAN_FilterControl *filterList = (CAN_FilterControl *)&s_filterControl[0];
  5.     int32_t ret = ERROR_NO_EXCUTE;
复制代码
我们可以看到在can驱动代码里面,can初始化函数默认有一个过滤控制列表s_filterControl,如果你没有填入自己的过滤list,驱动就会用自己的list来初始化硬件通道。
  1. ///< Filter sample setting list, or user define
  2. static const CAN_FilterControl s_filterControl[CAN_MAX_FILTER_NUM] =
  3. {
  4.     {0, 1, 0x00000000, 0x1FFFFFFF},    // mask mode
  5.     {1, 0, 0x00000002, 0x00000000},    // code mode
  6.     {2, 0, 0x00000013, 0x00000000},
  7.     {3, 0, 0x00000124, 0x00000000},
  8.     {4, 0, 0x00000050, 0x1FFFFF0F},
  9.     {5, 0, 0x00000060, 0x1FFFFF0F},
  10.     {6, 0, 0x00000007, 0x1FFFFFF0},
  11.     {7, 0, 0x00000008, 0x1FFFFFF0},

  12.     {8, 0, 0x00000009, 0x5FFFFFF0},    // standard frames
  13.     {9, 0, 0x0000000a, 0x7FFFFFF0},    // extended frames
  14.     {10, 0, 0x00000700, 0x1FFFF0FF},   // Both
  15.     {11, 0, 0x0000c000, 0x7FFF0FFF},
  16.     {12, 0, 0x000d0000, 0x7FF0FFFF},
  17.     {13, 0, 0x00e00000, 0x7F0FFFFF},
  18.     {14, 0, 0x0f000000, 0x70FFFFFF},
  19.     {15, 0, 0x10000000, 0x6FFFFFFF},
  20. };
复制代码
可以看到这个list默认是使能了第一个通道的。实际上硬件复位也是默认启用0通道的。
接下来讲讲另外两个成员,code和mask;
code就是你要接收的ID,只有前29个bit是有效的。
mask就是你选择要检查的bit,1表示屏蔽检查,0表示匹配相应的bit。具体怎么理解呢,举两个例子,假如我只想接收ID=0x400的报文,那可以如下设置:
  1. #else
  2.     g_canFilterTab[0].enable = 1;  
  3.     g_canFilterTab[0].code = 0x400;
  4.     g_canFilterTab[0].mask = 0x0;
  5. #endif
复制代码
把这段代码烧写进去,会发现你用can盒发送别的ID报文,led2都不会闪烁(闪烁表示接收到报文),只有ID400的报文才可以被接收

但有时候我们并不是只想接收一个ID,而是一段ID,这个时候就要用mask屏蔽部分bit,例如,我想要接收0x400到0x4FF段的报文,其余报文都不接收:
  1. #else
  2.     g_canFilterTab[0].enable = 1;  
  3.     g_canFilterTab[0].code = 0x400;
  4.     g_canFilterTab[0].mask = 0x0;
  5.    
  6.     g_canFilterTab[1].enable = 1;  
  7.     g_canFilterTab[1].code = 0x400;
  8.     g_canFilterTab[1].mask = 0x000000FF;
  9. #endif
复制代码
我们把这个规则用于通道1,把这段代码烧进去测试,可以看到CAN盒只接收ID400~4FF的报文,这是因为mask最后8个bit设置为1,表示屏蔽最后8个bit的检查,也就是对接收到的ID的最后8个bit是不进行匹配检查的。

除了ID匹配之外,mask的高3个bit还用于扩展帧和标准帧的检查。
WeChat Screenshot_20191203134122.png
这里bit5,6对应的是mask的bit29,bit30。可以通过这两个bit选择是否只接收标准帧或者扩展帧。

另外:对于任何一个ID,只要满足你使能的任何一个硬件通道要求,就可以被接收。

代码回复后可见
游客,如果您要查看本帖隐藏内容请回复




使用特权

评论回复
| 2019-12-3 14:38 | 显示全部楼层
好贴

使用特权

评论回复
| 2019-12-3 15:55 | 显示全部楼层
好贴

使用特权

评论回复
| 2019-12-3 16:46 | 显示全部楼层
学习学习

使用特权

评论回复
| 2019-12-3 17:46 | 显示全部楼层
感谢 分享 多多学习

使用特权

评论回复
| 2019-12-11 17:25 | 显示全部楼层

使用特权

评论回复
| 2020-1-2 22:07 | 显示全部楼层
好贴

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

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