嵌入式系统应用-第六章 操作系统(RTOS)之I/O设备模型介绍

6 操作系统(RTOS)之I/O口

绝大部分的嵌入式系统都包括一些 I/O(Input/Output,输入 / 输出)设备,例如仪器上的数据显示
屏、工业设备上的串口通信、数据采集设备上用于保存数据的 Flash 或 SD 卡,以及网络设备的以太网接口等,都是嵌入式系统中容易找到的 I/O 设备例子。
本章主要介绍 RT-Thread 如何对不同的 I/O 设备进行管理,读完本章,我们会了解 RT-Thread 的 I/O
设备模型,并熟悉 I/O 设备管理接口的不同功能。
RT-Thread 提供了一套简单的 I/O 设备模型框架,如下图所示,它位于硬件和应用程序之间,共分成
三层,从上到下分别是 I/O 设备管理层、设备驱动框架层、设备驱动层。
在这里插入图片描述
RT-Thread 提供了一套简单的 I/O 设备模型框架,如下图所示,它位于硬件和应用程序之间,共分成
三层,从上到下分别是 I/O 设备管理层、设备驱动框架层、设备驱动层。
I/O 设备管理层实现了对设备驱动程序的封装。应用程序通过 I/O 设备层提供的标准接口访问底层设
备,设备驱动程序的升级、更替不会对上层应用产生影响。这种方式使得设备的硬件操作相关的代码能够独立于应用程序而存在,双方只需关注各自的功能实现,从而降低了代码的耦合性、复杂性,提高了系统的可靠性。

6.1 设备注册介绍

设备驱动框架层是对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出
来,将不同部分留出接口,由驱动程序实现。
设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。它负责创建和注册 I/O 设备,对于操作逻辑简单的设备,可以不经过设备驱动框架层,直接将设备注册到 I/O 设备管理器中,使用序列图如下图所示,主要有以下 2 点:
• 设 备 驱 动 根 据 设 备 模 型 定 义, 创 建 出 具 备 硬 件 访 问 能 力 的 设 备 实 例, 将 该 设 备 通 过rt_device_register() 接口注册到 I/O 设备管理器中。
• 应用程序通过 rt_device_find() 接口查找到设备,然后使用 I/O 设备管理接口来访问硬件。

在这里插入图片描述
对于另一些设备,如看门狗等,则会将创建的设备实例先注册到对应的设备驱动框架中,再由设备驱
动框架向 I/O 设备管理器进行注册,主要有以下几点:

  • 看门狗设备驱动程序根据看门狗设备模型定义,创建出具备硬件访问能力的看门狗设备实例,并将该 看门狗设备通过 rt_hw_watchdog_register() 接口注册到看门狗设备驱动框架中。
  • 看门狗设备驱动框架通过 rt_device_register() 接口将看门狗设备注册到 I/O 设备管理器中应用程序通过 I/O设备管理接口来访问看门狗设备硬件。
    在这里插入图片描述

6.2 I/O 设备模型

RT-Thread 的设备模型是建立在内核对象模型基础之上的,设备被认为是一类对象,被纳入对象管理
器的范畴。每个设备对象都是由基对象派生而来,每个具体设备都可以继承其父类对象的属性,并派生出其私有属性,下图是设备对象的继承和派生关系示意图。
在这里插入图片描述

6.3 I/O 设备类型

RT-Thread 支持多种 I/O 设备类型,主要设备类型如下所示:

RT_Device_Class_Char /* 字 符 设 备 /
RT_Device_Class_Block /
块 设 备 /
RT_Device_Class_NetIf /
网 络 接 口 设 备 /
RT_Device_Class_MTD /
内 存 设 备 /
RT_Device_Class_RTC /
RTC 设 备 /
RT_Device_Class_Sound /
声 音 设 备 /
RT_Device_Class_Graphic /
图 形 设 备 /
RT_Device_Class_I2CBUS /
I2C 总 线 设 备 /
RT_Device_Class_USBDevice /
USB device 设 备 /
RT_Device_Class_USBHost /
USB host 设 备 /
RT_Device_Class_SPIBUS /
SPI 总 线 设 备 /
RT_Device_Class_SPIDevice /
SPI 设 备 /
RT_Device_Class_SDIO /
SDIO 设 备 /
RT_Device_Class_Miscellaneous /
杂 类 设 备 */

其中字符设备、块设备是常用的设备类型,它们的分类依据是设备数据与系统之间的传输处理方式。
字符模式设备允许非结构的数据传输,即通常数据传输采用串行的形式,每次一个字节。字符设备通常是一些简单设备,如串口、按键。
块设备每次传输一个数据块,例如每次传输 512 个字节数据。这个数据块是硬件强制性的,数据块可
能使用某类数据接口或某些强制性的传输协议,否则就可能发生错误。因此,有时块设备驱动程序对读或写操作必须执行附加的工作,

6.4 创建和注册 I/O 设备

//驱动层负责创建设备实例,并注册到 I/O 设备管理器中,可以通过静态申明的方式创建设备实例,也可以用下面的接口进行动态创建:
rt_device_t rt_device_create(int type, int attach_size);

//当一个动态创建的设备不再需要使用时可以通过如下函数来销毁:
void rt_device_destroy(rt_device_t device);

//设备被创建后,需要注册到 I/O 设备管理器中,应用程序才能够访问,
rt_err_t rt_device_register(rt_device_t dev, const char* name, rt_uint8_t flags);
//!!! note “注意事项” 应当避免重复注册已经注册的设备,以及注册相同名字的设备
#define RT_DEVICE_FLAG_RDONLY 0x001 /* 只 读 */
#define RT_DEVICE_FLAG_WRONLY 0x002 /* 只 写 */
#define RT_DEVICE_FLAG_RDWR 0x003 /* 读 写 */
#define RT_DEVICE_FLAG_REMOVABLE 0x004 /* 可 移 除 */
#define RT_DEVICE_FLAG_STANDALONE 0x008 /* 独 立 */
#define RT_DEVICE_FLAG_SUSPENDED 0x020 /* 挂 起 */
#define RT_DEVICE_FLAG_STREAM 0x040 /* 流 模 式 */
#define RT_DEVICE_FLAG_INT_RX 0x100 /* 中 断 接 收 */
#define RT_DEVICE_FLAG_DMA_RX 0x200 /* DMA 接 收 */
#define RT_DEVICE_FLAG_INT_TX 0x400 /* 中 断 发 送 */
#define RT_DEVICE_FLAG_DMA_TX 0x800 /* DMA 发 送 */

//当设备注销后的,设备将从设备管理器中移除,也就不能再通过设备查找搜索到该设备。
rt_err_t rt_device_unregister(rt_device_t dev);

6.5 访问 I/O 设备

应用程序通过 I/O 设备管理接口来访问硬件设备,当设备驱动实现后,应用程序就可以访问该硬件。I/
O 设备管理接口与 I/O 设备的操作方法的映射关系:
在这里插入图片描述

//应用程序根据设备名称获取设备句柄,进而可以操作设备
rt_device_t rt_device_find(const char* name);

//获得设备句柄后,应用程序可使用如下函数对设备进行初始化操作
rt_err_t rt_device_init(rt_device_t dev);

//通过设备句柄,应用程序可以打开和关闭设备,打开设备时,会检测设备是否已经初始化,没有初始化则会默认调用初始化接口初始化设备
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);

#define RT_DEVICE_OFLAG_CLOSE 0x000 /* 设 备 已 经 关 闭 (内 部 使 用)*/
#define RT_DEVICE_OFLAG_RDONLY 0x001 /* 以 只 读 方 式 打 开 设 备 */
#define RT_DEVICE_OFLAG_WRONLY 0x002 /* 以 只 写 方 式 打 开 设 备 */
#define RT_DEVICE_OFLAG_RDWR 0x003 /* 以 读 写 方 式 打 开 设 备 */
#define RT_DEVICE_OFLAG_OPEN 0x008 /* 设 备 已 经 打 开 (内 部 使 用)*/
#define RT_DEVICE_FLAG_STREAM 0x040 /* 设 备 以 流 模 式 打 开 */
#define RT_DEVICE_FLAG_INT_RX 0x100 /* 设 备 以 中 断 接 收 模 式 打 开 */
#define RT_DEVICE_FLAG_DMA_RX 0x200 /* 设 备 以 DMA 接 收 模 式 打 开 */
#define RT_DEVICE_FLAG_INT_TX 0x400 /* 设 备 以 中 断 发 送 模 式 打 开 */
#define RT_DEVICE_FLAG_DMA_TX 0x800 /* 设 备 以 DMA 发 送 模 式 打 开 */

//!!! note “注意事项” 如果上层应用程序需要设置设备的接收回调函数,则必须以 RT_DEVICE_FLAG_INT_RX或者 RT_DEVICE_FLAG_DMA_RX 的方式打开设备,否则不会回调函数。

//应用程序打开设备完成读写等操作后,如果不需要再对设备进行操作则可以关闭设备,通过如下函数完成
rt_err_t rt_device_close(rt_device_t dev);

//控制设备
rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);
#define RT_DEVICE_CTRL_RESUME 0x01 /* 恢 复 设 备 */
#define RT_DEVICE_CTRL_SUSPEND 0x02 /* 挂 起 设 备 */
#define RT_DEVICE_CTRL_CONFIG 0x03 /* 配 置 设 备 */
#define RT_DEVICE_CTRL_SET_INT 0x10 /* 设 置 中 断 */
#define RT_DEVICE_CTRL_CLR_INT 0x11 /* 清 中 断 */
#define RT_DEVICE_CTRL_GET_INT 0x12 /* 获 取 中 断 状 态 */

//读设备
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos,void* buffer, rt_size_t size)

//向设备中写入数据,
rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos,const void* buffer,rt_size_t size);


// 当硬件设备收到数据时,可以通过如下函数回调另一个函数来设置数据接收指示,通知上层应用线程有数据到达
rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_tdev,rt_size_t size));

//在应用程序调用 rt_device_write() 入数据时,如果底层硬件能够支持自动发送,那么上层应用可以设置一个回调函数。这个回调函数会在底层硬件数据发送完成后 (例如 DMA 传送完成或 FIFO 已经写入完毕产生完成中断时) 调用。可以通过如下函数设置设备发送完成指示,函数参数及返回值见

rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_tdev,void *buffer));

有了这一部分基础,进一步介绍相关的IO口的操作。 这一部分知识将分为以下6个模块模块来介绍具体操作。

1、PIN(GPIO)设备
2、ADC设备
3、PWM设备
4、I2C设备
5、RTC设备
6、SPI设备

这一部分模块通过接下来章节依次介绍。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

HHONGQI123

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

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

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

打赏作者

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

抵扣说明:

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

余额充值