STM32-CAN配置与库函数解析,实现环回模式通信

news/2024/4/25 13:58:24/文章来源:https://blog.csdn.net/weixin_46251230/article/details/129152356

STM32-CAN配置与库函数解析

CAN总线介绍:https://blog.csdn.net/weixin_46251230/article/details/129147612

STM32-CAN控制器介绍:https://blog.csdn.net/weixin_46251230/article/details/129150872

STM32CubeMx配置

因为bxCAN是挂载在APB1总线上的,所以设置APB1总线的时钟为36M

在这里插入图片描述

选择CAN接口进行配置

在这里插入图片描述

勾选主CAN模式,这里并不是主机的意思

在这里插入图片描述

配置位时间参数

根据STM32参考手册里位时间特性的介绍,来配置最小时间单位Tq

在这里插入图片描述

在这里插入图片描述

在位时间参数里可以配置分频系数,这个系数没有下拉列表,需要自己写,APB1 36MHz时钟来到这里经过分频再给后面使用,根据实际通信速度来配置,例如可以设置为4分频,那36MHz/4 = 9MHz

同步段因为固定为1个时间单元,所以不用配置

根据采样点最好在一个位的50% ~ 80%位置采样,所以时间段1可以配置长一点,其范围为1到16个时间单元,这里可根据下拉列表选择11个时间单元

时间段2的设置就要注意不要让总和超过最大Tq数,因为同步段+时间段1+时间段2的Tq数范围是8 ~ 25个,不过配置工具已经把参数规定好了,所以不用担心超出的问题,这里可以设置为6个时间单元,则会自动计算出一个位占用的时间(Time for one Bit)为2000ns

计算过程

36MHz/4 = 9MHz,因为同步段(1个Tq)+时间段1(11个Tq)+时间段2(6个Tq)=18个Tq

所以 9MHz/18 = 0.5MHz,即每一个Tq的频率就是0.5MHz,转为时间就为 1/0.5MHz = 1/500000Hz = 0.000002s = 2us = 2000ns

而2000ns的速率就是500KHz

重新同步跳跃宽度(SJW)可设置范围是1 ~ 4个时间单元,这里可以选择2

配置基础参数

在这里插入图片描述

接收FIFO锁定模式:选择Enable(锁定)时,当接收FIFO满时,新接收到的报文就丢弃,软件可以读到FIFO中最早收到的3个报文。

​ 选择Disable(不锁定)时,那么FIFO中最后收到的报文就被新报文所覆盖。这样,最新收到的报文不会被丢弃掉。

发送FIFO优先级:未使能就按邮箱序号进行发送

配置工作模式

在这里插入图片描述

正常模式就需要两个或更多的实验板来进行通信

环回模式就只使用一个实验板就可以测试通信

本次实验使用环回模式

在这里插入图片描述

NVIC中断配置

在这里插入图片描述

CAN发送使用轮询的方式,接收就用RX0中断方式

GPIO配置

在这里插入图片描述

因为CAN收发器的STB接到了单片机的PC13引脚,所以将PC13配置为推挽输出模式

在这里插入图片描述

上面配置完就可以生成Keil工程进行代码编写

生成的CAN初始化函数如下:

void MX_CAN_Init(void)
{hcan.Instance = CAN1;hcan.Init.Prescaler = 4;hcan.Init.Mode = CAN_MODE_LOOPBACK;hcan.Init.SyncJumpWidth = CAN_SJW_2TQ;hcan.Init.TimeSeg1 = CAN_BS1_11TQ;hcan.Init.TimeSeg2 = CAN_BS2_6TQ;hcan.Init.TimeTriggeredMode = DISABLE;hcan.Init.AutoBusOff = DISABLE;hcan.Init.AutoWakeUp = DISABLE;hcan.Init.AutoRetransmission = DISABLE;hcan.Init.ReceiveFifoLocked = DISABLE;hcan.Init.TransmitFifoPriority = DISABLE;if (HAL_CAN_Init(&hcan) != HAL_OK){Error_Handler();}
}

CAN使用到的库函数介绍

1、配置过滤器

CAN_FilterTypeDef结构体就是过滤器的一些参数设置

HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig);

2、发送数据

CAN_TxHeaderTypeDef结构体是对发送报文进行组帧,aData数组存放着要发送的数据,pTxMailbox指针是返回控制器使用了哪个邮箱进行发送

HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);

3、中止发送请求

HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes);

4、获取空邮箱的个数

uint32_t HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *hcan);

5、接收数据

RxFifo指定用于接收报文的FIFO缓存,CAN_RxHeaderTypeDef结构体定义接收报文的格式,aData数组存放接收到的报文

HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);

6、获取接收FIFO满的个数

uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *hcan, uint32_t RxFifo);

CAN通信实现(环回模式)

CAN.h

进行宏定义,定义结构体类型

//发送接收状态宏定义
#define CAN_SEND_OK     0
#define CAN_SEND_FAIL   1#define CAN_REC_OK      0
#define CAN_REC_FAIL    1//定义结构体类型
typedef struct
{uint32_t uiOperate_Mode;        //操作模式uint8_t ucRec_Flag;             //接收标志位uint8_t ucSend_Buf[8];          //发送缓存uint8_t ucRec_Buf[8];           //接收缓存void (*CAN_Init)(void);void (*CAN_Config)(void);uint8_t (*CAN_Send_Msg)(uint8_t* pSend_Buf,uint8_t LEN);uint8_t (*CAN_Rec_Msg)(uint8_t* pRec_Buf);}CAN_Test_T;/* extern variables-----------------------------------------------------------*/
extern CAN_Test_T CAN_Test;

CAN.c

配置过滤器并启动CAN

/*** @name   CAN_Config* @brief  CAN配置* @param  None* @retval None   */
static void CAN_Config(void)
{//CAN过滤器参数配置CAN_FilterTypeDef CAN_FilterTypeDefSture;CAN_FilterTypeDefSture.FilterBank  = 0;                             //配置过滤器0(F1共有14个,0-13)CAN_FilterTypeDefSture.FilterScale = CAN_FILTERSCALE_16BIT;         //配置为16位过滤器CAN_FilterTypeDefSture.FilterMode  = CAN_FILTERMODE_IDMASK;         //屏蔽位模式//ID号为0x00,屏蔽位为0x00,说明任何ID都接收CAN_FilterTypeDefSture.FilterIdLow      = 0x00;                     //FR1CAN_FilterTypeDefSture.FilterMaskIdLow  = 0x00;CAN_FilterTypeDefSture.FilterIdHigh     = 0x00;                     //FR2CAN_FilterTypeDefSture.FilterMaskIdHigh = 0x00;   CAN_FilterTypeDefSture.FilterFIFOAssignment = CAN_FILTER_FIFO0;     //过滤器0关联到FIFO0CAN_FilterTypeDefSture.FilterActivation = ENABLE;                   //激活过滤器0CAN_FilterTypeDefSture.SlaveStartFilterBank = 14;//启动过滤器if(HAL_CAN_ConfigFilter(&hcan,&CAN_FilterTypeDefSture) != HAL_OK){printf("CAN配置过滤器成功!");System.Error_Handler();}//使能FIFO0接收到一个新报文中断,具体为FIFO0的挂起中断if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK){printf("CAN使能FIFO0接收到一个新报文中断");System.Error_Handler();}//启动CANif(HAL_CAN_Start(&hcan) != HAL_OK){printf("CAN启动失败!");System.Error_Handler();}printf("配置成功,CAN成功启动!\r\n");
}

CAN发送报文,可在主函数中调用

/*** @name   CAN_Send_Msg* @brief  CAN发送信息* @param  pSend_Buf:发送缓存指针*          LEN:发送报文长度* @retval CAN_SEND_OK:发送成功*          CAN_SEND_FAIL:发送失败*/
static uint8_t CAN_Send_Msg(uint8_t* pSend_Buf,uint8_t LEN)
{uint8_t i = 0;static uint8_t ucTestData = 0;uint32_t uiTxMailBox;           //接收CAN发送数据成功时返回的邮箱号(0-2)//定义CAN TX消息头参数CAN_TxHeaderTypeDef CAN_TxHeaderTypeDefStrue = {0x88,           //标准标识符-11位0x00,           //拓展标识符-29位CAN_ID_STD,     //设置为标准格式CAN_RTR_DATA,   //设置为数据帧8,              //发送数据的长度 0 ~ 8DISABLE         //不使用捕获时间戳计数器};//判断工作模式if(CAN_Test.uiOperate_Mode == CAN_MODE_LOOPBACK){printf("\r\nCAN工作在环回模式,使用一块实验板来测试\r\n");}else{printf("\r\nCAN工作在正常模式,需要两块以上的实验板才能测试\r\n");}//设置要发送的报文printf("CAN要发送的报文如下:\r\n");for(i=0;i<8;i++){printf("%#.2x ",ucTestData);CAN_Test.ucSend_Buf[i] = ucTestData++;}printf("\r\n");//将消息添加到第一个空闲的Tx邮箱并激活相应的传输要求if(HAL_CAN_AddTxMessage(&hcan,&CAN_TxHeaderTypeDefStrue,pSend_Buf,&uiTxMailBox) != HAL_OK){return CAN_SEND_FAIL;}//通过检查空闲邮箱个数确认是否发送完成Timer6.usDelay_Timer = 0;do{//超时处理if(Timer6.usDelay_Timer >= TIMER_1s){printf("CAN发送超时\r\n");return CAN_SEND_FAIL;}} while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3); //如果3个发送邮箱都不是空闲的话,就说明数据还在发送//发送成功return CAN_SEND_OK;
}

CallBack.c

重写FIFO0挂起中断,接收CAN消息

因为是环回模式,所以主函数中发送的数据会被中断接收,通过HAL_CAN_GetRxMessage函数放到CAN_Test.ucRec_Buf缓存中

/*** @name   HAL_CAN_RxFifo0MsgPendingCallback* @brief  CAN接收FIFO0 挂起中断* @param  *_hcan:CAN结构体指针* @retval None   */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan_)
{//定义CAN Rx消息头参数CAN_RxHeaderTypeDef CAN_RxHeaderTypeDefStrue;//CAN接收消息if(HAL_CAN_GetRxMessage(&hcan,CAN_RX_FIFO0,&CAN_RxHeaderTypeDefStrue,CAN_Test.ucRec_Buf) == HAL_OK){CAN_Test.ucRec_Flag = TRUE;}LED.LED_Fun(LED3,LED_Flip);
}

System.c

主函数中,判断触摸按键1是否按下,是则发送一次数据,通过接收标志位判断中断是否已经完成数据接收,是则打印出数据

/*** @name   Run* @brief  系统运行* @param  None* @retval None   */
static void Run()
{//计数static uint16_t usCAN_Send_OK_Cnt = 0;static uint16_t usCAN_Send_Fail_Cnt = 0;static uint16_t usCAN_Rec_OK_Cnt = 0;//发送数据if(KEY1.KEY_Flag == TRUE){KEY1.KEY_Flag = FALSE;//发送if(CAN_Test.CAN_Send_Msg(CAN_Test.ucSend_Buf,8) == CAN_SEND_OK){printf("CAN发送数据成功次数:%u\r\n",++usCAN_Send_OK_Cnt);}else{printf("CAN发送数据失败次数:%u\r\n",++usCAN_Send_Fail_Cnt);}}//接收数据if(CAN_Test.ucRec_Flag == TRUE){CAN_Test.ucRec_Flag = FALSE;printf("CAN接收数据成功次数:%u\r\n",++usCAN_Rec_OK_Cnt);//打印接收到的数据CAN_Test.CAN_Rec_Msg(CAN_Test.ucRec_Buf); }
}

实验结果

每触摸一次按键,就成功发送一次数据,并成功接收一次数据
在这里插入图片描述

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

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

相关文章

【学习总结】相机与IMU标定一:Kalibr论文

论文&#xff1a;2013IROS论文&#xff0c;Unified Temporal and Spatial Calibration for Multi-Sensor Systems&#xff0c;是Kalibr工具的参考论文之一。介绍了如何进行IMU与相机标定。 参考的一篇资料&#xff1a;知乎&#xff1a;超全汇总&#xff01;多传感器离线/在线时…

新建微服务模块Maven子工程

gitegg-cloud是微服务框架&#xff0c;整体功能是非业务相关的基础功能&#xff0c;在实际业务开发过程中需要新建微服务的业务模块&#xff0c;根据业务的整体规划&#xff0c;设计新建Maven子工程。   下面以常用的电商项目举例新建Maven子工程&#xff0c;电商项目一般包含…

VIIRS-NPP夜间灯光遥感数据下载和预处理

VIIRS-NPP夜间灯光遥感数据下载和预处理 月和年合成产品下载网站 日数据下载网站 一、下载shp掩膜文件 下载好月合成产品后&#xff0c;在这个网站上下载矢量地图&#xff0c; 点击复制按钮&#xff0c;来到这个网站&#xff0c;ctrl v粘贴 点击右上角Export&#xff0c;…

搞懂事件——C# 的event的机制深度理解

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:无尽的折腾后,终于又回到了起点,工控,我来了 !1. 前言 为什么忽然对Event感兴趣了? 因为进入Web时代以后,很少使用它了,忽然想起这个知识点,…

九龙证券|市场化转融资业务试点上线首日平稳运行

2月21日&#xff0c;中国证券金融股份有限公司&#xff08;下称“中证金融”&#xff09;商场化转融资事务试点迎来首个买卖日。全天该事务试点平稳运转&#xff0c;商场化转融资规模合计10亿元。 业内人士以为&#xff0c;商场化转融资事务形式下&#xff0c;证券公司参加转融…

使用51单片机和DS1302时钟芯片做一个简易的电子时钟

简易的电子时钟实验一、前言二、DS1302模块介绍三、驱动DS1302的代码3.1 初始化DS1302时钟芯片3.2 读取DS1302时钟芯片的时间3.3 设置DS1302时钟芯片的时间3.4 读取DS1302时钟芯片的RAM四、读取DS1302时钟芯片的RAM4.1 发送读取RAM的命令4.2 读取RAM的内容4.3 读取部分单独代码…

[飞桨paddle]1. conda安装paddle环境.模型转换,pytorch->paddlepaddle

“一生费城七六人”1. conda装paddle环境1.1 验证是否装好2. x2paddle2.1 介绍2.2 安装3 模型转换3.1 pt -> onnx3.2 onnx > .pdparams3.2.1 会出现的错误情况3-1. 第一种情况3-2. 第二种情况4. 查看结果问题阐述&#xff1a;将yoloV5项目移至paddle框架下执行时&#xf…

中央一号文件首提“即时零售”,县域掀起消费业态新风潮

经过几年的探索&#xff0c;即时零售已经逐步走向成熟&#xff0c;并开始向三四线城市以及乡镇城市渗透。 过去一年&#xff0c;京东、美团、阿里争先布局即时零售市场&#xff0c;完善即时配送网络、培养用户消费习惯&#xff0c;即时零售订单迎来了骤增。2022年下半年&#…

C/C++每日一练(20230222)

目录 1. 部分复制字符串(★) 2. 按字典顺序排列问题(★★) 3. 地下城游戏(★★★) 附录 动态规划 1. 部分复制字符串 将字符串2小写字母复制到字符串1&#xff1a;编写程序,输入字符串s2,将其中所有小写字母复制到字符串数组strl中。例如&#xff1a;aal1bb22cc33de4AA55…

Java实现多线程有几种方式(满分回答)

目录JDK8 创建的线程的两种方式orcle文档解释方式一&#xff1a;继承Thread类方式二&#xff1a;实现Runnable接口同时用两种的情况其他间接创建方式Callable接口线程池JDK8 创建的线程的两种方式 orcle文档解释 orcle文档&#xff1a;https://docs.oracle.com/javase/8/docs…

九龙证券|银行资本管理办法迎“大修” 信用风险权重法调整优化

1年期AAA中债商业银行同业存单到期收益率 日前迎来“大修”的商业银行本钱办理方法&#xff0c;在债券商场激起“涟漪”——债券商场一改此前平静态势&#xff0c;连续两日跌落。 2月21日&#xff0c;10年期国债收益率较上星期五上行2.9个基点&#xff0c;至2.919%&#xff1b…

Redis学习【10】之Redis主从集群(1)

文章目录一 Redis主从集群搭建1 伪集群搭建与配置1.1.1 分级管理1.1.2 容灾冷处理1.2 主从复制原理1.2.1 主从复制过程1.2.2 数据同步演变过程1.3 哨兵机制实现1.3.1 哨兵机制简介1.3.2 Redis 高可用集群搭建1.3.3 Redis 高可用集群的启动1.3.4 Sentinel 优化配置1.4 哨兵机制原…

Spring中自定义Session管理,Spring Session源码解析

系列文章&#xff1a;Spring Boot学习大纲&#xff0c;可以留言自己想了解的技术点 目录 系列文章&#xff1a;Spring Boot学习大纲&#xff0c;可以留言自己想了解的技术点 1、session是什么&#xff1f; 1>session在哪里&#xff1f; 2>服务器怎么知道每次说话的是…

H5盲盒抽奖系统源码

盲盒抽奖系统4.0&#xff0c;带推广二维码防洪炮灰功能和教程。 支持微信无限回调登录 标价就是源码价格&#xff0c;vuetp5框架编写&#xff0c;H5网页&#xff0c;前后端分离 此源码为正规开发&#xff0c;正版产品已申请软著。 开源无加密无授权&#xff0c;可以二开使用…

霍尔元件的应用

霍尔传感器有3个pin&#xff0c;分别是 正极 负极和输出pin。 输出pin接电阻和发光二极管。电阻起限流作用。 电源接5.5v直流电。当拿一个磁铁的N极靠近霍尔元件时&#xff0c;二极管越来越亮。当拿S极靠近霍尔元件时&#xff0c;二极管越来越暗。 N极磁场强度定义为正的磁场强…

算法刷题日志——移除元素,双指针

文章目录删除有序数组中的重复项[删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/)移除元素[283. 移动零](https://leetcode.cn/problems/move-zeroes/description/)[844. 比较含退格的字符串](https://leetcode.cn/problem…

Docker之路(3.docker底层原理、和虚拟机VM对比区别)

1.docker run 流程图 2. docker 底层原理 2.1 docker 是怎么工作的&#xff1f; Docker 是一个 Client-Server 结构的系统&#xff0c;Docker的守护进程运行在主机上&#xff0c; 通过Socket从客户端访问&#xff01; DockerServer接收到Docker-Client的指令&#xff0c;就会执…

【Java】Spring的创建和使用

Spring的创建和使用 Spring就是一个包含众多工具方法的IOC容器。既然是容器&#xff0c;那么就具备两个最主要的功能&#xff1a; 将对象存储到容器中从容器中将对象取出来 在Java语言当中对象也叫作Bean。 1. 创建Spring项目 创建一个普通maven项目添加Spring框架支持(spri…

Spring Boot自动装配的原理

Spring Boot自动装配的原理自动装配的实现EnableAutoConfigurationAutoConfigurationImportSelectorSpring Boot中的自动装配&#xff0c;它是Starter的基础&#xff0c;也是Spring Boot的核心。那么什么叫自动装配呢&#xff1f;或者说什么叫装配呢&#xff1f; 简单来说&…

金三银四丨黑蛋老师带你剖析-安全开发岗

作者丨黑蛋在之前呢&#xff0c;我们聊了二进制这块的病毒岗位&#xff0c;漏洞岗位&#xff0c;逆向岗位以及CTF这块的岗位。今天我们就来聊一聊安全开发类的工作岗位。首先网络安全方向中安全开发岗位都有哪些&#xff0c;安全开发主要指安全研发工程师或安全开发工程师&…