当前位置: 首页 > news >正文

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

搞单片机,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)根据上层应用,或简化,或逻辑组合调用,实现上层功能接口
    这样,
    老项目换主控芯片,只需要修改底层驱动文件;
    相同芯片开发新应用,只需要修改上层功能接口;

相关文章:

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

搞单片机,MCU:STM32/GD32/HC32,通讯模组:4G/WIFI/BT/433,总线:USB/CAN/K/232/485,各种常见的传感器,都接触过。 一开始学习单片机的时候没有形成很好的编写习惯,如LED点亮/熄灭/闪烁…...

【C++笔记】C++多态

【C笔记】C多态 一、多态的概念及实现1.1、什么是多态1.2、实现多态的条件1.3、实现继承与接口继承1.4、多态中的析构函数1.5、抽象类 二、多态的实现原理 一、多态的概念及实现 1.1、什么是多态 多态的概念: 在编程语言和类型论中,多态(英…...

不想改代码!这样实现Reverse Sync测量时间同步精度

TSN的时间同步精度,指被测时钟与主时钟的最大偏差。在设备的组网过程中,最大的困难就是保证期望的时间同步精度。主时钟仅负责将自身的时间分发出去,难以判断其他设备的同步效果;此外,若在网络中某处发生了同步故障&am…...

【webrtc】 对视频质量的码率控制的测试与探索

目录 环境设置 transport-cc goog-remb (webrtc中的两种码率算法) 修改成remb算法 测试 效果 后续 可参考工程 环境设置 要到meshx上操作 telnet 112 然后执行factory_env show |grep meshx_ip 之后telnet meshx_ip 用户名admin 密码****.119 执行一下r…...

2003 - Can‘t connect to MysQL server on ‘39.108.169.0‘ (10060 “Unknown error“)

问题描述 某天和往常一样启动java项目,发现数据库出问题了,然后打开navicat,发现数据库的链接都连接不上, 一点击就会弹出报错框: 然后就各种上网搜索。 解决方案 上网查了一些解决方案,大部分都是说看…...

Python算法——选择排序

选择排序(Selection Sort)是一种简单的排序算法,它的基本思想是在未排序的部分中选择最小(或最大)的元素,然后将其放在已排序部分的末尾。选择排序不同于冒泡排序,它不需要反复交换元素&#xf…...

从「码农」到管理者,E人程序员的十年蜕变

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 封面 / 姝琦Midjourney 产品统筹 / bobo 场地支持 / 声湃轩北京录音间 当我们谈论程序员创业时,常常会首先想到一些传统观念认为的挑战:沟通技巧不佳、逻…...

ant Java任务的jvmargs属性和<jvmarg>内嵌元素

ant的Java任务可以在运行Apache Ant的Java虚拟机内、或者启用另外的Java虚拟机运行一个Java类。 可以使用java任务的jvmargs属性,设置传递给在新进程中的java虚拟机的参数。但当java任务的fork禁用的时候,jvmargs属性会被忽略。jvmargs这个属性已经被废…...

XML External Entity-XXE-XML实体注入

XML 实体? XML 实体允许定义标签,在解析 XML 文档时这些标签将被内容替换。一般来说,实体分为三种类型: 内部实体 外部实体 参数实体。 必须在文档类型定义(DTD)中创建实体 一旦 XML 文档被解析器处理,它将js用定义的常量“Jo Smith”替换定义的实体。正如您所看到…...

生态扩展Spark Doris Connector

生态扩展Spark Doris Connector doris官网去查找相匹配的spark spark的安装: tar -zxvf spark-3.1.2-bin-hadoop3.2.tgzmv spark-3.1.2-bin-hadoop3.2 /opt/sparkspark环境配置:vim /etc/profile export SPARK_HOME/opt/spark export PATH$PATH:$SPAR…...

构建 hive 时间维表

众所周知 hive 的时间处理异常繁琐且在一些涉及日期的统计场景中会写较长的 sql,例如:周累计、周环比等;本文将使用维表的形式降低时间处理的复杂度,提前计算好标准时间字符串未来可能需要转换的形式。 一、表设计 结合业务场景常…...

Pycharm安装jupyter和d2l

安装 jupyter: jupyter是d2l的依赖库,没有它就用不了d2l pycharm中端输入pip install jupyter安装若失败则: 若网速过慢,则更改镜像源再下载: pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ pip …...

虹科案例 | AR内窥镜手术应用为手术节约45分钟?

相信医疗从业者都知道,在手术室中有非常多的医疗器械屏幕,特别是内窥镜手术室中医生依赖这些内窥镜画面来帮助病患进行手术。但手术室空间有限,屏幕缩放位置相对固定,在特殊场景下医生观看内窥镜画面时无法关注到病患的状态。这存…...

纳米银线 纳米银纳米线 平均直径: 50-100nm

(西)纳米银线 (安)含量(%):99.9 (瑞)平均直径: 50-100nm (20nm 30nm 60nm ) (禧)长度:10um …...

力扣labuladong——一刷day15

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣92. 反转链表 II二、力扣206. 反转链表 前言 一、力扣92. 反转链表 II /*** Definition for singly-linked list.* public class ListNode {* int…...

【开题报告】基于微信小程序的母婴商品仓储管理系统的设计与实现

1.研究背景 母婴商品是指专门为婴幼儿和孕产妇提供的各类产品,如婴儿奶粉、尿布、奶瓶、洗护用品等。随着社会经济的发展和人们对婴幼儿健康关注度的提高,母婴商品市场呈现出快速增长的趋势。同时,电子商务的兴起和互联网技术的发展&#xf…...

Faraday库

require faraday# 创建Faraday对象,使用作为代理服务器 proxy_host huake proxy_port 1111 faraday Faraday.new(:proxy > { :host > proxy_host, :port > proxy_port })# 使用Faraday对象发送GET请求到https://www.dianping.com/ response faraday.get…...

【原创】java+swing+mysql校园论坛管理系统设计与实现

摘要: 随着互联网技术的不断发展,论坛作为一种信息交流和互动的平台,在学校中发挥着越来越重要的作用。校园论坛管理系统是为了方便学校管理论坛、提高论坛的互动性和用户体验而设计的一款系统。一般的论坛网站都是B/S架构,也就是…...

endnote调整参考文献

endnote调整参考文献 1. 2. 3.自定义GBT7714!!!...

chap认证带客户端IP分配案例

PPP协议两边的网段可以不在同一个网段,因为数据链路帧用0xff表示帧,不用arp,所以可以不同网段。 R1: aaa local-user test password cipher admin local-user test service-type ppp interface Serial4/0/0 link-protocol ppp pp…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

ESP32读取DHT11温湿度数据

芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异&#xff…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...