STM32 CAN 过滤器分析小结

发布者:BlissfulHeart最新更新时间:2017-09-25 来源: eefocus关键字:STM32  CAN  过滤器 手机看文章 扫描二维码
随时随地手机看文章

最近看了下STM32 CAN 通讯 其中标示符过滤器设置大有讲究。特别是你要使用ST库函数时,当过滤器工作在屏蔽模式下,并且你把屏蔽位设了1也就是标示符对应位必须全部匹配才能通过,这是由其要小心。


举个例子吧,过滤器长度为32位,模式为屏蔽模式,假如我要发送的标示符为0x1314;那过滤器设置如下

一、过滤器完全无效 接收到的标示符全部通过

   0x1314 二进制码: 0000 0000 0000 0000 0001 0011 0001 0100 

   CAN_Filter        xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 

   CAN_FilterMask    0000 0000 0000 0000 0000 0000 0000 0000

因为 CAN_FilterMask屏蔽寄存器所有位都是0 ,对应标示符全为“不关心”,也就是接收到数据的ID(标示符)不用与 CAN_Filter寄存器的任何一位进行匹配。 

二、过滤器完全有效 接收到的标示符要跟据MASK 寄存器指定需要匹配的位进行比较 

  部分匹配

   0x1314 二进制码: 0000 0000 0000 0000 0001 0011 0001 0100 

   CAN_Filter        xxxx xxxx xxxx xxxx xxxx xxx1 xxxx xxxx 

   CAN_FilterMask    0000 0000 0000 0000 0000 0001 0000 0000

CAN_FilterMask 寄存器指定接收到的标示符要与第8位进行匹配,其他位不管。也就是说接收到的标示符第8位必须为1,否则报文就会被丢弃。

  全部匹配

   0x1314 二进制码: 0000 0000 0000 0000 0001 0011 0001 0100 

   CAN_Filter        0000 0000 0000 0000 0000 0011 0001 0100 

   CAN_FilterMask    1111 1111 1111 1111 1111 1111 1111 1111

这种情况最为严格,接收到的标示符必须每一位都得与过滤器中的标示符的每一位进行匹配,有一位不对报文就会被丢弃。(这个标示符匹配的工作是CAN 模块内部硬件自动完成的)

三、利用ST库进行CAN 过滤器的配置

  同样发送端和接收端数据标示符都为0x1314

第一种:过滤器无效,全部通过

  static void CAN_Filter_Config(void)
{
   CAN_FilterInitTypeDef  CAN_FilterInitStructure;

 
 CAN_FilterInitStructure.CAN_FilterNumber=0;      //过滤器组0
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //工作在标识符屏蔽位模式
 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //过滤器位宽为单个32位。
 

    CAN_FilterInitStructure.CAN_FilterIdHigh= 0x0000;    //要过滤的ID高位
    CAN_FilterInitStructure.CAN_FilterIdLow= 0x0000;     //要过滤的ID低位     CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0x0000;   //过滤器高16位每位无须匹配
    CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0x0000;   //过滤器低16位每无必须匹配
 CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0 ;    //过滤器被关联到FIFO0
 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;   //使能过滤器
 CAN_FilterInit(&CAN_FilterInitStructure);
 
 CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

 

第二种:过滤器每位都必须匹配

static void CAN_Filter_Config(void)
{
   CAN_FilterInitTypeDef  CAN_FilterInitStructure;

 
 CAN_FilterInitStructure.CAN_FilterNumber=0;      //过滤器组0
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //工作在标识符屏蔽位模式
 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //过滤器位宽为单个32位。
 

    CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;    //要过滤的ID高位
    CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0xFFFF;   //过滤器高16位每位必须匹配
    CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0xFFFF;   //过滤器低16位每位必须匹配
 CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0 ;    //过滤器被关联到FIFO0
 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;   //使能过滤器
 CAN_FilterInit(&CAN_FilterInitStructure);
 
 CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

重点来了

在全部匹配的情况下为什么 CAN_FilterIdHigh )中0x1314要左移3位再与0xFFFF0000按位与; CAN_FilterIdLow中0x1314要左移3位再与CAN_ID_EXT CAN_RTR_DATA 按位或咧?实际中我发送数据时把ID标示符就设置为的是0x1314啊,见如下代码:

void CAN_SetMsg(void)
{  
  //TxMessage.StdId=0x00;      
  TxMessage.ExtId=0x1314;      //使用的扩展ID 标示符位0x1314
  TxMessage.IDE=CAN_ID_EXT;      //扩展模式
  TxMessage.RTR=CAN_RTR_DATA;     //发送的是数据
  TxMessage.DLC=2;        //数据长度为2字节
  TxMessage.Data[0]=0xDC;
  TxMessage.Data[1]=0xBA;
}

那你过滤器里标示符也应该是0x1314才对哦,按照上面那段配置标示符的代码最后存在过滤器标示符寄存器里的值肯定不是0x1314了,原因如下,就是我们用了ST的库,在发送标示符时进行了处理。

uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)
{
  uint8_t transmit_mailbox = 0;
 
  assert_param(IS_CAN_ALL_PERIPH(CANx));
  assert_param(IS_CAN_IDTYPE(TxMessage->IDE));
  assert_param(IS_CAN_RTR(TxMessage->RTR));
  assert_param(IS_CAN_DLC(TxMessage->DLC));

 
  if ((CANx->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)
  {
    transmit_mailbox = 0;
  }
  else if ((CANx->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)
  {
    transmit_mailbox = 1;
  }
  else if ((CANx->TSR&CAN_TSR_TME2) == CAN_TSR_TME2)
  {
    transmit_mailbox = 2;
  }
  else
  {
    transmit_mailbox = CAN_TxStatus_NoMailBox;
  }

  if (transmit_mailbox != CAN_TxStatus_NoMailBox)
  {
   
    CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ;
    if (TxMessage->IDE == CAN_Id_Standard)
    {
      assert_param(IS_CAN_STDID(TxMessage->StdId)); 
      CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \
                                                  TxMessage->RTR);
    }
    else
    {
      assert_param(IS_CAN_EXTID(TxMessage->ExtId));
      CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \
                                                  TxMessage->IDE | \
                                                  TxMessage->RTR);
    }

 

这是发送时对标示符做的处理,16位时只是先左移21位,然后与TxMessage->RTR(数据帧)按位或就可以了,发送32位时处理的就更多了,左移3位后先与TxMessage->IDE  按位或再与TxMessage->RTR(数据帧)按位或,这就有了我们在设置接收过滤器时为什么有了这样的语句:

CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位

 既然发送时对标示符进行了处理,同样在接收时又把标示符还原回来了:

void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage)
{
 
  assert_param(IS_CAN_ALL_PERIPH(CANx));
  assert_param(IS_CAN_FIFO(FIFONumber));
 
  RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR;
  if (RxMessage->IDE == CAN_Id_Standard)
  {
    RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21);
  }
  else
  {
    RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3);
  } // 不明白这里为什么只是把接收到的标示符还原时只进行了右移三位而没有其他处理,发送时这样的啊:

      CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \
                                                  TxMessage->IDE | \
                                                  TxMessage->RTR);
TxMessage->RTR因为是数据帧值位0,但是TxMessage->IDE 因为扩展标示符值是0x00000004,与0x1314左移3位后与数值肯定会有变化,不过就在刚刚这个问题想通了,0x4的二进制代码为0100,与0x1314左移3位后按位与就变成100肯定附加在哪个值后面,不过这个值在接收时经过一个右移三位的处理直接给处理掉了,真是高明。而RTR 为数据帧,数值为0,与另一个数与时对其没有影响。

 写了这么多太长了,不过还是搞清楚了一些东西,如果在屏蔽模式有效的情况不搞清楚这些,估计你的接收端过滤器怎么都配置不对啦,那调试起来就悲剧了,。。。。 当然如果你的屏蔽位不起作用,那就无所谓了可以随便配置过滤器标示符值,只要过滤器屏蔽寄存器值为0就OK了。。。


关键字:STM32  CAN  过滤器 引用地址:STM32 CAN 过滤器分析小结

上一篇:STM32 大小端模式 与 堆栈及其增长方向分析
下一篇:在STM32上移植ucGUI之触摸屏

推荐阅读最新更新时间:2024-03-16 15:38

STM32之SPI的思考
选择了与硬件打交道,就得戒骄戒躁,踏踏实实,一步一步的走下去。可能因为一个非常小的问题,就导致你失败。失败不可怕,可怕的是不能静下心来去思考。我在公司第一次调试硬件,spi的通信,是stm32的硬件既有的通信接口。之前用51的io口模拟过i2c的,感觉spi相对来说更简单些,结果调试spi的读写花费了我3天的时间。stm32f0与网上关于stm32f1大量的例程还不一样,刚刚上市半年多,应该是,并且有几项设置是stm32f1没有的,这也正是关键的地方。你直接把他们的程序拿过来用,可能就卡死了,为什么?因为f0多了个fifo设置,fifo不设置,默认应该是half of 32 bits,当你只接收到8个bit时,rxne不会置位,程
[单片机]
STM32+HC05串口蓝牙设计简易的蓝牙音箱
一、环境介绍 MCU: STM32F103C8T6 蓝牙模块: HC05 (串口蓝牙) 音频解码模块: VS1053B OLED显示屏: 0.96寸SPI接口OLED 开发软件: Keil5 上位机: 使用QT设计Android端APP 二、功能介绍 Android手机打开APP,设置好参数之后,选择音乐文件发送给蓝牙音箱设备端,HC05蓝牙收到数据之后,再传递给VS1053进行播放。程序里采用环形缓冲区,接收HC05蓝牙传递的数据,设置好传递的参数之后,基本播放音乐是很流畅的。 完整项目源码下载地址: https://download.csdn.net/download/xiaolong1126626
[单片机]
STM32+HC05串口蓝牙设计简易的蓝牙音箱
一种基于DSP芯片与CAN总线的电源监控系统设计
  电源技术发展的方向之一是运用电源模块并联技术实现功率合成,组成积木式、智能化的分布式大功率电源系统。为使并联的各个模块协调工作,对分布式电源系统进行可靠的监控是电源技术发展的热点之一。   目前对分布式电源监控普遍采用的做法存在的问题主要在数字化程度不高,速度不够快,精度和可靠性不够高等问题,然而在工业控制中电源控制显的十分的重要。   1电源监控系统总体设计   传统电源系统并联系统多是采用模拟的方法实现模块间的电流均流的,但存在着一些共同的不足:必须有均流控制母线,需要增加专门的均流控制器。且均流母线属于模拟电平信号线,抗干扰能力较弱;难于保证电源模块调制频率的一致。同时,当多个子并联电源单元组成分布式电源系统时,对
[嵌入式]
一种基于DSP芯片与<font color='red'>CAN</font>总线的电源监控系统设计
STM32-(31):独立看门狗
在嵌入式系统中,由于MCU(微控制单元:Microcontroller Unit)的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测程序运行状态的模块,俗称 看门狗 (watchdog) 在系统运行以后也就启动了看门狗的计数器,看门狗就开始自动计数,如果到了一定的时间还不去清看门狗,那么看门狗计数器就会溢出从而引起看门狗中断,造成系统复位。所以在使用有看门狗的时候要注意清看门狗。 看门狗是恢复系统的正常运行及有效的监视管理器(具有锁定光驱,锁定
[单片机]
STM32-(31):独立看门狗
stm32库中地址映射
一、预备知识 在编写ARM9裸机的程序时,读写某个寄存器可用如下代码实现: 例如,要读写UART_ULCON1寄存器的值,查找ARM9的用户手册就可已得到该寄存器地址。 #define UART_ULCON1 (volatile unsigned int *)(0x50004000) 写寄存器: *UART_ULCON1 = 0X00FF; 读寄存器: unsigned int temp; temp = *UART_ULCON1; 二、stm32库中地址映射 在stm32用户手册中找不到绝对的寄存器地址,需要进行换算。例如要找GPIOA中GPIOA_CRL寄存器地址: 第一步:在stm32f10x_reference文档中可查找到
[单片机]
STM32笔记(三)GPIO的配置(用GPIO点亮LED)
GPIO简介 GPIO的英文名称是General Purpose Input Output,顾名思意,就是通用输入输出口,可以用来输入输出高低电平进而控制各种连接在GPIO上的模块等等。STM32的GPIO就是51单片机的P11、P12等等引脚,不过STM32的GPIO更加强大,具有多种模式,为了控制功耗,每一个GPIO都有单独的时钟开关,每使用到一个GPIO都要对其时钟使能,而且STM32的GPIO的输入输出必须单独配置。 GPIO的模式与各种外设GPIO模式的设置 GPIO有八种输入输出模式,对于输出模式还能设置输出的速度,每一个外设对应GPIO口的模式都不全相同,例如使用I2C_SCL的时候GPIO口要设置成
[单片机]
<font color='red'>STM32</font>笔记(三)GPIO的配置(用GPIO点亮LED)
CANOPEN伺服电机的回零控制方法分享
通过总线控制伺服电机时,如何进行回零(寻参考点)控制?这里就CANOPEN伺服电机的回零控制方法分享给大家。 设置回零模式 在CANopen DSP402协议中,伺服电机进行回零动作时,其操作模式由6060h确定,当给6060h的值为6时,则将伺服电机切换为回零模式(HOMING MODE)。在回零动作启动前,可以通过读取6061h的值,以确认电机模式是否设置成功。 一般伺服电机是可以支持多种回零方式的,例如电机使用的是增量编码器,那么可以选择通过C脉冲的回零方式;如果电机使用的是串行编码器或旋转变压器,那么就不能选择通过C脉冲的回零方式。 回零启动控制 当回零模式设置完成后,可以通过控制字启动回零动作。 Controlw
[嵌入式]
<font color='red'>CAN</font>OPEN伺服电机的回零控制方法分享
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved