STM32 CAN 过滤器设置

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32 CAN 过滤器设置相关的知识,希望对你有一定的参考价值。

STM32 的CAN 通讯时要设置ID 标示符的模式(标准型还是扩展型),要设置过滤器的过滤方式(屏蔽型还是列表型,16位型还是32位型)然后有如下一段程序,配置32位屏蔽过滤器时我怎么也不看不懂,请懂的大侠给我指点一二

//主机这边的过滤器设置
static void CAN_Filter_Config(void)

CAN_FilterInitTypeDef CAN_FilterInitStructure;

/*CAN过滤器初始化*/
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器组0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //工作在标识符屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //过滤器位宽为单个32位。
/* 使能报文标示符过滤器按照标示符的内容进行比对过滤,扩展ID不是如下的就抛弃掉,是的话,会存入FIFO0。 */

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_ID_EXT=0x00000004;CAN_RTR_DATA=0x00000000;
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通信中断使能*/
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

//从机的发送配置
void CAN_SetMsg(void)

TxMessage.ExtId=0x1314; //使用的扩展ID
TxMessage.IDE=CAN_ID_EXT; //扩展模式
TxMessage.RTR=CAN_RTR_DATA; //发送的是数据
TxMessage.DLC=2; //数据长度为2字节
TxMessage.Data[0]=0xDC;
TxMessage.Data[1]=0xBA;

问题来了主机过滤器标示符CAN_FilterIdHigh=0x00000000;CAN_FilterIdLow=0x000098A4;但后面收到从机的数据标示符却是0x1314,1314和这个98A4不相等啊,怎么能够过滤过来咧?为什么在主机过滤器标示符低字节配置时要搞这么一句:
CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
直接把CAN_FilterIdLow配置成0x1314,这样标示符不就后面收到的从机的标示符一样了吗?如下:

CAN_FilterInitStructure.CAN_FilterIdLow= (u32)0x1314;

CAN总线传送到数据是基于消息而不是地址的,每个消息用不同的编号表达(2.0A用11位、2.0B用29位)。在CAN上进行简单传送而自定义传送协议时,要把所有需要传送的命令列出,然后根据传送的紧急程度(优先级)从高到低进行排序,然后把最高优先级的设定一个最低的编号、以此类推...最低优先级的设定最高的编号。因为CAN物理上是不分主从,所以当有几个站点同时发送而发生碰撞时,编号最低的将优先传送。
从总线上接收消息:每个站点可能只对所有协议中的几个消息感兴趣,CAN初始化时,在过滤器中设置本站点需要接收的消息编号,这样一旦总线上有需要的消息将会自动接收,并产生中断,通知CPU收到新消息,CPU在中断程序中接收、处理。
发送消息到总线上:CAN初始化时设置本站点将来需要发送的消息编号,当运行过程中需要发送消息时,填入相关数据,设置相关消息对象发送。
CAN控制器内部一般设有32个消息对象,分成2组,分别各用一组寄存器来操作。一般一组用来接收过滤,另一组用来发送。
希望能解决您的问题。
参考技术A 看手册里有关该模式过滤寄存器的每位含义,最低三位是IDE RTR和 0,前面高位是标识符 参考技术B 如果答案是你这样,那么IDE,RTR就不管了?移动三位我们可以理解成给IDE,RTR,以及保留位留位置出来(这三位可不是在扩展18位里面的),那么问题来了98A4怎么出来的呢(自己去算,单片机自己不动脑是不行的)?

用CAN总线对STM32微控制器编程的问题

【中文标题】用CAN总线对STM32微控制器编程的问题【英文标题】:Problem related to programing STM32 microcontroller with CAN bus 【发布时间】:2019-11-12 21:25:20 【问题描述】:

我是 STM32 微控制器和 CAN 总线通信协议的新手,我正在编写一个 STM32F103xx 微控制器。 我想使用 CAN 总线将数据传输到同系列的另一个微控制器。

我设置了所有必要的设置,但是在调试代码时,它卡在传输挂起函数中并且不传输。 我希望传输数据,但不是。

我认为我的硬件没有问题。

PS: 我已经尝试过 CAN 处理程序的正常模式和 LOOPBACK 模式,但它们都不起作用。

int main(void)

    HAL_Init();

    SystemClock_Config();

    uint32_t BUTTON_0;
    uint32_t BUTTON_1;

    uint8_t Data_0[5] = "aaaaa";
    uint8_t Data_1[5] = "ZZZZZ";

    MX_GPIO_Init();
    MX_CAN_Init();

    if(HAL_CAN_Init(&hcan) != HAL_OK)
        Error_Handler();
    

    if(HAL_CAN_Start(&hcan) != HAL_OK)
        Error_Handler();
    

    while (1)
           
        TxHeader.DLC   = 5;
        TxHeader.StdId = 0x65D;
        TxHeader.IDE   = CAN_ID_STD;
        TxHeader.RTR   = CAN_RTR_DATA;

        BUTTON_0 = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

        BUTTON_1 = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);

        if (BUTTON_0 == 0U)

            if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, Data_0, &TxMailbox) != HAL_OK )
                Error_Handler();
            

        

        if (BUTTON_1 == 0U)

            if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, Data_1, &TxMailbox) != HAL_OK)
                Error_Handler();
            

        

        while (HAL_CAN_IsTxMessagePending(&hcan, TxMailbox));

        if (BUTTON_0 && BUTTON_1 == 0U)
            printf("Please Press a Button");
        
    

【问题讨论】:

【参考方案1】:

您正在使用 STM32CubeF1 HAL 库(可能通过 STM32CubeMX)。 请检查对应的 User Manual - 第 9.2.1 节推荐以下程序:

    通过实现HAL_CAN_MspInit() 初始化 CAN 低级资源: 使用__HAL_RCC_CANx_CLK_ENABLE()启用CAN接口时钟 配置 CAN 引脚 为 CAN GPIO 启用时钟 将 CAN 引脚配置为备用功能开漏 如果使用中断 [...] 使用HAL_CAN_Init() 函数初始化CAN 外设。 该函数借助HAL_CAN_MspInit() 进行低级初始化。 使用以下配置函数配置接收过滤器: HAL_CAN_ConfigFilter() 使用HAL_CAN_Start()函数启动CAN模块。 在此级别,节点在总线上处于活动状态: 它接收消息,并且可以发送消息。 要管理消息传输,可以使用以下 Tx 控制功能: HAL_CAN_AddTxMessage() 请求传输新消息。 [...] HAL_CAN_IsTxMessagePending() 检查 Tx 邮箱中是否有消息待处理。 [...] 当 CAN Rx FIFO 接收到消息时, 可以使用HAL_CAN_GetRxMessage() 函数检索它。 函数 HAL_CAN_GetRxFifoFillLevel() 允许知道有多少 Rx 消息 存储在 Rx FIFO 中。 调用HAL_CAN_Stop() 函数会停止CAN 模块。 通过HAL_CAN_DeInit()函数实现去初始化。

[...]

轮询模式操作/传输:

监控 Tx 邮箱的可用性,直到至少有一个 Tx 邮箱空闲, 使用HAL_CAN_GetTxMailboxesFreeLevel()。 然后使用HAL_CAN_AddTxMessage() 请求传输消息。

您的代码示例未显示从 main() 调用的子函数,因此您必须自己检查 :-)

CAN/GPIO 时钟在分配相应的寄存器之前已启用。 GPIO 引脚按照建议配置。

另一个想法 - 是不是你必须在启动 CAN 之后检查HAL_CAN_GetTxMailboxesFreeLevel(),甚至在添加第一条消息进行传输之前?

步骤 (2.)、(4.)、(5.) 已由您的代码处理,并且 步骤 (3.)、(6.)、(7.)、(8.) 与您的问题无关(但仅与接收 / deinit 相关)。


如果您不想自己完成所有手动工作,也可以使用以下工具之一作为起点。 这两种工具都远非完美(我们的一些 *** 同行根本不同意推荐它们),但它们通常已经提供了包含您需要的大部分相关步骤的基本结构:

固件示例集合(参见他们的 Application Note 详情)。

代码生成器 STM32CubeMX

【讨论】:

以上是关于STM32 CAN 过滤器设置的主要内容,如果未能解决你的问题,请参考以下文章

stm32f103 can采样点设置为多少合适

CAN过滤

STM32 双CAN中Filter配置

STM32下调试CAN通信

STM32F1上CAN2不能接收到数据

ESP32 如何配置 CAN 双滤波器模式