stm32 cubemx can通讯(2)过滤器设置说明代码分析

文章目录

  • 前言
  • 一、基础知识快速理解
    • 1.1 理解CAN标识符:
    • 1.2 过滤器的工作原理:
    • 1.3 如何配置过滤器:
  • 二、过滤器模式的选择(监听多个ID)
    • 2.1 使用掩码模式多个过滤器匹配多标准ID:
    • 2.2 使用掩码来匹配多个ID:(待写)
    • 2.3 使用列表模式来匹配多个标准ID:
  • 三、相关代码测试
    • 3.1 测试列表模式__标准ID
    • 3.2 测试掩码模式__标准ID
    • 3.3 测试回调函数接收到的ID
  • 总结


前言

stm32 cubemx can通讯(1)回环模式

过滤器可以说是can中最重要的东西,我也认为这个是一个相当复杂的一个东西。
一个刚刚学习的小白,以下文字只是自我学习的笔记,若有写错或不明确的地方请大佬指正。
CAN过滤器是一个非常重要的功能,它允许你只接收你关心的CAN消息,从而提高效率和性能。


一、基础知识快速理解

1.1 理解CAN标识符:

在CAN总线上,每个消息都有一个唯一的标识符(ID)。这个ID可以是11位(标准ID)或29位(扩展ID)。ID不仅仅是用来标识消息来源,而且还决定了消息的优先级:ID小的消息优先级更高。

1.2 过滤器的工作原理:

过滤器的工作原理是将传入的ID与预设的ID进行比较,然后决定是否接收这个消息。过滤器可以工作在两种模式下:

  • 列表模式 (Identifier List mode):
    在这种模式下,你可以为每个过滤器指定一个或多个ID。只有与这些ID匹配的消息才会被接收。
  • 掩码模式 (Identifier Mask mode):
    在这种模式下,你为每个过滤器指定一个ID和一个掩码。只有与这个ID匹配的消息才会被接收。掩码允许你定义哪些位是重要的(即需要匹配的)和哪些位可以忽略。例如,一个掩码0xFF0表示你只关心ID的高8位,而不关心低4位。

1.3 如何配置过滤器:

(下面只要知道大致流程就行不要知道sFilterConfig这些东西是啥,后面会说)

1.3节都是基于标准ID
首先, 我们考虑一个例子:我们只希望接收ID为0x123的消息,其他消息都忽略。

设置选择的过滤器:
sFilterConfig.FilterBank = 0; // 使用过滤器0

设置过滤器模式为掩码模式:
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;

使用32位模式:
这使得我们可以处理标准ID和扩展ID。
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;

指定我们关心的ID和掩码:
因为0x123是一个标准ID,我们可以这样配置:

sFilterConfig.FilterIdHigh = 0x123 << 5; // 11位ID需要左移5位
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0xFFFF; // 只关心高16位
sFilterConfig.FilterMaskIdLow = 0x0000; 

这样的配置意味着:我们只接收高16位是0x123,低16位可以是任何值的消息。由于标准ID只有11位,低16位永远是0,所以这正是我们想要的。

为什么左移5位?
STM32的CAN过滤器使用了一种特殊的方式来处理标准11位和扩展29位的ID。为了在32位寄存器中放入11位的标准ID,我们需要将其左移5位。这是硬件的要求,不是我们随便决定的。
所以,如果你有一个标准ID0x123,其二进制形式是:
100100011
为了将它放入STM32的过滤器寄存器,你需要将它左移5位:
100100011 00000
这就是为什么我们使用<< 5。

为什么只关心高16位
当我们说“只关心高16位”,其实是指在32位的掩码或ID中,我们只设置或匹配高16位。STM32的CAN过滤器将32位分为了两个16位的部分:FilterIdHigh和FilterIdLow。在我们的例子中,由于我们只处理一个11位的标准ID,所以我们只需要在FilterIdHigh部分设置它,而将FilterIdLow部分设置为0。

关于11位与16位的区别:
实际上,我们并不真的关心整个16位,只关心其中的高11位。但由于简化和兼容性的考虑,我们通常设置整个16位。
如果我们想要严格限制为只匹配高11位,并且确保其他位不匹配,我们可以使用0xF800作为掩码。这表示我们关心高11位(1111 1000 0000 0000),而不关心低5位。
总之,为了简化操作,我们通常使用0xFFFF作为掩码来接收所有与指定ID匹配的标准CAN消息。但如果你想要更精确的匹配,你可以调整掩码以只匹配高11位。

设置FIFO:
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
这意味着匹配的消息将被放入FIFO0。

二、过滤器模式的选择(监听多个ID)

当想要监听多个标准ID的时候,有几种方法可以实现:

简而言之,掩码告诉硬件哪些位是我们关心的,而过滤器则告诉硬件我们希望这些位的值是什么。如果接收到的消息与过滤器匹配(只在我们关心的位上),那么消息将被接受。

2.1 使用掩码模式多个过滤器匹配多标准ID:

STM32的CAN控制器提供了多个过滤器(具体数量取决于具体的STM32型号)。每个过滤器可以配置为匹配一个或多个ID。
例如,你想要监听两个标准ID:0x123和0x456。你可以设置两个过滤器,每个过滤器匹配一个ID。

// 过滤器0匹配0x123
sFilterConfig.FilterBank = 0;  // 使用过滤器0
sFilterConfig.FilterIdHigh = 0x123 << 5;
sFilterConfig.FilterMaskIdHigh = 0xFFFF;
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
// 过滤器1匹配0x456
sFilterConfig.FilterBank = 1;  // 使用过滤器1
sFilterConfig.FilterIdHigh = 0x456 << 5;
sFilterConfig.FilterMaskIdHigh = 0xFFFF;
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);

2.2 使用掩码来匹配多个ID:(待写)

这种方法取决于你想要监听的ID的特性。如果这些ID有一定的位集合,你可以使用掩码来匹配它们。

2.3 使用列表模式来匹配多个标准ID:

在列表模式下,过滤器会尝试匹配你所列举的任何ID。对于标准ID,一个过滤器可以匹配两个ID。对于扩展ID,过滤器只能匹配一个ID。

这里是一个如何使用列表模式来匹配四个标准ID(0x1, 0x2, 0x3, 0x4)的示例:

// 过滤器1匹配0x1和0x2
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; // 16-bit列表模式用于标准IDsFilterConfig.FilterIdHigh = 0x1 << 5;    // ID1
sFilterConfig.FilterIdLow = 0x2 << 5;     // ID2HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);// 过滤器2匹配0x3和0x4
sFilterConfig.FilterBank = 1;
sFilterConfig.FilterIdHigh = 0x3 << 5;    // ID3
sFilterConfig.FilterIdLow = 0x4 << 5;     // ID4HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);

为什么使用 CAN_FILTERSCALE_16BIT 而不是 CAN_FILTERSCALE_32BIT?
当我们使用标准ID(11位)并希望用单个过滤器同时匹配多个ID时,CAN_FILTERSCALE_16BIT 是有意义的。STM32的CAN硬件允许我们在16位过滤模式下为两个标准ID设置单个过滤器。因此,每个32位寄存器可以分为两个16位部分,每部分用于一个标准ID。这使得硬件更加高效地匹配两个不同的ID,而不需要额外的过滤器。

关于 sFilterConfig.FilterIdHigh 和 sFilterConfig.FilterIdLow 的顺序:
过滤器的初始化顺序是可以互换的。你可以首先设置 FilterIdLow,然后再设置 FilterIdHigh。硬件只是看这两个值和接收的消息ID进行比较,不关心你是如何设置这两个值的。
sFilterConfig.FilterIdLow = 0x1 << 5; sFilterConfig.FilterIdHigh = 0x2 << 5;
这也是有效的,它将会匹配ID为 0x1 和 0x2 的消息。

三、相关代码测试

我们接着使用回环模式类似的代码,
这时候由于使用到了usb_can调试器,所以你要有一个这个东西。emm
然后cubemx里面的回环模式给位normal模式就行。
把发送函数改成这样,改动的地方在于。现在使用的是标准id,由于标准id最大支持11位,所以就要求最大不要超过0x7ff,并把ide改为id_std

void CAN_senddata(CAN_HandleTypeDef *hcan)
{TXHeader.StdId=0x7ff;//0X7FF因为标准id最大11位TXHeader.ExtId=0x0000000;TXHeader.DLC=8;TXHeader.IDE=CAN_ID_STD;TXHeader.RTR=CAN_RTR_DATA;TXHeader.TransmitGlobalTime = DISABLE;HAL_CAN_AddTxMessage(hcan,&TXHeader,TXmessage,&pTxMailbox);
}

3.1 测试列表模式__标准ID

只需要这些代码在can_init的位置就可以了。
当使用01 和 02进行发送的时候可以产生中断。其他的不行

  /* USER CODE BEGIN CAN_Init 2 */CAN_FilterTypeDef sFilterConfig;sFilterConfig.FilterActivation = ENABLE;sFilterConfig.FilterBank = 0;sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; // 16-bit列表模式用于标准IDsFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO0sFilterConfig.FilterIdHigh = 0x1 << 5;    // ID1sFilterConfig.FilterIdLow = 0x2 << 5;     // ID2if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器{Error_Handler();}if(HAL_CAN_Start(&hcan) != HAL_OK)//打开can{Error_Handler();}if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)//开启接受邮箱0挂起中断{Error_Handler();}/* USER CODE END CAN_Init 2 */

3.2 测试掩码模式__标准ID

只需要这些代码在can_init的位置就可以了。
当使用01 和 02进行发送的时候可以产生中断。其他的不行

	CAN_FilterTypeDef sFilterConfig;sFilterConfig.FilterActivation = ENABLE;sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 16-bit列表模式用于标准IDsFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO0
// 过滤器匹配0x1sFilterConfig.FilterBank = 0;sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;	sFilterConfig.FilterIdHigh = 0x1 << 5;sFilterConfig.FilterMaskIdHigh = 0xFFFF;if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器{Error_Handler();}
// 过滤器匹配0x1sFilterConfig.FilterBank = 1;sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;	sFilterConfig.FilterIdHigh = 0x2<< 5;sFilterConfig.FilterMaskIdHigh = 0xFFFF;if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器{Error_Handler();}

3.3 测试回调函数接收到的ID

int  cc =0;
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)//接受邮箱0挂起中断回调函数
{if(hcan->Instance == CAN1){// 获取数据HAL_CAN_GetRxMessage(hcan, CAN_FILTER_FIFO0, &RXHeader, RXmessage);// 根据接收到的ID进行处理switch (RXHeader.StdId){case 0x1:// 对于ID 0x1的处理代码cc=1;break;case 0x2:// 对于ID 0x2的处理代码cc=2;break;default:// 其他未知ID的处理(如果需要)break;}}	
}

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/34499.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于.Net开发的ChatGPT客户端,兼容Windows、IOS、安卓、MacOS、Linux

2023年目前要说最热的点&#xff0c;肯定是ChatGPT了。 ChatGPT官方提供的网页版本&#xff0c;还有需要科*上网&#xff0c;很多人都会基于此进行封装。 现在是移动互联网时代&#xff0c;基于手机APP的需求还是很大的。 所以&#xff0c;今天给大家推荐一个ChatGPT客户端开…

Vue电商项目--组件通信

组件通信6种方式 第一种&#xff1a;props 适用于的场景&#xff1a;父子组件通信 注意事项&#xff1a; 如果父组件给子组件传递数据&#xff08;函数&#xff09;&#xff1a;本质其实是子组件给父组件传递数据 如果父组件给子组件传递的数据&#xff08;非函数&#xf…

期权定价模型系列【1】—BSM通用式模型

这是期权定价模型专栏的第一篇文章&#xff0c;此专栏旨在分享一些期权定价模型&#xff0c;将会从最基础的BSM模型开始写起&#xff0c;逐步扩散到蒙特卡洛模拟、二叉树等数值法模型&#xff0c;以及跳跃扩散模型、随机波动率模型&#xff0c;神经网络模型等等。 如果你觉得有…

Java负载均衡算法实现与原理分析(轮询、随机、哈希、加权、最小连接)

文章目录 一、负载均衡算法概述二、轮询&#xff08;RoundRobin&#xff09;算法1、概述2、Java实现轮询算法3、优缺点 三、随机&#xff08;Random&#xff09;算法1、概述2、Java实现随机算法 四、源地址哈希&#xff08;Hash&#xff09;算法1、概述2、Java实现地址哈希算法…

198、仿真-基于51单片机函数波形发生器调幅度频率波形Proteus仿真(程序+Proteus仿真+原理图+流程图+元器件清单+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、原理图 五、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选…

Leetcode-每日一题【剑指 Offer 27. 二叉树的镜像】

题目 请完成一个函数&#xff0c;输入一个二叉树&#xff0c;该函数输出它的镜像。 例如输入&#xff1a; 4 / \ 2 7 / \ / \ 1 3 6 9 镜像输出&#xff1a; 4 / \ 7 2 / \ / \ 9 6 3 1 示例 1&#xff1a; 输入&#xff1a;root [4,2,…

(vue)获取对象的键遍历,同时循环el-tab页展示key及内容

(vue)获取对象的键遍历&#xff0c;同时循环el-tab页展示key及内容 效果&#xff1a; 数据结构&#xff1a; "statusData": {"订购广度": [ {"id": 11, "ztName": "广", …

YAPi在线接口文档简单案例(结合Vue前端Demo)

在前后端分离开发中&#xff0c;我们都是基于文档进行开发&#xff0c;那前端人员有时候无法马上拿到后端的数据&#xff0c;该怎么办&#xff1f;我们一般采用mock模拟伪造数据直接进行测试&#xff0c;本篇文章主要介绍YApi在线接口文档的简单使用&#xff0c;并结合Vue的小d…

[保研/考研机试] KY183 素数 北京航空航天大学复试上机题 C++实现

题目链接&#xff1a; 素数https://www.nowcoder.com/share/jump/437195121691718444910 描述 输入一个整数n(2<n<10000)&#xff0c;要求输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数&#xff0c;如果没有则输出-1。 输入描述&#xff1a; 输入有多…

vue3+element-plus点击列表中的图片预览时,图片被表格覆盖

文章目录 问题解决 问题 视觉 点击图片进行预览&#xff0c;但还能继续选中其他的图片进行预览&#xff0c;鼠标放在表格上&#xff0c;那一行表格也会选中&#xff0c;如图所示第一行的效果。 代码 <el-table-column prop"id" label"ID" width"…

云原生K8S------Yaml文件详解

目录 一&#xff1a;K8S支持的文件格式 1&#xff0c;yaml和json的主要区别 2&#xff0c;YAML语言格式 二&#xff1a;yuml 1、查看 api 资源版本标签 2、写一个yaml文件demo 3、创建service服务对外提供访问并测试 4、详解k8s中的port 三&#xff1a;文件生成 1、kubec…

华为OD真题--完美走位--带答案

2023华为OD统一考试&#xff08;AB卷&#xff09;题库清单-带答案&#xff08;持续更新&#xff09;or2023年华为OD真题机考题库大全-带答案&#xff08;持续更新&#xff09; 题目描述 输入一个长度为4的倍数的字符串Q,字符串中仅包含WASD四个字母。 将这个字符串中的连续子串…

Vue2到3 Day5 全套学习内容,众多案例上手(内付源码)

简介&#xff1a; Vue2到3 Day1-3 全套学习内容&#xff0c;众多案例上手&#xff08;内付源码&#xff09;_星辰大海1412的博客-CSDN博客本文是一篇入门级的Vue.js介绍文章&#xff0c;旨在帮助读者了解Vue.js框架的基本概念和核心功能。Vue.js是一款流行的JavaScript前端框架…

类与对象(加深)

目录 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 6.const成员 7.取地址及const取地址操作符重载 1.类的6个默认成员函数 如果…

Mysql 和Oracle的区别

、mysql与oracle都是关系型数据库&#xff0c;Oracle是大型数据库&#xff0c;而MySQL是中小型数据库。但是MySQL是开源的&#xff0c;但是Oracle是收费的&#xff0c;而且比较贵。 1 2 mysql默认端口&#xff1a;3306&#xff0c;默认用户&#xff1a;root oracle默认端口&…

shell脚本开发

shell脚本语言属于弱类型的语言&#xff0c;无需声明变量类型&#xff0c;直接定义使用 shell语言定义的变量&#xff0c;数据类型默认都是字符串类型 调用历史记录命令&#xff1a;&#xff01; 历史记录id

vue3+vue-simple-uploader实现大文件上传

vue-simple-uploader本身是基于vue2实现,如果要使用vue3会报错。如何在vue3中使用,可参考我的另一篇文章:解决vue3中不能使用vue-simple-uploader__Jyann_的博客-CSDN博客 一.实现思路 使用vue-simple-uploader组件的uploader组件,设置自动上传为false,即可开启手动上传。…

netty基础与原理

Netty线程模型和Reactor模式 简介&#xff1a;reactor模式 和 Netty线程模型 设计模式——Reactor模式&#xff08;反应器设计模式&#xff09;&#xff0c;是一种基于 事件驱动的设计模式&#xff0c;在事件驱动的应用中&#xff0c;将一个或多个客户的 服务请求分离&#x…

【ARM Cache 系列文章 9 -- ARM big.LITTLE技术】

文章目录 big.LITTLE 技术背景big.LITTLE 技术详解big.LITTLE 硬件要求 big.LITTLE 软件模型CPU MigrationGlobal Task SchedulingGlobal Task Scheduling比CPU Migration的优势 转自&#xff1a;https://zhuanlan.zhihu.com/p/630981648 如有侵权&#xff0c;请联系删除 big.L…

Leetcode 21. 合并两个有序链表

题目描述 题目链接&#xff1a;https://leetcode.cn/problems/merge-two-sorted-lists/description/ 思路 两个链表都是升序链表&#xff0c;新建一个链表&#xff0c;引入伪头节点作为辅助节点&#xff0c;将各节点添加到伪节点之后&#xff0c;再用一个cur节点指向新链表的…