在STM32F7上实现CAN总线收发队列

下面我将提供一个完整的STM32F7 CAN总线通信实现方案,包含中断驱动的收发队列管理。

1. CAN总线配置与队列定义
can_bus.h

#ifndef __CAN_BUS_H
#define __CAN_BUS_H#include "stm32f7xx_hal.h"
#include "queue.h"// CAN消息结构体
typedef struct {uint32_t id;        // 标准ID或扩展IDuint8_t data[8];    // 数据域uint8_t len;        // 数据长度uint8_t format;     // 0-标准帧, 1-扩展帧uint8_t type;       // 0-数据帧, 1-远程帧
} CAN_Msg_t;// CAN队列配置
#define CAN_TX_QUEUE_SIZE  16
#define CAN_RX_QUEUE_SIZE  32// CAN总线初始化
void CAN_Init(CAN_HandleTypeDef *hcan);// 消息发送/接收接口
bool CAN_SendMsg(CAN_HandleTypeDef *hcan, CAN_Msg_t *msg);
bool CAN_GetMsg(CAN_Msg_t *msg);// 中断处理函数
void CAN_IRQHandler(CAN_HandleTypeDef *hcan);#endif

can_bus.c

#include "can_bus.h"// CAN发送接收队列
static Queue_t can_tx_queue;
static Queue_t can_rx_queue;// CAN初始化
void CAN_Init(CAN_HandleTypeDef *hcan) {// 初始化队列Queue_Init(&can_tx_queue);Queue_Init(&can_rx_queue);// CAN过滤器配置 (示例配置)CAN_FilterTypeDef filter;filter.FilterBank = 0;filter.FilterMode = CAN_FILTERMODE_IDMASK;filter.FilterScale = CAN_FILTERSCALE_32BIT;filter.FilterIdHigh = 0x0000;filter.FilterIdLow = 0x0000;filter.FilterMaskIdHigh = 0x0000;filter.FilterMaskIdLow = 0x0000;filter.FilterFIFOAssignment = CAN_RX_FIFO0;filter.FilterActivation = ENABLE;filter.SlaveStartFilterBank = 14;HAL_CAN_ConfigFilter(hcan, &filter);// 启动CANHAL_CAN_Start(hcan);// 激活CAN中断HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_TX_MAILBOX_EMPTY);
}// 发送CAN消息 (非阻塞)
bool CAN_SendMsg(CAN_HandleTypeDef *hcan, CAN_Msg_t *msg) {// 尝试直接发送if (HAL_CAN_GetTxMailboxesFreeLevel(hcan) > 0) {CAN_TxHeaderTypeDef tx_header;tx_header.StdId = msg->format ? 0 : msg->id;tx_header.ExtId = msg->format ? msg->id : 0;tx_header.IDE = msg->format ? CAN_ID_EXT : CAN_ID_STD;tx_header.RTR = msg->type ? CAN_RTR_REMOTE : CAN_RTR_DATA;tx_header.DLC = msg->len;tx_header.TransmitGlobalTime = DISABLE;uint32_t mailbox;if (HAL_CAN_AddTxMessage(hcan, &tx_header, msg->data, &mailbox) == HAL_OK) {return true;}}// 发送邮箱已满,放入队列return Queue_SendToBackFromISR(&can_tx_queue, msg);
}// 接收CAN消息 (非阻塞)
bool CAN_GetMsg(CAN_Msg_t *msg) {return Queue_Receive(&can_rx_queue, msg);
}// CAN中断处理
void CAN_IRQHandler(CAN_HandleTypeDef *hcan) {// RX FIFO0中断处理if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV0) || __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF0)) {__HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV0 | CAN_FLAG_FF0);}if (__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_MSG_PENDING)) {CAN_RxHeaderTypeDef rx_header;CAN_Msg_t msg;if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, msg.data) == HAL_OK) {msg.id = rx_header.IDE == CAN_ID_STD ? rx_header.StdId : rx_header.ExtId;msg.len = rx_header.DLC;msg.format = rx_header.IDE == CAN_ID_EXT;msg.type = rx_header.RTR == CAN_RTR_REMOTE;Queue_SendToBackFromISR(&can_rx_queue, &msg);}}// TX邮箱空中断处理if (__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_TX_MAILBOX_EMPTY)) {// 检查并发送队列中的消息while (HAL_CAN_GetTxMailboxesFreeLevel(hcan) > 0) {CAN_Msg_t msg;if (Queue_Receive(&can_tx_queue, &msg)) {CAN_SendMsg(hcan, &msg);  // 递归调用,但不会无限递归} else {break;}}}
}

2. 主程序集成示例
main.c

#include "stm32f7xx_hal.h"
#include "can_bus.h"CAN_HandleTypeDef hcan1;int main(void) {HAL_Init();SystemClock_Config();// CAN初始化hcan1.Instance = CAN1;hcan1.Init.Prescaler = 6;hcan1.Init.Mode = CAN_MODE_NORMAL;hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;hcan1.Init.TimeSeg1 = CAN_BS1_13TQ;hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;hcan1.Init.TimeTriggeredMode = DISABLE;hcan1.Init.AutoBusOff = DISABLE;hcan1.Init.AutoWakeUp = DISABLE;hcan1.Init.AutoRetransmission = ENABLE;hcan1.Init.ReceiveFifoLocked = DISABLE;hcan1.Init.TransmitFifoPriority = DISABLE;HAL_CAN_Init(&hcan1);CAN_Init(&hcan1);while (1) {// 接收处理CAN_Msg_t rx_msg;if (CAN_GetMsg(&rx_msg)) {// 处理接收到的CAN消息// ...}// 示例:周期发送测试消息static uint32_t last_tick = 0;if (HAL_GetTick() - last_tick > 1000) {last_tick = HAL_GetTick();CAN_Msg_t tx_msg;tx_msg.id = 0x123;tx_msg.len = 8;tx_msg.format = 0; // 标准帧tx_msg.type = 0;   // 数据帧for (int i = 0; i < 8; i++) {tx_msg.data[i] = i;}CAN_SendMsg(&hcan1, &tx_msg);}// 其他任务...}
}// CAN中断服务函数
void CAN1_RX0_IRQHandler(void) {CAN_IRQHandler(&hcan1);
}void CAN1_TX_IRQHandler(void) {CAN_IRQHandler(&hcan1);
}

3. 关键实现细节说明
双队列设计:

发送队列(can_tx_queue):缓存待发送消息

接收队列(can_rx_queue):缓存接收到的消息

中断驱动机制:

接收中断:当FIFO收到消息时触发,将消息存入接收队列

发送中断:当发送邮箱空闲时触发,从发送队列取出消息发送

流量控制:

当CAN控制器发送邮箱满时,消息暂存到发送队列

当接收队列满时,新消息将被丢弃(可根据需求修改)

性能优化:

直接使用HAL库提供的邮箱状态检查

在中断中只做必要的最小操作

扩展性考虑:

支持标准帧和扩展帧

支持数据帧和远程帧

可轻松扩展为多CAN总线支持

4. 实际应用建议

  1. 错误处理增强:
// 在CAN_Init中添加错误中断使能
HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING |CAN_IT_TX_MAILBOX_EMPTY |CAN_IT_ERROR |CAN_IT_BUSOFF |CAN_IT_LAST_ERROR_CODE);
  1. 诊断功能:
// 添加CAN状态监控
typedef struct {uint32_t tx_count;uint32_t rx_count;uint32_t tx_queue_full;uint32_t rx_queue_full;uint32_t errors;
} CAN_Stats_t;// 在中断处理中更新统计信息
  1. 多帧传输支持:
// 对于长消息,可以实现分段/重组逻辑
#define CAN_MTU 8  // CAN最大传输单元typedef struct {uint32_t id;uint16_t total_len;uint16_t offset;uint8_t data[64];  // 假设最大支持64字节数据
} CAN_LongMsg_t;

这个实现提供了完整的CAN总线通信框架,您可以根据具体应用需求进行调整和扩展。

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

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

相关文章

【例3.5】位数问题(信息学奥赛一本通-1313)

【题目描述】 在所有的N位数中&#xff0c;有多少个数中有偶数个数字3?由于结果可能很大&#xff0c;你只需要输出这个答案对12345取余的值。 【输入】 读入一个数N(N≤1000)。 【输出】 输出有多少个数中有偶数个数字3。 【输入样例】 2 【输出样例】 73 【题解代码】 #incl…

pyQt学习笔记——Qt资源文件(.qrc)的创建与使用

Qt资源文件&#xff08;.qrc&#xff09;的创建与使用 1. 选择打开资源2. 创建新资源3. 添加资源文件夹4. 选择要加载的图片文件5. 编译resource.qrc文件6. 替换PySlide6为PyQt57. 其他说明 1. 选择打开资源 在Qt项目中&#xff0c;可以通过windowIcon点击选择打开资源。 2. 创…

光电效应及普朗克常数的测定数据处理 Python实现

内容仅供参考&#xff0c;如有错误&#xff0c;欢迎指正&#xff0c;如有疑问&#xff0c;欢迎交流。 因为我不会Excel所以只能用Python来处理 祝大家早日摆脱物理实验的苦海 用到的一些方法 PCHIP &#xff08;分段三次埃尔米特插值多项式&#xff09; 因为实验时记录的数…

2025最新3个wordpress好用的主题

红色大气的wordpress企业主题&#xff0c;适合服务行业的公司搭建企业官方网站使用。是一款专为中小企业和个人开发者设计的WordPress主题&#xff0c;旨在提供专业的网站构建解决方案。 通过此WordPress主题&#xff0c;用户可以轻松创建和维护一个专业的企业网站&#xff0c…

OLLVM 增加 CC++ 字符串加密功能

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 前言 当我们如果没有对字符串进行加密&#xff0c;使用 IDA 反汇编一下 so 可以看到 C 代码中的字符串就直接暴露了。 字符串加密原理 sobf.c #include <…

桑福德·韦尔策划美国捷运公司收购南美银行案例分析

桑福德韦尔(Sanford I. Weill)在1981年策划美国捷运公司(American Express)以5.5亿美元收购南美贸易发展银行所属外国银行机构的案例中,展现了其作为战略家与执行者的双重能力。这一交易的流程和韦尔的具体行为可从以下六个关键环节解析: 一、战略定位与目标筛选 战略目标…

人工智能与区块链融合:开启数字信任新时代

引言 在当今数字化飞速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;与区块链技术正以前所未有的速度改变着我们的生活和工作方式。AI以其强大的数据处理和智能决策能力&#xff0c;为各行业带来了效率的飞跃&#xff1b;而区块链则以其去中心化、不可篡改的特性…

自动化逆向框架使用(Objection+Radare2)

1. 工具链架构与核心优势 1.1 动静结合逆向体系 graph LR A[动态分析] -->|Objection实时Hook| B[关键点定位] B --> C[行为数据捕获] D[静态分析] -->|Radare2深度解析| E[控制流重建] E --> F[漏洞模式识别] B --> F C --> F 组合优势对比&…

流式ETL配置指南:从MySQL到Elasticsearch的实时数据同步

流式ETL配置指南&#xff1a;从MySQL到Elasticsearch的实时数据同步 场景介绍 假设您运营一个电商平台&#xff0c;需要将MySQL数据库中的订单、用户和产品信息实时同步到Elasticsearch&#xff0c;以支持实时搜索、分析和仪表盘展示。传统的批处理ETL无法满足实时性要求&…

Docker-Volume数据卷详讲

Docker数据卷-Volume 一&#xff1a;Volume是什么&#xff0c;用来做什么的 当删除docker容器时&#xff0c;容器内部的文件就会跟随容器所销毁&#xff0c;在生产环境中我们需要将数据持久化保存&#xff0c;就催生了将容器内部的数据保存在宿主机的需求&#xff0c;volume …

单片机和微控制器知识汇总——《器件手册--单片机、数字信号处理器和可编程逻辑器件》

目录 四、单片机和微控制器 4.1 单片机(MCU/MPU/SOC) 一、定义 二、主要特点 三、工作原理 四、主要类型 五、应用领域 六、选型与设计注意事项 七、发展趋势 4.2 数字信号处理器(DSP/DSC) ​编辑​编辑 一、定义 二、工作原理 三、结构特点 四、应用领域 五、选型与设计注…

macOS 安装 Miniconda

macOS 安装 Miniconda 1. Quickstart install instructions2. 执行3. shell 上初始化 conda4. 关闭 终端登录用户名前的 base参考 1. Quickstart install instructions mkdir -p ~/miniconda3 curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o…

高数下---8.1平面与直线

目录 平面的确定 直线的确定 若要求某一直线或平面就根据要素来求。 例题 平面中的特殊情况 平面中的解题思路 直线的解题思路 平面的确定 两要素 一 一点 二 倾斜角 即法向量 点法式 可化为一般式 Ax By Cz D 0; (A,B,C) 即法向量&#xff1b; 改变D 即…

CMS迁移中SEO优化整合步骤详解

内容概要 在CMS迁移过程中&#xff0c;系统化的规划与执行是保障SEO排名稳定性的核心。首先需明确迁移流程的关键阶段&#xff0c;包括数据备份、URL适配、元数据同步及安全配置等环节。其中&#xff0c;数据备份不仅需覆盖原始数据库与静态资源&#xff0c;还需验证备份文件的…

存储过程、存储函数与触发器详解(MySQL 案例)

存储过程、存储函数与触发器详解&#xff08;MySQL 案例&#xff09; 一、存储过程&#xff08;Stored Procedure&#xff09; 定义 存储过程是预先编译好并存储在数据库中的一段 SQL 代码集合&#xff0c;可以接收参数、执行逻辑操作&#xff08;如条件判断、循环&#xff09;…

Python:进程间的通信,进程的操作队列

进程间的队列&#xff1a; 队列的基本操作&#xff1a; 入队&#xff1a;将数据放到队列尾部 出队&#xff1a;从队列的头部取出一个元素 maxsize&#xff1a;队列中能存放数据个数的上限(整数)&#xff0c;一旦达到上限插入会导致阻塞&#xff0c;直到队列中的数据被消费掉 …

【C++初阶】--- 类与对象(中)

1.类的默认成员函数 默认成员函数就是⽤⼾没有显式实现&#xff0c;编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类&#xff0c;我们不写的情况下编译器会默认⽣成以下6个默认成员函数&#xff0c;我们主要需要掌握前4个&#xff0c;后两个了解以下即可&#xff0c;默认…

python处理音频相关的库

1 音频信号采集与播放 pyaudio import sys import pyaudio import wave import timeCHUNK 1024 FORMAT pyaudio.paInt16 CHANNELS 1#仅支持单声道 RATE 16000 RECORD_SECONDS 3#更改录音时长#录音函数&#xff0c;生成wav文件 def record(file_name):try:os.close(file_…

[M模拟] lc2711. 对角线上不同值的数量差(对角线遍历+前后缀分解)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;2711. 对角线上不同值的数量差 前置题&#xff1a; [M模拟] lc3446. 按对角线进行矩阵排序(对角线遍历公式推导模板题) 矩形的对角线遍历的基础题。 题单&#xff1a; 待补充 2. 题目解析 2025年03月25日…

设计一个基于机器学习的光伏发电功率预测模型,以Python和Scikit - learn库为例

下面为你设计一个基于机器学习的光伏发电功率预测模型&#xff0c;以Python和Scikit - learn库为例。此模型借助历史气象数据和光伏发电功率数据来预测未来的光伏发电功率。 模型设计思路 数据收集&#xff1a;收集历史气象数据&#xff08;像温度、光照强度、湿度等&#xf…