目录
前言:
做嵌入式开发,如果没有好的框架以及架构,写出来的程序实时性以及扩展性不满足可维护性以及可移植性,那么程序写的就是失败的,所以强烈建议做嵌入式开发的朋友学习好的框架,学习架构知识!如果觉得认同,可以关注我,可以带你实现高级框架,优美的嵌入式系统框架!
另外,我的资源中上传了一本书:《从入职到架构师,嵌入式软件成长之路》,强烈建议下载阅读,学习如何更好的做架构设计!
正文:
CAN(Controller Area Network)通信在嵌入式系统中应用广泛,特别是在汽车电子、工业控制等领域。设计一个通用的 CAN 通信框架可以提高代码复用性和可维护性。
框架设计目标
- 硬件无关性:通过抽象层隔离具体硬件实现
- 可配置性:支持不同的 CAN 波特率、滤波方式等
- 灵活性:支持中断和查询两种工作模式
- 易用性:提供简洁的 API 接口
- 可扩展性:方便添加新功能和适配新硬件
框架整体结构
CAN通信框架
├── 应用层(用户接口)
├── 核心层(消息处理、队列管理)
└── 硬件抽象层(HAL)
└── 具体硬件实现
数据结构设计
首先定义 CAN 消息结构体和框架所需的核心数据结构:
// can.h
#ifndef _CAN_H_
#define _CAN_H_
#include <stdint.h>
#include <stdbool.h>
// CAN消息结构体
typedef struct {
uint32_t id; // 消息ID
uint8_t data[8]; // 数据内容
uint8_t len; // 数据长度(1-8)
bool is_extended; // 是否为扩展帧
bool is_remote; // 是否为远程帧
} CanMsgTypeDef;
// CAN状态枚举
typedef enum {
CAN_STATE_RESET = 0, // 重置状态
CAN_STATE_READY, // 就绪状态
CAN_STATE_BUSY, // 忙碌状态
CAN_STATE_ERROR // 错误状态
} CanStateTypeDef;
// CAN波特率枚举
typedef enum {
CAN_BAUD_125K = 0, // 125Kbps
CAN_BAUD_250K, // 250Kbps
CAN_BAUD_500K, // 500Kbps
CAN_BAUD_1000K // 1000Kbps
} CanBaudRateTypeDef;
// 消息接收回调函数类型
typedef void (*CanRxCallbackFunc)(CanMsgTypeDef *msg);
// CAN句柄结构体
typedef struct {
void *hw_handle; // 硬件句柄
CanStateTypeDef state; // 状态
CanBaudRateTypeDef baud_rate; // 波特率
CanRxCallbackFunc rx_callback; // 接收回调函数
// 其他需要的成员...
} CanHandleTypeDef;
// 函数声明
bool CAN_Init(CanHandleTypeDef *hcan, CanBaudRateTypeDef baud_rate);
bool CAN_DeInit(CanHandleTypeDef *hcan);
bool CAN_SendMessage(CanHandleTypeDef *hcan, CanMsgTypeDef *msg);
bool CAN_RegisterRxCallback(CanHandleTypeDef *hcan, CanRxCallbackFunc callback);
CanStateTypeDef CAN_GetState(CanHandleTypeDef *hcan);
uint32_t CAN_GetError(CanHandleTypeDef *hcan);
#endif /* _CAN_H_ */
核心层实现
核心层负责消息处理和提供 API 接口:
// can.c
#include "can.h"
#include "can_hal.h"
// 初始化CAN控制器
bool CAN_Init(CanHandleTypeDef *hcan, CanBaudRateTypeDef baud_rate) {
if (hcan == NULL) return false;
hcan->state = CAN_STATE_RESET;
hcan->baud_rate = baud_rate;
hcan->rx_callback = NULL;
// 调用硬件抽象层初始化函数
if (!CAN_HAL_Init(hcan)) {
hcan->state = CAN_STATE_ERROR;
return false;
}
hcan->state = CAN_STATE_READY;
return true;
}
// 反初始化CAN控制器
bool CAN_DeInit(CanHandleTypeDef *hcan) {
if (hcan == NULL || hcan->state == CAN_STATE_RESET) return false;
// 调用硬件抽象层反初始化函数
if (!CAN_HAL_DeInit(hcan)) {
return false;
}
hcan->state = CAN_STATE_RESET;
return true;
}
// 发送CAN消息
bool CAN_SendMessage(CanHandleTypeDef *hcan, CanMsgTypeDef *msg) {
if (hcan == NULL || msg == NULL || hcan->state != CAN_STATE_READY) {
return false;
}
if (msg->len < 1 || msg->len > 8) {
return false;
}
hcan->state = CAN_STATE_BUSY;
// 调用硬件抽象层发送函数
bool result = CAN_HAL_SendMessage(hcan, msg);
hcan->state = CAN_STATE_READY;
return result;
}
// 注册接收回调函数
bool CAN_RegisterRxCallback(CanHandleTypeDef *hcan, CanRxCallbackFunc callback) {
if (hcan == NULL) return false;
hcan->rx_callback = callback;
return true;
}
// 获取CAN状态
CanStateTypeDef CAN_GetState(CanHandleTypeDef *hcan) {
if (hcan == NULL) return CAN_STATE_ERROR;
return hcan->state;
}
// 获取错误代码
uint32_t CAN_GetError(CanHandleTypeDef *hcan) {
if (hcan == NULL) return 0xFFFFFFFF;
return CAN_HAL_GetError(hcan);
}
// 硬件抽象层回调函数,用于接收中断
void CAN_HAL_RxCallback(CanHandleTypeDef *hcan, CanMsgTypeDef *msg) {
if (hcan != NULL && hcan->rx_callback != NULL && msg != NULL) {
// 调用用户注册的回调函数
hcan->rx_callback(msg);
}
}
硬件抽象层接口
硬件抽象层定义了与具体硬件无关的接口,需要针对不同 MCU 进行实现:
// can_hal.h
#ifndef _CAN_HAL_H_
#define _CAN_HAL_H_
#include "can.h"
// 硬件抽象层函数声明
bool CAN_HAL_Init(CanHandleTypeDef *hcan);
bool CAN_HAL_DeInit(CanHandleTypeDef *hcan);
bool CAN_HAL_SendMessage(CanHandleTypeDef *hcan, CanMsgTypeDef *msg);
uint32_t CAN_HAL_GetError(CanHandleTypeDef *hcan);
// 硬件抽象层回调函数,由具体硬件实现调用
void CAN_HAL_RxCallback(CanHandleTypeDef *hcan, CanMsgTypeDef *msg);
#endif /* _CAN_HAL_H_ */
硬件抽象层实现示例(以 STM32 为例)
// can_hal_stm32.c
#include "can_hal.h"
#include "stm32f4xx_hal.h"
// STM32 CAN硬件初始化
bool CAN_HAL_Init(CanHandleTypeDef *hcan) {
if (hcan == NULL) return false;
// 分配STM32 CAN句柄
CAN_HandleTypeDef *stm32_can = (CAN_HandleTypeDef*)malloc(sizeof(CAN_HandleTypeDef));
if (stm32_can == NULL) return false;
// 初始化STM32 CAN外设
stm32_can->Instance = CAN1; // 假设使用CAN1
stm32_can->Init.Mode = CAN_MODE_NORMAL;
stm32_can->Init.AutoBusOff = DISABLE;
stm32_can->Init.AutoRetransmission = ENABLE;
stm32_can->Init.ReceiveFifoLocked = DISABLE;
stm32_can->Init.TimeTriggeredMode = DISABLE;
stm32_can->Init.TransmitFifoPriority = DISABLE;
// 根据选择的波特率配置位时序
switch (hcan->baud_rate) {
case CAN_BAUD_125K:
stm32_can->Init.Prescaler = 48;
stm32_can->Init.SyncJumpWidth = CAN_SJW_1TQ;
stm32_can->Init.TimeSeg1 = CAN_BS1_8TQ;
stm32_can->Init.TimeSeg2 = CAN_BS2_3TQ;
break;
case CAN_BAUD_250K:
// 配置250K波特率的位时序
// ...
break;
// 其他波特率配置...
default:
free(stm32_can);
return false;
}
if (HAL_CAN_Init(stm32_can) != HAL_OK) {
free(stm32_can);
return false;
}
// 配置过滤器
CAN_FilterTypeDef can_filter;
can_filter.FilterBank = 0;
can_filter.FilterMode = CAN_FILTERMODE_IDMASK;
can_filter.FilterScale = CAN_FILTERSCALE_32BIT;
can_filter.FilterIdHigh = 0x0000;
can_filter.FilterIdLow = 0x0000;
can_filter.FilterMaskIdHigh = 0x0000;
can_filter.FilterMaskIdLow = 0x0000;
can_filter.FilterFIFOAssignment = CAN_RX_FIFO0;
can_filter.FilterActivation = ENABLE;
can_filter.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(stm32_can, &can_filter) != HAL_OK) {
HAL_CAN_DeInit(stm32_can);
free(stm32_can);
return false;
}
// 启动CAN
if (HAL_CAN_Start(stm32_can) != HAL_OK) {
HAL_CAN_DeInit(stm32_can);
free(stm32_can);
return false;
}
// 启用接收中断
if (HAL_CAN_ActivateNotification(stm32_can, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
HAL_CAN_Stop(stm32_can);
HAL_CAN_DeInit(stm32_can);
free(stm32_can);
return false;
}
hcan->hw_handle = stm32_can;
return true;
}
// STM32 CAN硬件反初始化
bool CAN_HAL_DeInit(CanHandleTypeDef *hcan) {
if (hcan == NULL || hcan->hw_handle == NULL) return false;
CAN_HandleTypeDef *stm32_can = (CAN_HandleTypeDef*)hcan->hw_handle;
// 停止CAN
HAL_CAN_Stop(stm32_can);
// 反初始化CAN
HAL_CAN_DeInit(stm32_can);
// 释放内存
free(stm32_can);
hcan->hw_handle = NULL;
return true;
}
// STM32 CAN发送消息
bool CAN_HAL_SendMessage(CanHandleTypeDef *hcan, CanMsgTypeDef *msg) {
if (hcan == NULL || hcan->hw_handle == NULL || msg == NULL) return false;
CAN_HandleTypeDef *stm32_can = (CAN_HandleTypeDef*)hcan->hw_handle;
CAN_TxHeaderTypeDef tx_header;
uint32_t tx_mailbox;
// 配置发送头部
tx_header.StdId = msg->is_extended ? 0 : msg->id;
tx_header.ExtId = msg->is_extended ? msg->id : 0;
tx_header.RTR = msg->is_remote ? CAN_RTR_REMOTE : CAN_RTR_DATA;
tx_header.IDE = msg->is_extended ? CAN_ID_EXT : CAN_ID_STD;
tx_header.DLC = msg->len;
tx_header.TransmitGlobalTime = DISABLE;
// 发送消息
if (HAL_CAN_AddTxMessage(stm32_can, &tx_header, msg->data, &tx_mailbox) != HAL_OK) {
return false;
}
// 等待发送完成
uint32_t timeout = 100000;
while (HAL_CAN_GetTxMailboxesFreeLevel(stm32_can) != 3 && timeout--);
return timeout > 0;
}
// 获取STM32 CAN错误
uint32_t CAN_HAL_GetError(CanHandleTypeDef *hcan) {
if (hcan == NULL || hcan->hw_handle == NULL) return 0xFFFFFFFF;
CAN_HandleTypeDef *stm32_can = (CAN_HandleTypeDef*)hcan->hw_handle;
return stm32_can->ErrorCode;
}
// STM32 CAN接收中断回调
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
CanMsgTypeDef msg;
CAN_RxHeaderTypeDef rx_header;
// 读取接收消息
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, msg.data) == HAL_OK) {
// 转换为通用消息格式
msg.id = rx_header.IDE == CAN_ID_EXT ? rx_header.ExtId : rx_header.StdId;
msg.len = rx_header.DLC;
msg.is_extended = (rx_header.IDE == CAN_ID_EXT);
msg.is_remote = (rx_header.RTR == CAN_RTR_REMOTE);
// 查找对应的CanHandleTypeDef
// 实际应用中需要维护一个映射表
CanHandleTypeDef *can_handle = /* 从hcan找到对应的CanHandleTypeDef */;
// 调用硬件抽象层回调函数
if (can_handle != NULL) {
CAN_HAL_RxCallback(can_handle, &msg);
}
}
}
使用示例
// main.c
#include "can.h"
#include <stdio.h>
// CAN句柄
CanHandleTypeDef hcan;
// 接收回调函数
void can_rx_callback(CanMsgTypeDef *msg) {
printf("Received CAN message: ID=0x%X, len=%d\n", msg->id, msg->len);
// 处理接收到的消息...
}
int main(void) {
// 初始化CAN,波特率500K
if (!CAN_Init(&hcan, CAN_BAUD_500K)) {
printf("CAN initialization failed!\n");
while (1); // 初始化失败,停机
}
// 注册接收回调函数
CAN_RegisterRxCallback(&hcan, can_rx_callback);
// 发送测试消息
CanMsgTypeDef tx_msg;
tx_msg.id = 0x123;
tx_msg.is_extended = false;
tx_msg.is_remote = false;
tx_msg.len = 4;
tx_msg.data[0] = 0x11;
tx_msg.data[1] = 0x22;
tx_msg.data[2] = 0x33;
tx_msg.data[3] = 0x44;
if (CAN_SendMessage(&hcan, &tx_msg)) {
printf("Message sent successfully!\n");
} else {
printf("Failed to send message!\n");
}
while (1) {
// 主循环
// 可以添加其他任务...
}
}
框架扩展建议
- 添加消息队列:为发送和接收添加消息队列,提高实时性
- 支持多 CAN 外设:修改框架支持多个 CAN 控制器
- 增加诊断功能:添加 CAN 总线诊断和错误统计
- 支持 CAN FD:扩展框架支持 CAN FD 协议
- 添加消息路由:实现基于 ID 的消息路由功能
- 完善测试用例:为框架添加单元测试和集成测试
这个通用框架通过分层设计实现了硬件无关性,用户可以根据需要替换硬件抽象层以适配不同的 MCU,同时保持应用层代码不变,大大提高了代码的可移植性和复用性。
1477

被折叠的 条评论
为什么被折叠?



