stm32cubemx hal学习记录:CAN

news2025/1/12 2:59:41

一、实验内容

RM C板,can1给can2发送数据

二、CAN总线简介

1、控制器局域网络:Controller Area Network

2、异步半双工通信

3、总线制

CAN由一对差分对(两条线)CANH和CANL组成

CANH电压比CANL高视为逻辑0(显性电平),否则为逻辑1(隐性电平)

多个设备可以连接到同一条CAN上

总线上的设备通过ID号区分

ID号长度可以为11位标准长度或者29位拓展长度

4、常用标准

①CAN2.0b标准

最大速率1Mbps,一组数据称为一帧,分为数据帧和远程帧,数据帧最多传输8个字节的数据,每一帧都有CRC校验。

②CAN FD标准,很多设备不支持

最大速率可达8Mbps,数据帧最多可传输64字节数据

5、CAN物理层

单片机一般使用类似串口的CAN RX和CAN TX接口驱动CAN

CAN RX/CAN TX需要经过CAN收发器才能被转换成对应的差分电平

一般CAN差分信号的电压为0-5V,也可以是0-3.3V,但不建议使用3.3v

6、CAN总线结构

CAN有两个120Ω的终端电阻,位于CAN布线的两端,每个设备挂载在总线上幸成数个支路

 7、CAN时序

太复杂懒得学

8、CAN的帧

ID:ID号,标准11位,扩展29位

RTR:区别远程帧与数据帧,一般为数据帧,设置为0

IDE:区别ID号长度,0的话为11位,1的话为29位

DLC:数据长度,发送多少字节的数据,为0-8或者增强帧的0-64位

CRC:校验部分,CRC16,不用管,stm32自动生成

连续的五个以上相同位中间会插入一个相反位,除结尾外

9、CAN的仲裁

①由于CAN定义2条信号线的电压差代表逻辑0或者逻辑1,CAN的两条信号线实质上等效为串口的一条线

②当总线上连续3位的时间为1且没有正在传输的帧时,视为空闲状态,此时设备才能进行发送

③如果有2个或以上设备同时启动了发送则会进入仲裁

发送0更多的设备会赢得仲裁并继续发送

由于CAN时序的规定,仲裁是很难进入的,只有两个设备在同一Tq内启动发送才会进入仲裁

10、STM32的CAN外设

①FDCAN:仅限H系列和G系列(FDCAN和CAN2.0b)

②bxCAN:标准CAN外设,仅支持CAN2.0b

一般有1-3个CAN,CAN1和CAN3是主CAN,CAN2是从CAN

CAN2在CAN1打开之后才能打开,推荐两个同时打开

11、STM32的CAN时序

f=fapb/(psc*(bs1+bs2+1))

常用参数:用于STM32F407,主频为168MHz时,APB1为42MHz,设置BS1=9,BS2=4,BS3=3,此时得到1MHz的CAN频率

三、配置

1、板子接线H连L,L连H

2、配置cubemx基础配置

3、点开CAN1和CAN2

 4、配置CAN的参数

 按照123的顺序配置,否则会报错

5、打开CAN的全部中断

 6、设置PA8为输入模式,使用此按键来触发发送

7、生成代码

四、未添加过滤器代码

初始化

void CAN_ConfigFilter(void)
{
	CAN_FilterTypeDef sFilterConfig;
	sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
	sFilterConfig.FilterBank=0;  //过滤器编号
	sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO0; //过滤器给到rx0还是rx1
	sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK;//模式
	sFilterConfig.FilterScale=CAN_FILTERSCALE_32BIT;//16位还是32位,此时配置32位
	sFilterConfig.FilterIdHigh=0x00;
	sFilterConfig.FilterIdLow=0x00;
	sFilterConfig.FilterMaskIdHigh=0x00;
	sFilterConfig.FilterMaskIdLow=0x00;
	sFilterConfig.SlaveStartFilterBank=14;//定值
	
	if(HAL_CAN_ConfigFilter(&hcan1,&sFilterConfig)!=HAL_OK)
	{
		Error_Handler();
	}
	
	sFilterConfig.FilterBank=14;  //CAN2过滤器编号

	if(HAL_CAN_ConfigFilter(&hcan2,&sFilterConfig)!=HAL_OK)
	{
		Error_Handler();
	}	
	
	if(HAL_CAN_Start(&hcan1)!=HAL_OK)
	{
		Error_Handler();
	}
	
	if(HAL_CAN_Start(&hcan2)!=HAL_OK)
	{
		Error_Handler();
	}
	
	//打开中断
	if(HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
	{
		Error_Handler();
	}
	if(HAL_CAN_ActivateNotification(&hcan2,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
	{
		Error_Handler();
	}
}

参数定义

uint8_t txDataBuffer[8],rxDataBuffer0[8],rxDataBuffer1[8];
CAN_TxHeaderTypeDef txHeader;;
CAN_RxHeaderTypeDef rxHeader0,rxHeader1;

uint16_t txID=0x20;	//发送的ID
uint32_t txMailbox;	//发送邮箱的地址

main中按键触发can1发送

  while (1)
  {
    /* USER CODE END WHILE */
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8)==0)
		{
			HAL_Delay(20);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8)==0)
			{
				
				txHeader.StdId=txID;
				txHeader.IDE=CAN_ID_STD;
				txHeader.RTR=CAN_RTR_DATA;  //数据帧
				txHeader.DLC=8;							//8位
				
				*((uint32_t*)(txDataBuffer))=HAL_GetTick();  //发送当前运行的时间
				
				if(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)!=0)  //检验是否是空闲状态
				{
					HAL_CAN_AddTxMessage(&hcan1,&txHeader,txDataBuffer,&txMailbox);
				}
				
			}
		}
    /* USER CODE BEGIN 3 */
  }

中断can2接收

//接收到的数据将会在rxHeader结构体和rxDataBuffer中
void HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan == &hcan2)
	{
		HAL_CAN_GetRxMessage(&hcan2,CAN_RX_FIFO0,&rxHeader0,rxDataBuffer0);
	}
}

void HAL_CAN_RxFifo1FullCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan == &hcan2)
	{
		HAL_CAN_GetRxMessage(&hcan2,CAN_RX_FIFO1,&rxHeader1,rxDataBuffer1);
	}	
}

五、过滤器

1、STM32的bxCAN接收时必须使用过滤器接收

2、根据CAN外设数量的不同有以下情况:

①只有CAN1:CAN1有14个过滤器

②有CAN1和CAN2:CAN1和CAN2共享28个过滤器

③有CAN1-3:CAN1和CAN2共享28个过滤器,CAN3则有独立的14个过滤器

3、过滤器可以过滤CAN总线上帧的ID号,可以不处理不想接受的ID号,直接收想要的ID号

4、掩码

①两个单元分别组成匹配ID和掩码

②被过滤的ID号和匹配ID号会和掩码进行按位与运算后再进行匹配,也就是只有对应的掩码为1的位才会被匹配

③例如:

匹配ID为0x200,掩码为0x000,则所有ID号都能通过

匹配ID为0x200,掩码为0x700,则ID为0x200~0x2FF均可通过

匹配ID为0x200,掩码为0x7FF,则只有0x200能通过

void CAN_ConfigFilter(void)
{
	CAN_FilterTypeDef sFilterConfig;
	sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
	sFilterConfig.FilterBank=0;  												//过滤器编号,CAN1为0-13
	sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO0; //过滤器给到rx0还是rx1
	sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK;			//模式
	sFilterConfig.FilterScale=CAN_FILTERSCALE_32BIT;		//16位还是32位,此时配置32位
	sFilterConfig.FilterIdHigh=0x00;
	sFilterConfig.FilterIdLow=0x00;
	sFilterConfig.FilterMaskIdHigh=0x00;
	sFilterConfig.FilterMaskIdLow=0x00;
	sFilterConfig.SlaveStartFilterBank=14;							//定值
	
	if(HAL_CAN_ConfigFilter(&hcan1,&sFilterConfig)!=HAL_OK)
	{
		Error_Handler();
	}
	
	//CAN2设置过滤器,FIFO0
	sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
	sFilterConfig.FilterBank=14;  											//过滤器编号,CAN2为14-27
	sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO0; //过滤器给到rx0还是rx1
	sFilterConfig.FilterMode=CAN_FILTERMODE_IDLIST;			//模式
	sFilterConfig.FilterScale=CAN_FILTERSCALE_16BIT;		//16位还是32位,此时配置16位
	//过滤0x200 201 202 203这四个ID号,只有当这个id号完全等于完全匹配的时候,才会被过滤掉
	//如果想要过滤三个,则写一个不存在的id号,例如0x800
	sFilterConfig.FilterIdHigh=0x200<<5;   
	sFilterConfig.FilterIdLow=0x201<<5;
	sFilterConfig.FilterMaskIdHigh=0x202<<5;
	sFilterConfig.FilterMaskIdLow=0x203<<5;
	sFilterConfig.SlaveStartFilterBank=14;							//定值

	if(HAL_CAN_ConfigFilter(&hcan2,&sFilterConfig)!=HAL_OK)
	{
		Error_Handler();
	}	
	
	//CAN2设置过滤器,FIFO1
	sFilterConfig.FilterActivation=CAN_FILTER_ENABLE;
	sFilterConfig.FilterBank=15;  											//过滤器编号,CAN2为14-27
	sFilterConfig.FilterFIFOAssignment=CAN_FilterFIFO1; //过滤器给到rx0还是rx1
	sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK;			//模式
	sFilterConfig.FilterScale=CAN_FILTERSCALE_16BIT;		//16位还是32位,此时配置16位
	//过滤0x200 201 202 203这四个ID号,只有当这个id号完全等于完全匹配的时候,才会被过滤掉
	//如果想要过滤三个,则写一个不存在的id号,例如0x800
	sFilterConfig.FilterIdHigh=0x200<<5;   
	sFilterConfig.FilterMaskIdHigh=0x700<<5; //这句和上一句说明过滤的为0x200-0x2FF
	sFilterConfig.FilterIdLow=0x201<<5;
	sFilterConfig.FilterMaskIdLow=0x203<<5;
	sFilterConfig.SlaveStartFilterBank=14;							//定值

	if(HAL_CAN_ConfigFilter(&hcan2,&sFilterConfig)!=HAL_OK)
	{
		Error_Handler();
	}		
	
	if(HAL_CAN_Start(&hcan1)!=HAL_OK)
	{
		Error_Handler();
	}
	
	if(HAL_CAN_Start(&hcan2)!=HAL_OK)
	{
		Error_Handler();
	}
	
	//打开中断
	if(HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
	{
		Error_Handler();
	}
	if(HAL_CAN_ActivateNotification(&hcan2,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
	{
		Error_Handler();
	}
}

整理自:CH4.2 CAN 第2讲 过滤器【南工骁鹰嵌入式软件培训】_哔哩哔哩_bilibili

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

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

相关文章

IDEA插件系列(3):Easy Javadoc插件——快速生成javadoc文档注释

1.插件介绍 Easy Javadoc插件。 能帮助开发者快速生成类、方法、属性等中文javadoc 2.安装方式 第一种安装方式是在线下载安装插件。 第二种安装方式是使用离线插件进行安装。 插件下载地址&#xff1a;https://plugins.jetbrains.com/plugin/12977-easy-javadoc 3.使…

梦开始的地方—— C语言预处理+编译过程

文章目录C语言程序的编译(预处理)1.编译和链接1) 编译的几个阶段预编译阶段编译阶段汇编阶段2) 链接2. 预处理1) 预定义符号2) #define3) #和##4) 带副作用的宏参数5) 宏和函数对比3. 常见预处理命令1) #undef2) 命令行定义3) 条件编译4) 文件包含5) 实现offsetofC语言程序的编…

Spring 中 @Autowired 修饰构造方法时注意事项

代码演示 给定一个类 One&#xff0c;然后看下的几种构造方法什么时候被调用 1、假设现在只有一个默认的空构造方法&#xff0c;代码如下&#xff1a; Component public class One {}然后追踪源码&#xff0c;如下所示&#xff1a; 先拿到所有声明的构造方法 然后挨个判断构…

总结Python设置Excel单元格样式的一切,比官方文档还详细

总结Python设置Excel单元格样式的一切&#xff0c;比官方文档还详细 Python对Excel表格处理非常方便&#xff0c;本文专门对Excel单元格样式设置进行总结&#xff0c;日常用到的设置基本都可以用openpyxl库完成。 创建一个表格 openpyxl是第三方库&#xff0c;如果你还没有安…

如何撰写好的科研论文:摘要(1)

导读 本系列将切片介绍如何写好科研论文&#xff0c;包含了&#xff1a;摘要&#xff0c;背景介绍&#xff0c;方法&#xff0c;结果&#xff0c;讨论等&#xff0c;本文[1]将从摘要开始。 1. 标准 Criteriapointline一般背景听众中的每个人都关心的事情。具体背景从每个人都关…

免费内网穿透工具测评对比,谁更好用 1

文章目录1. 前言2. 对比内容1.1官网主页对比1.2 用户注册对比1.3 用户功能页面对比1.4 客户端对比3. 结语1. 前言 自从接触到内网穿透服务&#xff0c;知道能把自家的电脑、树莓派、NAS等等一堆硬件改造成服务器后&#xff0c;笔者就陷入其中无法自拔&#xff0c;一会儿把树莓…

jmeter接口测试之大家都来我家领豆子

一、测试目的&#xff1a; 2万用户不停请求云豆领取接口时&#xff0c;查看服务器内存占用情况&#xff0c;从而确认服务器内存占用异常的情况是否得到修复。 二、测试策略&#xff1a; 用2万个账号&#xff0c;以每2秒100次请求的速度向服务器发出请求&#xff0c;观察内存…

c#入门-顶级语句和Main方法

程序入口 在你运行程序以后会弹出一个窗口&#xff0c;显示一行文字&#xff1a;Hello world 现在将代码中的所有东西再复制一遍。然后运行&#xff0c;就会得到两行Hello world 显然&#xff0c;我们的程序是写在这里的。 在这里写了什么&#xff0c;什么就会生效。 Main方…

【自动化测试】Pytest+Appium+Allure 做 UI 自动化的那些事

文本主要介绍下 PytestAllureAppium 记录一些过程和经历。 法主要用了啥: Python3 Appium Allure-pytest Pytest Appium 不常见却好用的方法 Appium 直接执行 adb shell 方法 Appium 启动时增加 --relaxed-security 参数 Appium 即可执行类似adb shell的方法 appium -p 4…

短视频账号搭建之Banner图和视频封面

前面在我赢小禾呈序里学了账号名称、头像和个人简介设置&#xff0c;今天把账号搭建的最后两部分一起公开&#xff1a; banner图是你主页上面的这个主图。 同样它的存在可以有三个作用&#xff1a; 第一个作用比较简单&#xff0c;就是让你的主页更好看。 听起来太简单了&am…

【软件测试】测试人在团队中没地位?怎么办?为什么会出现这样的问题?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 为什么会出现这样的…

Linux 学习之:如何让代码在后台保持运行

文章目录nohup 命令使用场景使用方法nohup ... &nohup ... > train.log 2>&1 &结束进程参考文章nohup 命令 使用场景 比如我要在服务器里运行如下代码来训练我的深度学习模型&#xff1a; python train.py但是这样运行你一旦合上笔记本电脑或者换个工作环…

java版商城多商家入驻商城 直播带货商城 电子商务

一个好的SpringCloudSpringBoot b2b2c 电子商务平台涉及哪些技术、运营方案&#xff1f;以下是我结合公司的产品做的总结&#xff0c;希望可以帮助到大家&#xff01; 搜索体验小程序&#xff1a;海哇 1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家…

vxe table 虚拟滚动 表格每一行的高度不一致 出现空白

今天在做表格数据时&#xff0c;发现滚动表格会出现空白区域&#xff0c;如图所示 虚拟滚动表格每一行的高度不一致, 导致表格滚动时出现空白区域 然后在查阅资料时发现有设置:row-config"{height: 70}"这种 &#xff0c;试过发现不行 以下这个不可行 <vxe-grid…

论文常用 | FineBI v6.0 新图表 | 箱形图

箱形图&#xff08;Box-plot&#xff09;又称为盒须图、盒式图或箱线图&#xff0c;是一种用作显示一组数据分散情况资料的统计图&#xff0c;因形状如箱子而得名。在各种领域也经常被使用&#xff0c;常见于品质管理。它主要用于反映原始数据分布的特征&#xff0c;还可以进行…

突破重围,攻“新”为上!凯里亚德与郁锦香酒店以创新势能获投资者青睐

近日&#xff0c;汇聚国内众多投资人的锦江酒店(中国区)品牌沙龙会烟台站顺利举行。本次沙龙活动以“齐风鲁韵 锦绘未来”为主题&#xff0c;锦江酒店(中国区)旗下众多优秀品牌共同亮相。凯里亚德酒店与郁锦香酒店在本次活动中向投资人展示了在如今复杂多变的酒店市场中如何以强…

载波层叠调制在多电平变换器及两电平变换器中的应用

1. 载波层叠调制在MMC中的应用 载波层叠调制在MMC中应用广泛。通过上下桥臂的调制波和多个载波进行比较&#xff0c;得到每个桥臂应该投入的模块数。如下图所示&#xff0c;上下桥臂各有4个模块&#xff0c;每个模块的电容电压是uc&#xff0c;直流侧电压是4uc。A相下桥臂的调制…

Qt 模型视图编程之 ItemDataRole

背景 Qt 中的模型视图架构是用来实现大量数据的存储、处理及其显示的&#xff0c;主要原理是将数据的存储与显示分离&#xff1a;模型定义了标准接口对数据进行访问&#xff1b;视图通过标准接口获取数据并定义显示方式&#xff1b;模型使用信号与槽机制通知视图数据变化。 Q…

C语言百日刷题第十四天

前言 今天是刷题第14天&#xff0c;放弃不难&#xff0c;但坚持一定很酷~ 临近期末&#xff0c;集中把模拟卷的编程题都刷一下 C语言百日刷题第十四天前言模拟题&#xff08;一&#xff09;1.设计程序实现比较两数大小2.排序成绩模拟题&#xff08;二&#xff09;1.求最大值…

力扣(LeetCode)138. 复制带随机指针的链表(C++)

模拟 第一趟遍历&#xff0c;在结点的右侧复制映射。第二趟遍历&#xff0c;复制 randomrandomrandom。第三趟遍历&#xff0c;将链表中的映射结点取出作为新链表。 初始链表如图①。 有必要说明&#xff0c;原结点如 111~555 &#xff0c;映射结点就是 1‘11‘~5‘55‘。 复…