【STM32CubeMX】F103 BxCAN

news2024/11/14 8:42:21

F103&BxCAN

bxCAN总体描述

  • 有一个增强的过滤机制来处理各种类型的报文此外,应用层任务需要更多CPU时间,因此报文接收所需的实时响应程度需要减轻。

  • 接收FIFO的方案允许,CPU花很长时间处理应用层任务而不会丢失报文。 构筑在底层CAN驱动程序上的高层协议软件,跟CAN控制器之间有高效的接口。

BxCAN与CAN的区别?

  1. 硬件结构:BxCAN是基本扩展CAN(Basic Extended CAN)的缩写,它支持CAN协议2.0A和2.0B。而CAN通常只有一个主控制器。
  2. 功能:BxCAN具有更多的功能,例如时间触发通信模式。在该模式下,CAN硬件的内部定时器被激活,并且被用于产生(发送与接收邮箱的)时间戳,分别存储在CAN_RDTxR/CAN_TDTxR寄存器中。内部定时器在每个CAN位时间累加。内部定时器在接收和发送的帧起始位的采样点位置被采样,并生成时间戳。

功能名词

标识符过滤:在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者乙 广播的形式把报文发送给所有的接收者。节点在接收报文时-根据标识符的值-决定软件是否 需要该报文;如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。

数据结构

  • CAN过滤器配置结构定义

    typedef struct
    {
      uint32_t FilterIdHigh;          // 指定过滤器标识号的高16位,范围0x0000~0xFFFF
      uint32_t FilterIdLow;           // 指定过滤器标识号的低16位,范围0x0000~0xFFFF
      uint32_t FilterMaskIdHigh;      // 用于设置过滤器掩码高16位,范围0x0000~0xFFFF
      uint32_t FilterMaskIdLow;       // 用于设置过滤器掩码低16位,范围0x0000~0xFFFF
      uint32_t FilterFIFOAssignment;  // 指定将分配给过滤器的FIFO(0或1U),该参数可以是@ref CAN_filter_FIFO的值
      uint32_t FilterBank;            // 指定要初始化的筛选器组,对于单个CAN实例(14个专用过滤器组),该参数必须是0~13之间。对于双CAN实例(28个过滤器组共享),该参数必须是0~27之间。
      uint32_t FilterMode;            // 指定要初始化的筛选器模式,列表模式和掩码模式,该参数可以是@ref CAN_filter_mode的值
      uint32_t FilterScale;           // 指定过滤器的规模,该参数可以是@ref CAN_filter_scale的值
      uint32_t FilterActivation;      // 启用或禁用过滤器,该参数可以是@ref CAN_filter_activation的值
      uint32_t SlaveStartFilterBank;  // 为从CAN实例选择启动过滤器组,对于单个CAN实例,此参数没有意义。对于双CAN实例,索引较低的滤波器组分配给主CAN实例,索引较大的滤波器组分配给从CAN实例。该参数必须为0~27之间。
    
    } CAN_FilterTypeDef;
    
  • CAN Tx消息头结构定义

    typedef struct
    {
      uint32_t StdId;    // 指定标准标识符,范围0~0x7FF
      uint32_t ExtId;    // 指定扩展标识符,范围0~0x1FFFFFFF
      uint32_t IDE;      // 指定要传输的消息的标识符类型。该参数可以是@ref CAN_identifier_type
      uint32_t RTR;      // 指定要传输的消息的帧类型。该参数可以是@ref CAN_remote_transmission_request
      uint32_t DLC;      // 指定要传输的帧的长度,范围0~8
      FunctionalState TransmitGlobalTime;	//指定时间戳计数器值是否在开始时捕获在帧传输中,以DATA6和DATA7代替pData[6]和pData[7]发送。@注:必须启用“时间触发通信模式”。@注意:DLC必须被编程为8字节,为了这2字节被发送。可设置为“ENABLE”或“DISABLE”。
    
    } CAN_TxHeaderTypeDef;
    
  • CAN Rx消息头结构定义

    typedef struct
    {
      uint32_t StdId;    	// 指定标准标识符,范围0~0x7FF
      uint32_t ExtId;    	// 指定扩展标识符,范围0~0x1FFFFFFF
      uint32_t IDE;      	// 指定要传输的消息的标识符类型。该参数可以是@ref CAN_identifier_type
      uint32_t RTR;      	// 指定要传输的消息的帧类型。该参数可以是@ref CAN_remote_transmission_request
      uint32_t DLC;      	// 指定要传输的帧的长度,范围0~8
      uint32_t Timestamp; 	//指定在帧接收开始时捕获的时间戳计数器值。@注:必须启用“时间触发通信模式”。该参数必须为0~0xFFFF。
      uint32_t FilterMatchIndex; // 指定匹配接受筛选元素的索引。该参数必须为0~0xFF
    
    } CAN_RxHeaderTypeDef;
    

相关资料

下面图片摘录于STM32F10xxx参考手册(中文)

  • 注意手册里也提醒了,要是想跑CAN总线的化,还需要CAN收发器,MCU只能提供CAN_Rx,CAN_Tx,不要搞混了。

    在这里插入图片描述

  • 这里是过滤器的寄存器的含义图,因为我没找到其它的关于解释过滤器关于CAN中标准的ID的位置到底在哪里,下面两张图就有,比如STID的含义就是CAN协议中的标准ID,而且它也是通过程序也知道它是对应着过滤器结构中FilterIdHigh,FilterIdLow之类的,方便理解下面的程序,为什么要移位。

    在这里插入图片描述

    在这里插入图片描述

  • 这个说实话,没看懂这样的定义是啥,32位的仲裁域?还是标准标识符,怪怪的。但是是手册中唯一,一张有介绍CAN帧的图,所以就顺便截出来了,万一大家有自己的理解。

    在这里插入图片描述

前置配置

  • STM32CubeMX中配置

    在STM32CubeMX中配置,RCC配置使用高速外部晶振,开启USART1,配置PC13为输出模式(点灯),CAN配置(下面附图)其它的省略配置过程。

    在这里插入图片描述

    在这里插入图片描述

  • 配置完后生成,Keil5打开。

相关程序

以下函数都可以写在main.c中,只不过分块写更容易理解。

初始化相关的

// 开启CAN
HAL_CAN_Start(&hcan);

发送相关的

/*
* @描述:CAN发送函数
* @参数:id(CAN发送的ID号)
* @参数:idMode(帧ID号类型选择)
         CAN_ID_STD:标准ID号
         CAN_ID_EXT:扩展ID号
* @参数:*pData(要发送的数据)
* @参数:len(发送的数据长度)
*				 范围 0 ~ 8
* @返回值: 返回0:正常  返回1:异常
*/
uint8_t CAN_SendData(uint32_t id,uint8_t idMode,uint8_t *pData,uint8_t len)
{
	CAN_TxHeaderTypeDef pHeader;
	uint32_t pTxmailbox;
	uint8_t result = 0;
	
	if(idMode == CAN_ID_STD)
	{
		pHeader.StdId = id;   		//标准ID号
		pHeader.IDE = CAN_ID_STD;	//标准ID
	}
	else
	{
		pHeader.ExtId = id;				//扩展ID号
		pHeader.IDE = CAN_ID_STD;	//扩展ID
	}
	
	pHeader.RTR = CAN_RTR_DATA;	//传输数据的帧类型为数据帧
	pHeader.DLC = len>8?8:len;	//发送数据的字节长度,最大为8个字节
	pHeader.TransmitGlobalTime = DISABLE;	//是否要发送时间戳
	
	// CAN发送函数
	if(HAL_CAN_AddTxMessage(&hcan, &pHeader, pData, &pTxmailbox) != HAL_OK)
	{
		return 1;
	}
	return 0;
}

接收相关的

过滤模式:部分ID位数相同也能接收  列表模式:必须是指定ID才能接收

两种模式的程序都在下面,测试时,二选一验证就行了。

  • 列表模式
/*
* @描述:CAN过滤器配置,接收模式采用的是列表模式,
*			  该id不管是标准帧还有扩展帧都适用,因为两个
*				筛选id的寄存器分别写入了它的标准帧和扩展帧
* @参数:id(筛选的ID号)
*/
void CAN_Fliter_Config_IDLIST(uint32_t id)
{
	CAN_FilterTypeDef hcan_filterconfig;
	
	hcan_filterconfig.FilterActivation = CAN_FILTER_ENABLE;		//过滤器使能
	hcan_filterconfig.FilterBank = 0;  												//使用过滤器0
	hcan_filterconfig.FilterMode = CAN_FILTERMODE_IDLIST;			//采用列表模式
	hcan_filterconfig.FilterScale = CAN_FILTERSCALE_32BIT;		//采用32位掩码模式
	hcan_filterconfig.FilterFIFOAssignment = CAN_FilterFIFO0;	//使用FIFO0
	
	hcan_filterconfig.FilterIdHigh =     id << 5;																					//过滤器ID高16位
	hcan_filterconfig.FilterIdLow =      0 | CAN_ID_STD | CAN_RTR_DATA;    								//过滤器ID低16位,CAN_ID_STD(标准ID)、CAN_RTR_DATA(帧类型为数据帧)
	hcan_filterconfig.FilterMaskIdHigh = ((id<<3)>>16)&0xffff;														//过滤器掩码高16位
	hcan_filterconfig.FilterMaskIdLow =  ((id<<3) & 0xffff) | CAN_ID_EXT | CAN_RTR_DATA;	//过滤器掩码低16位,CAN_ID_EXT(扩展ID)、CAN_RTR_DATA(帧类型为数据帧)

	
	hcan_filterconfig.SlaveStartFilterBank = 14; 		//过滤器数量14
	HAL_CAN_ConfigFilter(&hcan,&hcan_filterconfig); //初始化过滤器
	HAL_CAN_Start(&hcan);	//开启CAN
	//开启CAN-FIFO0中断
	HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING);
}
  • 掩码模式
/*
* @描述:CAN过滤器配置,接收模式采用的是掩码模式。
*				掩码模式,对'1'位,不感兴趣,对'0'位必须匹配。
* @参数:id(筛选的ID号)
* @阐述:mask_if(掩码)
*/
void CAN_Fliter_Config_IDMASK(uint32_t id,uint32_t mask_id)
{
	CAN_FilterTypeDef hcan_filterconfig;
	
	hcan_filterconfig.FilterActivation = CAN_FILTER_ENABLE;	//过滤器使能
	hcan_filterconfig.FilterBank = 0;  											//使用过滤器0
	hcan_filterconfig.FilterMode = CAN_FILTERMODE_IDMASK;		//采用掩码模式
	hcan_filterconfig.FilterScale = CAN_FILTERSCALE_32BIT;	//采用32位掩码模式
	hcan_filterconfig.FilterFIFOAssignment = CAN_FilterFIFO0;	//使用FIFO0
	
//	hcan_filterconfig.FilterIdHigh =     (((((uint32_t)id)<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xffff0000)>>16;//过滤器ID高16位,CAN_ID_EXT(扩展ID)、CAN_RTR_DATA(帧类型为数据帧)
//	hcan_filterconfig.FilterIdLow =      (((((uint32_t)id)<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0x0000ffff);    //过滤器ID低16位,CAN_ID_EXT(扩展ID)、CAN_RTR_DATA(帧类型为数据帧)
//	hcan_filterconfig.FilterMaskIdHigh = (mask_id & 0xffff0000)>>16;	//过滤器掩码高16位
//	hcan_filterconfig.FilterMaskIdLow =  mask_id & 0x0000ffff;      	//过滤器掩码低16位
	
	hcan_filterconfig.FilterIdHigh =     id << 5;														//过滤器ID高16位,CAN_ID_EXT(扩展ID)、CAN_RTR_DATA(帧类型为数据帧)
	hcan_filterconfig.FilterIdLow =      0 | CAN_ID_STD | CAN_RTR_DATA;    	//过滤器ID低16位,CAN_ID_EXT(扩展ID)、CAN_RTR_DATA(帧类型为数据帧)
	hcan_filterconfig.FilterMaskIdHigh = 0x00;			//过滤器掩码高16位
	hcan_filterconfig.FilterMaskIdLow =  0x00;      				//过滤器掩码低16位
	
	hcan_filterconfig.SlaveStartFilterBank = 14; 		//过滤器数量14
	HAL_CAN_ConfigFilter(&hcan,&hcan_filterconfig); //初始化过滤器
	HAL_CAN_Start(&hcan);	//开启CAN
	HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING);//开启CAN-FIFO0中断
}

中断回调函数

/*CAN-FIFO0中断回调函数*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)  
{  
    CAN_RxHeaderTypeDef RxHeader;  
    uint8_t RxData[8];				// 存储接收数据
    uint32_t RxDataLength;  	// 数据长度
	
    if(hcan->Instance == CAN1)  
    {  
        // 从FIFO中读取消息  
        if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)  
        {  
            // 处理读取错误 
        }  
        
				// 获取数据长度
        RxDataLength = RxHeader.DLC;  
          
        // 判断是标准帧还是扩展帧,并打印相应的ID和简单的验证下前四个字节的数据
        if(RxHeader.IDE == CAN_ID_STD)  
        {  
          printf("接收到标准ID为:0x%X\r\n", RxHeader.StdId); 
					printf("接收到的数据为:%d %d %d %d\r\n",RxData[0],RxData[1],RxData[2],RxData[3]);
        }  
        else if(RxHeader.IDE == CAN_ID_EXT)  
        {  
					printf("接收到扩展ID为:0x%X\r\n", RxHeader.ExtId);  
					printf("接收到的数据为:%d %d %d %d\r\n",RxData[0],RxData[1],RxData[2],RxData[3]);
        }  		
    }  
}

main.c中主函数片段,该片段中只包含用户需要测试编写的,不包括STM32CubeMX生成的其它初始化。

int main()
{
    uint8_t CAN_Send_Data[] = {8,8,8,8,8,8,8,8};
	int Count = 0;
    HAL_CAN_Start(&hcan);//开启CAN
	CAN_Fliter_Config_IDMASK(0x123,0x000);
    while(1)
    {
        // CAN发送函数
		if(CAN_SendData(0x0123,CAN_ID_STD,CAN_Send_Data,8))
		{
			printf("Send Lose!\r\n");
		}
		else
		{
			printf("SendOK:%d\r\n",Count++);
		}

		// 闪烁LED-运行状态灯
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
		HAL_Delay(500);
    }
}

串口配置(可选),方便观察到调试现象,不一定要用

// 引入该库为了可以使用 printf 函数
#include "stdio.h" 

//避免使用半主机模式
void _sys_exit(int x)
{
	x = x;
}
//标准库需要支持的函数
struct __FILE
{
	int handle;
};
FILE __stdout;

//重定向print
int fputc(int ch, FILE *f)//printf
{
	//HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET); 	//485发送使能端口 没有可去掉
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1,0xffff);  	//发送一个字节的数据到你希望的串口
	//HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET); 	//485发送使能端口 没有可去掉
	return (ch);
}

实验现象

材料:STM32C6T6两块,CAN收发器两块,若干杜邦线,串口模块,ST-LINK下载器,面包板若干块

程序:配置,闪烁LED观察程序运行状态,调用CAN发送程序并用变量计数程序是否发送成功,并用串口打印出来。

在这里插入图片描述

在这里插入图片描述

程序资料

文中演示的程序

链接:https://pan.baidu.com/s/18lqiq-thWXHbma8eLD9ODw  提取码:7qkw

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

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

相关文章

MySQL增量备份与恢复

实验环境 某学校近期在进行期中考试&#xff0c;要求数据库管理员负责一班&#xff0c;二班学生的考试成绩录入&#xff0c;为保证数据的可靠性&#xff0c;数据库管理员在录入学生成绩后均要做数据库备份&#xff0c;并且为了测试备份数据是否可 用&#xff0c;模拟数据丢失故…

柯桥日常英语口语,外贸英语商务英语|英文打电话的常用语

日常生活中&#xff0c;我们常常需要打电话交流。在打电话时说话清楚&#xff0c;使用适当的礼节是很重要的。 如果你太正式&#xff0c;人们在和你说话时&#xff0c;可能会很难感到舒适。如果你太随便&#xff0c;他们可能会认为你很粗鲁&#xff01; 所以&#xff0c;说话的…

Jmeter,提取响应体中的数据:正则表达式、Json提取器

一、正则表达式 1、线程组--创建线程组&#xff1b; 2、线程组--添加--取样器--HTTP请求&#xff1b; 3、Http请求--添加--后置处理器--正则表达式提取器&#xff1b; 4、线程组--添加--监听器--查看结果树&#xff1b; 5、线程组--添加--取样器--调试取样器。 响应体数据…

Disruptor详解,Java高性能内存队列最优解

文章目录 一、Disruptor介绍1、为什么要有Disruptor2、Disruptor介绍3、Disruptor的高性能设计4、RingBuffer数据结构5、等待策略6、Disruptor在日志框架中的应用7、术语 二、Disruptor实战1、引入依赖2、Disruptor构造器3、入门实例&#xff08;1&#xff09;Hello World&…

MATLAB 绘制伯德图之将幅频特性和相频特性分开绘制方法

幅频和相频特性分别在两个图窗&#xff0c;不在一起方便保存&#xff0c;无需再裁剪 clear; close all; k 1; numH 1; denH [1,k]; sysH tf(numH,denH); w logspace(-2,2);[mag, phase] bode(sysH,w);% 幅频特性 loglog(w,squeeze(mag));grid on; % 相频特性 semilogx(…

在springboot中引入参数校验

一、概要 一般我们判断前端传过来的参数&#xff0c;需要对某些值进行判断&#xff0c;是否满足条件。 而springboot相关的参数校验注解&#xff0c;可以解决我们这个问题。 二、快速开始 首先&#xff0c;我用的springboot版本是 3.1.5 引入参数校验相关依赖 <!--1…

数据之美:零售业的变革之道

数据可视化能够为零售业带来令人瞩目的变化。随着零售业务的发展&#xff0c;数据可视化成为了洞察市场、优化运营并提升客户体验的强大工具。下面我就以可视化从业者的视角出发&#xff0c;简单分析一下数据可视化为零售业可能带来的改变。 数据可视化让零售商深入了解消费者行…

邮政快递物流查询,分析筛选出提前签收件

批量查询邮政快递单号的物流信息&#xff0c;将提前签收件分析筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 邮政快递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界面左上角…

从 AST 到代码生成:代码背后的秘密花园(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

JS基础之执行上下文

JS基础之执行上下文 执行上下文顺序执行可执行代码执行上下文栈回顾上文 执行上下文 顺序执行 写个JavaScript的开发者都会有个直观的印象&#xff0c;那就是顺序执行&#xff1a; var foo function(){console.log(foo1) } foo(); //foo1 var foo function(){console.log(…

ES分词查询

全文检索介绍 全文检索的发展过程&#xff1a; 数据库使用SQL语句&#xff1a;select * from table where data like “%检索内容%”出现lucene全文检索工具&#xff08;缺点&#xff1a;暴露的接口相对复杂&#xff0c;且没有效率&#xff09;出现分布式检索服务框架solr&am…

Unity 控制刚体的移动与旋转的方法

在场景创建一个Cube,并添加刚体&#xff0c;如图&#xff1a; 编写脚本&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine;[RequireComponent(typeof(Rigidbody))] public class RibRotate : MonoBehaviour {//private Vector3 mo…

计算机如何看待内存

计算机如何看待内存&#xff1b; 对象在内存中如何表示&#xff0c;如何操纵对象&#xff1b;

国产数据库适配-达梦(DM)

1、通用性 达梦数据库管理系统兼容多种硬件体系&#xff0c;可运行于X86、X64、SPARC、POWER等硬件体系之上。DM各种平台上的数据存储结构和消息通信结构完全一致&#xff0c;使得DM各种组件在不同的硬件平台上具有一致的使用特性。 达梦数据库管理系统产品实现了平台无关性&…

智能优化算法应用:基于蝠鲼觅食算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝠鲼觅食算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝠鲼觅食算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝠鲼觅食算法4.实验参数设定5.算法结果6.…

Knowledge Distillation from A Stronger Teacher(NeurIPS 2022)论文解读

paper&#xff1a;Knowledge Distillation from A Stronger Teacher official implementation&#xff1a;https://github.com/hunto/dist_kd 前言 知识蒸馏通过将教师的知识传递给学生来增强学生模型的性能&#xff0c;我们自然会想到&#xff0c;是否教师的性能越强&…

vue的slot插槽详解

目录 一、基本用法 在上面的例子中&#xff0c;我们在子组件中定义了一个插槽&#xff0c;然后在父组件中使用标签&#xff0c;并在标签内部放置了一个 标签作为插槽的内容。当父组件被渲染时&#xff0c;插槽的内容将被替换为实际传入的内容。 二、具名插槽 在上面的例子…

Java集合--Map

1、Map集合概述 在Java的集合框架中&#xff0c;Map为双列集合&#xff0c;在Map中的元素是成对以<K,V>键值对的形式存在的&#xff0c;通过键可以找对所对应的值。Map接口有许多的实现类&#xff0c;各自都具有不同的性能和用途。常用的Map接口实现类有HashMap、Hashtab…

初识GroovyShell

文章目录 前言一、GroovyShell二、maven三、解决方案四、关键代码4.1 数据库配置表(pg)4.2 入参4.3 分页查询 总结 前言 项目背景&#xff1a;查询多个表的数据列表和详情&#xff0c;但不想创建过多的po、dao、resp等项目文件。 一、GroovyShell Apache Groovy是一种强大的…

关于ctf反序列化题的一些见解([MRCTF2020]Ezpop以及[NISACTF 2022]babyserialize)

这里对php反序列化做简单了解 在PHP中&#xff0c;序列化用于存储或传递 PHP 的值的过程中&#xff0c;同时不丢失其类型和结构。 serialize&#xff08;&#xff09; 函数序列化对象后&#xff0c;可以很方便的将它传递给其他需要它的地方&#xff0c;且其类型和结构不会改变…