一、简介

在 CAN 协议中,消息的标识符与节点地址无关,但与消息内容有关。因此,发送器将消息广播给所有接收器。在接收到消息时,接收器节点会根据标识符的值来确定软件是否需要该消息。如果需要,该消息将复制到 SRAM 中。如果不需要,则必须在无软件干预的情况下丢弃该消息。

二、详细各概念

2.1 筛选器组

bxCAN 控制器为应用程序提供了 28 个可配置且可调整的筛选器组 (CAN1和CAN2分享28个过滤器组27-0)。在互联型产品中,bxCAN 控制器为应用程序提供了 14 个可配置且可调整的筛选器组 (13-0),以便仅接收软件需要的消息。此硬件筛选功能可以节省软件筛选所需的 CPU 资源。每个筛选器组 x 均包含两个 32 位寄存器,分别是 CAN_FxR0 和 CAN_FxR1。

sFilterConfig.BankNumber = n;

此句代码针对双CAN的STM32产品,配置CAN2可使用的过滤器组的起始编号,n取值范围为0~28。从编号为n的过滤器组到编号为27的过滤器组分配给CAN2使用。如果此句配置不在代码中明确写出来,默认值就是14. 即硬件默认将编号为14起往后的过滤器组分配给CAN2使用。

(配置为32位模式则一个屏蔽要占用两个过滤器组,如下图231)

2.2 过滤器的过滤模式

STM32提供两种过滤模式供用户设置:屏蔽位模式和标识符列表模式。

2.2.1 屏蔽位模式

为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。
在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。

2.2.2 标识符列表模式

为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。
在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。

2.3 过滤器的位宽

每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
        ●1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
        ●2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

2.4 过滤器组的过滤模式和位宽设置

过滤器组可以通过相应的CAN_FMR寄存器(CAN过滤器主控寄存器)配置。但是不是什么时候都可以直接配置,在配置一个过滤器组前,必须通过清除CAN_FAR寄存器(CAN过滤器激活寄存器)的FACT位,把它设置为禁用状态。然后才能设置或设置过滤器组的配置。

通过设置CAN_FS1R(CAN过滤器位宽寄存器)的相应FSCx位,可以配置一个过滤器组的位宽。
通过CAN_FM1R(CAN过滤器模式寄存器)的FBMx位,可以配置对应的屏蔽/标识符寄存器的标识符列表模式或屏蔽位模式。

上图对应四种模式设置寄存器各位的内容。

2.5 过滤器匹配序号

根据过滤器优先级规则,过滤器匹配序号和报文一起,被存入邮箱中。因此每个收到的报文,都有与它相关联的过滤器匹配序号。

过滤器匹配序号可以通过下面两种方式来使用:
             ● 把过滤器匹配序号跟一系列所期望的值进行比较
             ● 把过滤器匹配序号当作一个索引来访问目标地址
            对于标识符列表模式下的过滤器(非屏蔽方式的过滤器),软件不需要直接跟标识符进行比较。
            对于屏蔽位模式下的过滤器,软件只须对需要的那些屏蔽位(必须匹配的位)进行比较即可。
在给过滤器编号时,并不考虑过滤器组是否为激活状态。另外,每个FIFO各自对其关联的过滤器进行编号,如下图(此图暂时未能理解):

2.6 过滤器优先级规则

根据过滤器的不同配置,有可能一个报文标识符能通过多个过滤器的过滤;在这种情况下,存放在接收邮箱中的过滤器匹配序号,根据下列优先级规则来确定:
● 位宽为32位的过滤器,优先级高于位宽为16位的过滤器
● 对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式
● 位宽和模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级高

如下图:

如上图,在接收一个报文时,其标识符首先与配置在标识符列表模式下的过滤器相比较;如果匹配上,报文就被存放到相关联的FIFO中,并且所匹配的过滤器的序号(这时为4)被存入过滤器匹配序号中。如同例子中所显示,报文标识符跟#4标识符匹配,因此报文内容和FMI4被存入FIFO。

如果没有匹配,报文标识符接着与配置在屏蔽位模式下的过滤器进行比较。
              如果报文标识符没有跟过滤器中的任何标识符相匹配,那么硬件就丢弃该报文,且不会对软件有任何打扰。

三、实测代码

CAN ID值的结构分析(非常重要)

ISO11898的定义,如下图:

如上图,基本格式不存在扩展ID,而扩展格式中ID0~ID17为Extension ID,而ID18~ID28为Base ID.

因此CAN ID值0x1800f001用二进制表示为:0b 0001 1000 0000 0000 1111 0000 0000 0001,用括号分别区别为:0b 000[1 1000 0000 00][00 1111 0000 0000 0001],红色部分为扩展ID,蓝色部分为基本ID。

举例:0x35e    二进制:0000 0011 0101 1110     需要左移两位与上图基本ID位对齐,还需左移三位与下图寄存器位对齐。

扩展ID0x0187  相对简单,本身与上图扩展ID位对齐,只需要左移三位即可与下面寄存器位对齐。(自己理解了好久,唉)

位宽为32位的屏蔽模式

两个过滤器,分别过滤两类ID。(实际项目使用)

u16 std_id   =0x0350;//后四位不比较,即0x350~0x35f
u16 std_id_f =0x035F;
u32 ext_id   =0x00001870;//同上
u32 ext_id_f =0x0000187F;
u32 mask =0;
//配置过滤器0
CAN_FilterInitStructure.CAN_FilterNumber=0;      //过滤器0  0-13
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;  //屏蔽模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32ID//扩展ID屏蔽
//ext_id<<3对齐,见上图9,再>>16取高16位
CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff;
CAN_FilterInitStructure.CAN_FilterIdLow=(u16)(ext_id<<3) | CAN_ID_EXT;
mask  = ext_id;
mask ^= ext_id_f;
mask  = ~mask;
mask <<=3;
mask |=0x02; //只接受数据帧
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;//关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能
CAN_FilterInit(&CAN_FilterInitStructure);//配置CAN_FilterInitStructure.CAN_FilterNumber=1;     //过滤器1
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32ID
//基本ID屏蔽
//设置标识符寄存器高字节.这里为什么是左移5位呢?从上图可以看出,CAN_FilterIdHigh包含的是STD[0~10]和EXID[13~17],标准CAN ID本身是不包含扩展ID数据,因此为了要将标准CAN ID放入此寄存器,标准CAN ID首先应左移5位后才能对齐.
CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5;
CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_Id_Standard;
mask  = std_id<<5;
mask ^= std_id_f<<5;
mask  = ~mask;
mask |=0x02; //只接受数据帧
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = mask ;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能
CAN_FilterInit(&CAN_FilterInitStructure);//配置

一个过滤器筛选出一个标准ID,一个扩展ID。(网上)

CAN_FilterInitTypeDef  CAN_FilterInitStructure;
U16 std_id =0x7e9;
U32 ext_id =0x1800f001;
CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量
CAN_FilterInitStructure.CAN_FilterNumber=0;     //设置过滤器组0,范围为0~13
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;    //设置过滤器组0为标识符列表模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位//设置屏蔽寄存器,这里当标识符寄存器用
CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ;  //为什么左移5位?与上面相同道理,这里不再重复解释
CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。//设置标识符寄存器
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节
CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器

位宽为16位的屏蔽码模式

在此模式下,最多存在两个屏蔽码过滤器,如下图:

由上图映射可知,最下面的映射只包含STDID0~ID10,因此,此模式下的两个屏蔽过滤器只能实现对标准ID的过滤。具体代码就不介绍了,参见上图的映射即可。

位宽为16位的标识符列表模式

在此模式下,由于标识符寄存器的高16位和低16位,屏蔽寄存器的高16位和低16位都用来做标识符寄存器,因此,最多可存在4个标识符过滤器。同样,只能实现对标准帧的过滤。具体代码就不介绍了,参见上图的映射即可。
(部分参考https://blog.csdn.net/flydream0/article/details/8148791)

STM32 CAN通讯过滤器使用总结及代码分析相关推荐

  1. 【STM32】按键检测实验主要程序代码分析

    文章目录 main.c key.c key.h main.c #include "led.h" #include "delay.h" #include &quo ...

  2. 【STM32】跑马灯实验主要程序代码分析

    文章目录 main.c led.c led.h STM32 的 IO 口可以由软件配置成如下 8 种模式: 输入浮空 输入上拉 输入下拉 模拟输入 开漏输出 推挽输出 推挽式复用功能 开漏复用功能 S ...

  3. 安卓设备通过USB串口与STM32单片机通讯之二

    安卓设备通过USB串口与STM32单片机通讯之二 本博文系JGB联合商务组的原创作品,引用请标明出处. 本博文接续上一篇的末尾章节. (二) APP的JAVA代码部分(使用Android Studio ...

  4. K210学习笔记(五)——MAIX BIT(K210)与STM32串口通讯

    前言 uart 模块主要用于驱动开发板上的异步串口,可以自由对 uart 进行配置.k210 一共有3个 uart,每个 uart 可以进行自由的引脚映射. 一.MAIX BIT串口使用步骤 1.引脚 ...

  5. 作业—STM32串口通讯

    STM32串口通信 一.基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异 二.STM32的USART窗口通讯程序 1.烧录代码 2.代码 3.效果图 三.c语言程序里全局变量. ...

  6. STM32 —— 串口通讯

    STM32 -- 串口通讯 什么是串口通讯 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层 ...

  7. stm32串口通讯问题

    stm32串口通讯问题 在串口试验中,串口通讯不正常,则可能会出现以下问题: 1. 配置完成后,串口没有任何消息打印. 原因:1,端口配置有问题,需要重新检查I/O口的配置 2,接线有问题,检查接线是 ...

  8. HAL库版STM32双轮自平衡车(三) ———代码精讲

    系列文章目录 编码电机测速 HAL库OLED的使用 HAL库版STM32双轮自平衡车(一) ---代码思路和PID基础精讲 HAL库版STM32双轮自平衡车(二) --- CubeMX的配置.原理图接 ...

  9. HAL库版STM32双轮自平衡车(一) ———代码思路和PID基础精讲

    系列文章目录 HAL库版STM32双轮自平衡车(一) ---代码思路和PID的简单介绍(本篇) HAL库版STM32双轮自平衡车(二) --- CubeMX的配置.原理图接线.物料准备 HAL库版ST ...

  10. 【stm32】如何把原子哥的代码移植到最小系统板stm32f103c8t6 以跑马灯实验为例

    [stm32]如何把原子哥的代码移植到最小系统板stm32f103c8t6 以跑马灯实验为例 外部硬件: stm32仿真编程器 (仿真编制器自己在网上买,不确定买哪个的可以就买我这个,图片上有牌子,自 ...

最新文章

  1. csdn新版博客初体验
  2. 用Javascript隐藏超级链接的真实地址
  3. Yii的数值唯一性-场景与SQL
  4. php5.4以下,json_encode不转义实现方法
  5. 投资学习网课笔记(part1)--基金第一课
  6. 拿 C# 搞函数式编程
  7. jvm高级特性第4章-虚拟机性能监控与故障处理工具
  8. git 上下载的项目在本地安装依赖时报错 Could not resolve dependency
  9. 【Java】Java 线程池 8 大拒绝策略
  10. 深度剖析WinPcap之(四)——WinPcap的体系架构(2)
  11. LINUX获得线程号、设置线程名
  12. pc端+移动端电商源码
  13. 华为云计算ie学习一IA部分(1)
  14. DongTai--被动型IAST工具部署体验
  15. win10教育版加域提示错误
  16. 页面交换文件pagefile.sys-虚拟内存页面文件
  17. s5p4418挂载nfs文件系统
  18. Java 数据结构-循序表
  19. gromacs 安装_gromacs编译安装教程
  20. java-小学期小小项目-通讯录管理系统

热门文章

  1. 中国人正在上的四个大当 看你到底上了几个了?
  2. HTML 音乐播放器界面
  3. 常见外贸英文术语(下)
  4. Linux 别名设置,可一键登入服务器- alias
  5. Failed to save persistent token
  6. JavaScript navigator对象
  7. 卡卡云模板(适配彩虹发卡系统)
  8. 学习笔记--数据通信与计算机网络
  9. QCOM chi-camera bring up
  10. 计算机等级保护 备案,信息安全等级保护备案实施细则