打印
[技术问答]

CAN硬件过滤通道设置方法

[复制链接]
24390|102
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 JasonLee27 于 2019-12-3 13:46 编辑

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

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


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

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

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

除了ID匹配之外,mask的高3个bit还用于扩展帧和标准帧的检查。

这里bit5,6对应的是mask的bit29,bit30。可以通过这两个bit选择是否只接收标准帧或者扩展帧。

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

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




使用特权

评论回复
评论
YAO目录 2024-2-26 09:35 回复TA
感谢分享,学习学习 

相关帖子

沙发
梦想| | 2019-12-3 14:38 | 只看该作者
好贴

使用特权

评论回复
板凳
TechHolder| | 2019-12-3 15:55 | 只看该作者
好贴

使用特权

评论回复
地板
RunningX| | 2019-12-3 16:46 | 只看该作者
学习学习

使用特权

评论回复
5
心口上的朱砂痣| | 2019-12-3 17:46 | 只看该作者
感谢 分享 多多学习

使用特权

评论回复
6
craneinsky| | 2019-12-11 17:25 | 只看该作者

使用特权

评论回复
7
sackfc| | 2020-1-2 22:07 | 只看该作者
好贴

使用特权

评论回复
8
wangbo411326| | 2020-6-23 14:07 | 只看该作者
真的好帖子

使用特权

评论回复
9
zfczfc0| | 2020-6-29 11:04 | 只看该作者
学习了,好贴

使用特权

评论回复
10
zxdesh| | 2020-6-30 18:16 | 只看该作者
学习了!!!

使用特权

评论回复
11
love辉| | 2020-7-3 16:54 | 只看该作者
学习了

使用特权

评论回复
12
540035759| | 2020-8-21 16:16 | 只看该作者
看看

使用特权

评论回复
13
jazzyfox| | 2020-9-22 16:48 | 只看该作者
学习一下

使用特权

评论回复
14
oula| | 2020-9-22 17:37 | 只看该作者
学习了

使用特权

评论回复
15
ailliam| | 2020-9-26 10:11 | 只看该作者
ok

使用特权

评论回复
16
欢乐家园| | 2020-9-28 23:49 | 只看该作者
对于任何一个ID,只要满足你使能的任何一个硬件通道要求,就可以被接收。

使用特权

评论回复
17
chenjun89| | 2020-10-5 19:29 | 只看该作者
感谢楼主分享

使用特权

评论回复
18
weifeng90| | 2020-10-5 21:07 | 只看该作者
谢谢分享

使用特权

评论回复
19
看别人照片| | 2020-10-10 10:12 | 只看该作者
我看很多人都不太了解CAN的硬件过滤机制以及设置方法,这里专门拿出来讲一下,其实芯片虽然不同,但过滤的原理都是大同小异,都是通过设置过滤ID以及ID掩码来选择接收的ID。

使用特权

评论回复
20
wf663776| | 2020-10-20 23:12 | 只看该作者

学习一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

66

主题

415

帖子

10

粉丝