嵌入式 C 开发 CAN 通信通用框架设计与实现

目录

框架设计目标

框架整体结构

数据结构设计

核心层实现

硬件抽象层接口

硬件抽象层实现示例(以 STM32 为例)

使用示例

框架扩展建议


前言:

做嵌入式开发,如果没有好的框架以及架构,写出来的程序实时性以及扩展性不满足可维护性以及可移植性,那么程序写的就是失败的,所以强烈建议做嵌入式开发的朋友学习好的框架,学习架构知识!如果觉得认同,可以关注我,可以带你实现高级框架,优美的嵌入式系统框架!

另外,我的资源中上传了一本书:《从入职到架构师,嵌入式软件成长之路》,强烈建议下载阅读,学习如何更好的做架构设计!

正文:                      

CAN(Controller Area Network)通信在嵌入式系统中应用广泛,特别是在汽车电子、工业控制等领域。设计一个通用的 CAN 通信框架可以提高代码复用性和可维护性。

框架设计目标

  1. 硬件无关性:通过抽象层隔离具体硬件实现
  2. 可配置性:支持不同的 CAN 波特率、滤波方式等
  3. 灵活性:支持中断和查询两种工作模式
  4. 易用性:提供简洁的 API 接口
  5. 可扩展性:方便添加新功能和适配新硬件

框架整体结构

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) {
        // 主循环
        // 可以添加其他任务...
    }
}

框架扩展建议

  1. 添加消息队列:为发送和接收添加消息队列,提高实时性
  2. 支持多 CAN 外设:修改框架支持多个 CAN 控制器
  3. 增加诊断功能:添加 CAN 总线诊断和错误统计
  4. 支持 CAN FD:扩展框架支持 CAN FD 协议
  5. 添加消息路由:实现基于 ID 的消息路由功能
  6. 完善测试用例:为框架添加单元测试和集成测试

这个通用框架通过分层设计实现了硬件无关性,用户可以根据需要替换硬件抽象层以适配不同的 MCU,同时保持应用层代码不变,大大提高了代码的可移植性和复用性。

内容概要:本文介绍了ENVI Deep Learning V1.0的操作教程,重点讲解了如何利用ENVI软件进行深度学习模型的训练应用,以实现遥感图像中特定目标(如集装箱)的自动提取。教程涵盖了从数据准备、标签图像创建、模型初始化训练,到执行分类及结果优化的完整流程,并介绍了精度评价通过ENVI Modeler实现一键化建模的方法。系统基于TensorFlow框架,采用ENVINet5(U-Net变体)架构,支持通过点、线、面ROI或分类图生成标签数据,适用于多/高光谱影像的单一类别特征提取。; 适合人群:具备遥感图像处理基础,熟悉ENVI软件操作,从事地理信息、测绘、环境监测等相关领域的技术人员或研究人员,尤其是希望将深度学习技术应用于遥感目标识别的初学者实践者。; 使用场景及目标:①在遥感影像中自动识别和提取特定地物目标(如车辆、建筑、道路、集装箱等);②掌握ENVI环境下深度学习模型的训练流程关键参数设置(如Patch Size、Epochs、Class Weight等);③通过模型调优结果反馈提升分类精度,实现高效自动化信息提取。; 阅读建议:建议结合实际遥感项目边学边练,重点关注标签数据制作、模型参数配置结果后处理环节,充分利用ENVI Modeler进行自动化建模参数优化,同时注意软硬件环境(特别是NVIDIA GPU)的配置要求以保障训练效率。
内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略效果评估体系,涵盖当前企业传播面临的预算、资源、内容效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户和自媒体四类媒体资源的特性、传播优势发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放GEO优化,提升品牌在AI搜索中的权威性可见性;④通过数据驱动评估体系量化品牌影响力销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析工具指南进行系统学习,重点关注媒体适配性策略GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

start_up_go

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值