单片机如何写好一个模块的驱动文件

搞单片机,MCU:STM32/GD32/HC32,通讯模组:4G/WIFI/BT/433,总线:USB/CAN/K/232/485,各种常见的传感器,都接触过。

一开始学习单片机的时候没有形成很好的编写习惯,如LED点亮/熄灭/闪烁控制都是有一个功能新增一个函数,外面直接调用这个函数。

其实模块化的东西,就应该模块化。如同Linux的底层驱动,都是先注册一个设备类型,实现初始化、读写和控制函数。对外部只提供一个结构体指针(里面包含函数指针)。

这里就记录和分享一下驱动框架:

首先是.c和.h文件结构

  1. Include files
  2. Local type definitions ('typedef')
  3. Local pre-processor symbols/macros ('#define')
  4. Local variable definitions ('static')
  5. Function implementation - global ('extern') and local ('static')

.c文件应该包含以上5个部分,.h文件包含4部分(不包括static)

static:代码中内部实现的子函数、不需要外部访问的变量,都应该限制其作用域,只允许在本文件内访问。包含因代码逻辑处理或运算而定义的宏定义和宏函数也应该在本文件内定义。

其次是typedef和define

  1. typedef
    在.h文件中应该根据设备的硬件结构和配置寄存器定义一个合理的结构体,让外部调用函数指针。

如W25Q256的驱动文件可以分成2层:

一是整体驱动文件,二是功能驱动文件。

在功能驱动的.h文件中

定义了如下这么一个结构体,

typedef struct {

void (*Delay)(uint32_t);

void (*Init)(void);

void (*DeInit)(void);

void (*Active)(void);

void (*Inactive)(void);

int32_t (*Trans)(const uint8_t *, uint32_t);

int32_t (*Receive)(uint8_t *, uint32_t);

} stc_w25qxx_ll_t;

其对应的驱动函数,

int32_t W25QXX_Init(const stc_w25qxx_ll_t *pstcW25qxxLL);

int32_t W25QXX_DeInit(const stc_w25qxx_ll_t *pstcW25qxxLL);

int32_t W25QXX_GetManDeviceId(const stc_w25qxx_ll_t *pstcW25qxxLL, uint16_t *pu16ID);

可以这样总结:

1、功能驱动的.c文件基本是不包含静态变量或全局变量的 ,只关注于实现W25Q256对应的寄存器功能,如基本读写/擦除/获取ID/初始化等函数。借鉴下来,对于硬件模块,功能驱动文件应该只关注实现细分子功能。而不应该将上层应用的实现直接放到驱动层里面来。

2、功能驱动的.c文件的函数都要有一个底层驱动的结构体指针传进来 ,底层驱动无非就是初始化、读写、控制,将之封装成结构体函数指针,也尽量不包含静态变量或全局变量。供上层调用。

3、这个功能驱动文件应该是一个只需要include stdint.h、string.h的代码文件,就是模块化。

  1. define
    对于底层驱动:
    1、应该是尽量减少define定义,只关注于实现基础函数。
    2、需要实现define定义的:
    1)硬件的规格参数
    2)宏函数

对于功能驱动:

1、应该包含硬件寄存器相关的定义

2、包含相关硬件规格定义

多少个C文件

最简单的,一个C文件搞定。只提供结构体指针来调用内部的接口。

这样能做的就是,合理的设计和拆分子功能,不要出现多个接口代码类似的情况。

当然.h文件要包含必要的宏定义、宏函数和错误码、状态定义等等

两个C文件,这样搞一般是有多型号、微差别的模块,可以将功能驱动抽象出来。

如W25QXX系列,差别在于存储容量、单元大小会有不同。

这个功能驱动文件是一个标准的c文件,理论上可以在不同平台和环境使用。

最终实现是在整体驱动文件中:实现底层驱动函数和结构体指针,调用功能驱动文件实现功能。

三个C文件,则是更进一步的细分:

1、底层驱动文件

只实现底层驱动文件,属于更换编译器、芯片平台时需要修改的文件。

2、功能驱动文件

同上。逻辑抽象好之后基本不需要修改的文件。

3、整体驱动文件

引用底层驱动和功能驱动,实现上层应用需要的接口函数。

由此及彼

  1. CAN驱动
    1)一个CAN驱动首先是根据CAN ISO11898等协议,制定和拆分功能驱动文件。实现如总线初始化、总线接收配置,发送和接收回调、读取接收等函数。
    2)根据芯片平台的不同,制作底层驱动文件,实现基本驱动接口
    3)根据上层应用,或简化,或逻辑组合调用,实现上层功能接口
    这样,
    老项目换主控芯片,只需要修改底层驱动文件;
    相同芯片开发新应用,只需要修改上层功能接口;
相关推荐
厉昱辰44 分钟前
一文读懂单片机的串口
单片机·嵌入式硬件
沐欣工作室_lvyiyi1 小时前
基于STM32的智能生态水族箱系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·毕业设计·水族箱
7yewh2 小时前
自制红外热像仪(二) MLX90640移植 RP2040 STM32 ESP32
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机视觉
冰糖雪莲IO3 小时前
【江协STM32】10-2/3 MPU6050简介、软件I2C读写MPU6050
stm32·单片机·嵌入式硬件
1101 11013 小时前
STM32-笔记39-SPI-W25Q128
笔记·stm32·嵌入式硬件
Leiditech__3 小时前
汽车氛围灯静电浪涌的难点
嵌入式硬件·汽车·硬件工程
云山工作室5 小时前
基于单片机的客车载客状况自动检测系统(论文+源码)
单片机·嵌入式硬件·毕业设计·毕设
2301_805962937 小时前
NRF24L01模块STM32通信-发送端
stm32·单片机·嵌入式硬件
LeoZY_9 小时前
CH348结合开源ModBus协议组成串口温度采集服务器
运维·笔记·嵌入式硬件·开源
我想学LINUX9 小时前
【STM32+QT项目】基于STM32与QT的智慧粮仓环境监测与管理系统设计(完整工程资料源码)
stm32·嵌入式硬件·qt·毕业设计·课程设计·项目开发