0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

strongerHuang 来源:老吴嵌入式 2023-10-26 10:36 次阅读

转自 | 老吴嵌入式

今天要介绍的开源软件叫 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 的用法

简单例子

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

intmain(void)
{
serial_t*serial;
uint8_ts[]="HelloWorld!";
uint8_tbuf[128];
intret;

serial=serial_new();

/*Open/dev/ttyUSB0withbaudrate115200,anddefaultsof8N1,noflowcontrol*/
if(serial_open(serial,"/dev/ttyUSB0",115200)< 0) {
        fprintf(stderr, "serial_open(): %s
", serial_errmsg(serial));
        exit(1);
    }

    /* Write to the serial port */
    if (serial_write(serial, s, sizeof(s)) < 0) {
        fprintf(stderr, "serial_write(): %s
", 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
", serial_errmsg(serial));
        exit(1);
    }
    printf("read %d bytes: _%s_
", 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:

4d3374ac-73a0-11ee-939d-92fbcf53809c.png


比较有意思的几个 API:

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

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

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

c-periphery 的实现

关键数据

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

Serial:

4d393f36-73a0-11ee-939d-92fbcf53809c.png


I2C:

4d483b1c-73a0-11ee-939d-92fbcf53809c.png


GPIO:

4d599376-73a0-11ee-939d-92fbcf53809c.png


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

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

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

几个关键 API 的实现

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


分配与释放:

4d640e64-73a0-11ee-939d-92fbcf53809c.png

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


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

4d6e816e-73a0-11ee-939d-92fbcf53809c.png


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

4d860334-73a0-11ee-939d-92fbcf53809c.png

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

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


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

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

先定义 backlight_t:

4d8a2324-73a0-11ee-939d-92fbcf53809c.png

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

4d901374-73a0-11ee-939d-92fbcf53809c.png

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


总结

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

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

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5082

    文章

    19104

    浏览量

    304784
  • Linux
    +关注

    关注

    87

    文章

    11292

    浏览量

    209318
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1706

    浏览量

    91498
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136680
  • 开源
    +关注

    关注

    3

    文章

    3309

    浏览量

    42471

原文标题:嵌入式开发神器:硬件外设访问库

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言实现圣诞树!

    2022年12月25号就是圣诞节了!圣诞节当然要有圣诞树了,今天给你们C语言编写
    发表于 12-07 11:18 1910次阅读

    C语言标准的基本使用

    写出看起来专业的C代码,除了规范的变量/函数命名,还需要熟练使用C语言的标准。当为了数组拷贝自己编写
    发表于 09-14 14:04 694次阅读

    STM32标准外设概述

    描述和应用实例,为开发者访问底层硬件提供了中间API,通过使用固件函数,无需深入掌握底层硬件
    发表于 08-05 06:59

    STM32标准外设概述

    描述和应用实例,为开发者访问底层硬件提供了中间API,通过使用固件函数,无需深入掌握底层硬件
    发表于 08-06 06:32

    C语言中使用嵌入式SQL访问Oracle数据的方法

    (Oracle Call Interface简称OCI),通过调用系列OCI函数即可访问数据。我在这里介绍的是前种方法。另外,在本文中
    发表于 12-15 06:35

    编写C语言为基础的DSP程序

    实验2 : 编写C 语言为基础的DSP程序.实验目的1.学习用标准
    发表于 03-17 00:13 3489次阅读
    <b class='flag-5'>编写</b><b class='flag-5'>一</b><b class='flag-5'>个</b>以<b class='flag-5'>C</b><b class='flag-5'>语言</b>为基础的DSP程序

    C语言编写程序实现通过按键使LED灯周期闪烁

    C语言编写程序实现通过按键使LED灯周期闪烁。
    发表于 03-30 16:54 10次下载

    arduino什么语言编程

    Arduino使用C/C++编写程序,虽然C++兼容C语言,但这是两种
    发表于 11-08 15:21 7w次阅读

    基于keil mdk 标准外设的软件开发

    的性能特征。该函数还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了
    发表于 11-24 17:56 1220次阅读
    基于keil mdk 标准<b class='flag-5'>外设</b><b class='flag-5'>库</b>的软件开发

    ASP访问数据的几种常见方式

    Connectivity (ODBC) 兼容的数据和 OLE DB 兼容的数据源。如果您是对数据连接有定了解的脚本
    发表于 03-26 14:46 4次下载

    STM32开发标准外设的详细资料说明

    底层硬件提供了中间API,通过使用固件函数,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个
    发表于 05-09 18:15 1次下载
    STM32开发标准<b class='flag-5'>外设</b><b class='flag-5'>库</b>的详细资料说明

    STM32F10x _硬件I2C读写EEPROM(标准外设版本)

    STM32F10x_硬件I2C读写EEPROM(标准外设版本)
    的头像 发表于 03-25 11:11 1w次阅读
    STM32F10x _<b class='flag-5'>硬件</b>I2<b class='flag-5'>C</b>读写EEPROM(标准<b class='flag-5'>外设</b><b class='flag-5'>库</b>版本)

    CC++编写环境下LabVIEW如何调用动态

    C语言编写的动态链接相比,不同的地方在于extern int “C” __declspec(dllexport) add(int x,i
    发表于 06-11 09:15 7722次阅读
    <b class='flag-5'>C</b>和<b class='flag-5'>C</b>++<b class='flag-5'>编写</b>环境下LabVIEW如何调用动态<b class='flag-5'>库</b>?

    c语言hello world程序编写

    C语言种非常经典和常用的编程语言,而"Hello world"程序是每一个编程入门者的必修课。它是用来熟悉编程
    的头像 发表于 11-26 09:23 2399次阅读

    如何解决C语言中的“访问权限冲突”异常?C语言引发异常原因分析

    些措施来解决和防止其发生。本文将详细介绍C语言访问权限冲突异常的原因以及解决方法。
    的头像 发表于 01-12 16:03 5614次阅读