嵌入式硬件库的基本操作方式与分析

本次要介绍的开源软件是 c-periphery:

https://github.com/vsergeev/c-periphery

一个用 C 语言编写的硬件外设访问库。

我们可以用它来读写 Serial、SPI、I2C 等,非常适合在嵌入式产品上使用。

我们可以基于它优秀的代码框架,不断地扩展出更多的功能模块,最终形成自己产品适用的 Linux 硬件抽象层。


源文件:

$ tree .
├── src
│   ├── gpio.c
│   ├── gpio.h
│   ├── i2c.c
│   ├── i2c.h
│   ├── led.c
│   ├── led.h
│   ├── mmio.c
│   ├── mmio.h
│   ├── pwm.c
│   ├── pwm.h
│   ├── serial.c
│   ├── serial.h
│   ├── spi.c
│   ├── spi.h
│   ├── version.c
│   └── version.h

约 4500 行代码,每个硬件模块的代码都是相对独立,上手难度小。
 

能收获什么?
1、降低硬件编程的门槛;

2、了解 Linux 应用层如何访问 GPIO / I2C / SPI / PWM 等硬件;

3、了解如何对硬件外设进行封装,并提供良好的 API;

4、了解如何将代码封装成库;

5、了解如何为代码编写单元测试程序;

c-periphery 很好地示范了如何在 Linux 平台上进行硬件编程,定义出来的接口即丰富又实用。

另外,它最终输出的是静态库 libperiphery.a,并且为每一个硬件模块功能都编写了单元测试代码,代码质量有保障。
 

c-periphery 的用法

简单例子

我们以最常见的串口读写为例:

int main(void)
{serial_t *serial;uint8_t s[] = "Hello World!";uint8_t buf[128];int ret;serial = serial_new();/* Open /dev/ttyUSB0 with baudrate 115200, and defaults of 8N1, no flow control */if (serial_open(serial, "/dev/ttyUSB0", 115200) < 0) {fprintf(stderr, "serial_open(): %s\n", serial_errmsg(serial));exit(1);}/* Write to the serial port */if (serial_write(serial, s, sizeof(s)) < 0) {fprintf(stderr, "serial_write(): %s\n", serial_errmsg(serial));exit(1);}/* Read up to buf size or 2000ms timeout */if ((ret = serial_read(serial, buf, sizeof(buf), 2000)) < 0) {fprintf(stderr, "serial_read(): %s\n", serial_errmsg(serial));exit(1);}printf("read %d bytes: _%s_\n", ret, buf);serial_close(serial);serial_free(serial);return 0;
}

serial_t 是对串口设备的抽象;

serial_new() 用于创建一个串口设备, 这里只是申请了数据,使用完毕后, 要通过 serial_free() 将其释放掉。

serial_open() 用于初始化串口,设置设备节点、波特率等; 相应地,用 serial_close() 可以关闭串口。

serial_write() 用于给串口发数据,模仿了系统调用 write()。

serial_read() 用于从串口读数据,比系统调用 read() 多了一个 timeout_ms 的参数,有了超时机制后,至少可以避免程序一直阻塞。

这就是一个最简单的基于 c-periphery 的串口示例。即便是嵌入式初学者,基于这些接口,也能轻松地读写串口了。
 

另外,这里只用到了最常用的几个 API。对于串口模块,c-periphery 还有很多实用的 API:


比较有意思的几个 API:

serial_poll() 类似 select(),用于监控串口是否有数据,避免死等;

serial_get/set_xxx() 用于读写串口的属性;

serial_fd() 用于获取文件描述符,有了 fd 就意味这所有 Linux 应用编程的机制都可以使用了。例如我们可以将这个 fd 传递给 libev,然后就能进行事件驱动编程了。
 

c-periphery 的实现

关键数据

c-periphery 里对每个硬件模块封装的方法都是类似,用一个结构体来保存模块所有相关的信息,看下面这几个例子。

Serial:


I2C:


GPIO:


它们的成员变量大多都有文件描述符 fd、用于记录错误状态的 errno / error string,然后再加上一些硬件模块特有的成员变量。

最终库的调用者只会看到 serial_t、i2c_t、gpio_t 这种类似描述符的数据类型,使用时不需要关心内部细节。

后续我们要添加自己的硬件模块时,可以依葫芦画瓢,模仿着定义出属于该硬件的 xxx_t 结构体,然后一步步地为 c-periphery 扩展出新的功能模块。
 

几个关键 API 的实现

我们以 Serial 为例,看下其核心 API 的实现。


分配与释放:

就是在申请分配和释放 serial_t 的内存。


写数据 serial_write() 就是调用 write(),读数据 serial_read() 则是利用 select() 实现了超时的功能:


serial_poll() 则是使用 poll() 来完成 io 监控。

其他硬件模块的实现都是类似的。

到此,c-periphery 的核心实现代码就拆解完毕了。


为 c-periphery 添加新的硬件模块
学以致用,我们按照 c-periphery 的框架,添加背光 Backlight 功能。

Backlight 的控制方法可以参考这篇文章:一个控制背光的命令行小工具。
 

先定义 backlight_t:

然后再实现好下面这些 API:

API 的具体实现代码就不再这里展示了,因为控制背光无非就是读写 /sys/class/backlight/ 内的文件节点,难度不大。


总结

c-periphery 是一个 C 语言编写的硬件访问库,已支持 Serial、I2C、SPI、MMIO、PWM、GPIO 等硬件。约 4500 行代码,每个硬件模块的代码都是相对独立,上手难度小,非常使用在嵌入式 Linux 平台上使用。

另外,我们可以基于它优秀的代码框架,不断地扩展出自己需要的功能模块,最终形成自己产品专用的 Linux 硬件抽象层,绝对的嵌入式开发的利器。

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

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

相关文章

Prometheus接入AlterManager配置邮件告警(基于K8S环境部署)

文章目录 一、配置AlterManager告警发送至邮箱二、Prometheus接入AlterManager配置三、部署PrometheusAlterManager(放到一个Pod中)四、测试告警 注意&#xff1a;请基于 PrometheusGrafana监控K8S集群(基于K8S环境部署)文章之上做本次实验。 一、配置AlterManager告警发送至邮…

C++——特殊类设计

目录 一.不能被拷贝的类 1.C98做法 2.C11做法 二.只能在堆上实例化的类 1.实现方式一 2.实现方式二 三.只能在栈上创建的对象 四.不能被继承的类 1.C98方式 2.C11方式 五.只能创建一个对象的类 1.设计模式 2.单例模式 一.不能被拷贝的类 拷贝只会放在两个场景中&a…

visual studio Qt 开发环境中手动添加 Q_OBJECT 导致编译时出错的问题

问题简述 创建项目的时候&#xff0c;已经添加了类文件&#xff0c;前期认为不需要信号槽&#xff0c;就没有添加宏Q_OBJECT,后面项目需要&#xff0c;又加入了宏Q_OBJECT&#xff0c;但是发现只是添加了一个宏Q_OBJECT&#xff0c;除此之外没有改动其它的代码&#xff0c;原本…

基于springboot实现地方废物回收机构平台管理系统【项目源码+论文说明】

基于springboot实现地方废物回收机构管理系统演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把地方废物回收机构管理与现在网络相结合&#xff0c;利用java技术建设地方废物回收机构管理系统&#xff0c;实现地方废物回收机构的信息化。则对于进一步提高地方废物回收机…

如何提高广告投放转化率?Share Creators 资产库与Appsflyer营销数据的全面结合

如何提高广告投放转化率&#xff1f;Share Creators 资产库与Appsflyer营销数据的全面结合 全球经济进入了低迷期。 营销成本越来越高&#xff0c; 营销需要更务实&#xff0c;注重投入产出比。众所周知&#xff0c;除了渠道、客群画像以外&#xff0c; 优秀的广告设计图&#…

c进阶测试题

选择题 1.请问该程序的输出是多少&#xff08;C&#xff09; #include<stdio.h> int main(){unsigned char i 7;int j 0;for(;i > 0;i - 3){ j;} printf("%d\n", j);return 0; }A. 2 B. 死循环 C. 173 D. 172 首先unsigned char型是不会为负数&#xff…

flask入门(四)前后端数据传输

文章目录 1、flask后端接收来自前端的数据1&#xff09;如果前端提交的方法为POST2&#xff09;如果前段提交的方法是GET 2、flask后端向前端传数据3、案例参考文献 1、flask后端接收来自前端的数据 1&#xff09;如果前端提交的方法为POST 后端接收时的代码&#xff1a; xx…

我试图扯掉这条 SQL 的底裤。只能扯一点点,不能扯多了

之前不是写分页嘛,分页肯定就要说到 limit 关键字嘛。 然后我啪的一下扔了一个链接出来: https://dev.mysql.com/doc/refman/8.0/en/limit-optimization.html 这个链接就是 MySQL 官方文档,这一章节叫做“对 Limit 查询的优化”,针对 limit 和 order by 组合的场景进行了较…

【MySQL】存储引擎

存储引擎 查看存储引擎设置表的存储引擎创建表时指定存储引擎修改表的存储引擎 引擎介绍InnoDB引擎: 具备外键支持的十五存储引擎MyISAM引擎: 主要的非事务处理存储引擎Archive引擎: 用于数据存档Blackhole引擎: 丢弃写操作,读操作返回空内容CSV引擎: 读取数据时,以逗号分隔各个…

redis底层数据结构

总所周知&#xff0c;redis支持五种数据类型String、Hash、List、Set、ZSet。在支持这些复杂数据结构的同时&#xff0c;redis不仅需要保证读写的性能&#xff0c;还能提供各种微操作&#xff0c;比如直接修改Hash字典中的某个field的值&#xff0c;或者直接往ZSet中插入某个值…

Failed to start The nginx HTTP and reverse proxy server.

本章教程主要分享一下&#xff0c;当nginx 启动时&#xff0c;遇到报这个错误时的一个解决问题思路。 目录 1、观察报错信息 2、尝试性解决 1、观察报错信息 根据日志的信息&#xff0c;我们至少可以知道2个比较信息。 1、操作用户执行命令是在非root权限下进行操作的。 2、Ad…

Xcode14创建github远程仓库Token

1.点击Create a Token on GitHub 2.在打开的网页中,登陆GitHub 3.点击生成Token 这是不能为空 4.Token创建成功如下: 5.复制Token到Xcode然后点击Sign In登陆 正在创建远程我仓库 正在将本地仓库代码推入远程仓库 创建成功

C++项目——云备份-②-第三方库认识

文章目录 专栏导读1. json 认识1.1 JSON 数据结构的特点 2. jsoncpp库认识3. json实现序列化案例4. json实现反序列化案例5. bundle文件压缩库认识6. bundle库实现文件压缩案例7.bundle库实现文件解压缩案例8.httplib库认识9. httplib库搭建简单服务器案例10. httplib库搭建简单…

YOLO目标检测——密集人群人头检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;在公共场所&#xff0c;如车站、商场、景区等&#xff0c;可以通过人头目标检测技术来监测人群流量数据集说明&#xff1a;人头检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富标签说明&#xff1a;使用lableimg标注软件标注…

python实现excel的数据提取

一文带你实现excel表格的数据提取 今天记录一下如何使用python提取Excel中符合特定条件的数据 在数据处理和分析的过程中&#xff0c;我们经常需要从Excel表格中提取特定条件下的数据。Python的pandas库为我们提供了方便的方法来进行数据查询和过滤。 Pandas 是 Python 语言…

SELECT COUNT(*) 会造成全表扫描吗?

前言 SELECT COUNT(*)会不会导致全表扫描引起慢查询呢&#xff1f; SELECT COUNT(*) FROM SomeTable 网上有一种说法&#xff0c;针对无 where_clause 的 COUNT(*)&#xff0c;MySQL 是有优化的&#xff0c;优化器会选择成本最小的辅助索引查询计数&#xff0c;其实反而性能…

基于深度学习实现一张单图,一个视频,一键换脸,Colab脚本使用方法,在线版本,普通人也可以上传一张图片体验机器学习一键换脸

基于深度学习实现一张单图,一个视频,一键换脸,Colab脚本使用方法,在线版本,普通人也可以上传一张图片体验机器学习一键换脸。 AI领域人才辈出,突然就跳出一个大佬“s0md3v”,开源了一个单图就可以进行视频换脸的项目。 项目主页给了一张换脸动图非常有说服力,真是一图…

Fiber Golang:Golang中的强大Web框架

揭示Fiber在Go Web开发中的特点和优势 在不断发展的Web开发领域中&#xff0c;选择正确的框架可以极大地影响项目的效率和成功。介绍一下Fiber&#xff0c;这是一款令人印象深刻的Golang&#xff08;Go语言&#xff09;Web框架。以其飞快的性能和强大的特性而闻名&#xff0c;…

【算法训练-动态规划 一】【应用DP问题】零钱兑换、爬楼梯、买卖股票的最佳时机I、打家劫舍

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【动态规划】&#xff0c;使用【数组】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&…

VR虚拟现实技术在法院技能培训中的应用

开展法治宣传教育&#xff0c;是全面贯彻落实科学发展观的重要决策&#xff0c;也是保障和促进经济设备会发展和实施“十一五”规划的内在要求。为了让全民法治文化宣传深入人们群众中&#xff0c;突破性地采用VR虚拟现实、web3d开发和三维仿真技术&#xff0c;开发线上法治文化…