RTT(RT-Thread)IO设备模型

目录

IO设备模型

模型框架原理

IO设备类型

创建和注册IO设备

RTT设备管理程序实现原理

访问IO设备

查找设备

初始化设备

打开设备

关闭设备

 控制设备

 读写设备

数据收发回调

数据接收回调

数据发送回调

设备模型实例


IO设备模型

        RT-Thread 提供了一套简单的 I/O 设备模型框架,如下图所示,它位于硬件和应用程序之间,共分成三层,从上到下分别是 I/O 设备管理层、设备驱动框架层、设备驱动层。

  • 应用程序通过 I/O 设备管理接口获得正确的设备驱动,然后通过这个设备驱动与底层 I/O 硬件设备进行交互。
  • I/O 设备管理层实现了对设备驱动程序的封装
  • 设备驱动框架层是对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。
  • 设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。

简单设备的注册不经过设备驱动框架层,直接将设备注册到I/O设备管理器中

  • 设备驱动根据设备模型定义,创建出具备硬件访问能力的设备实例,将该设备通过rt_device_register()接口注册到 I/O 设备管理器中
  • 应用程序通过 rt_device_find()接口查找到设备,然后使用 I/O 设备管理接口来访问硬件

模型框架原理

图中:在左边是应用层代码,在右边是设备驱动代码,设备驱动层是与硬件最接近的(用于直接访问硬件)。而设备驱动和应用程序通过同一的IO设备管理器来统一管理起来。

如何去管理呢?设备驱动在要操作硬件的时候,要向IO设备管理器去注册,一旦注册完之后,设备管理器就知道了哪个设备的驱动注册到系统里面了。当注册成功以后,当应用层想要访问硬件的时候,通过调用rt_device_find函数来找到相应的设备驱动,一旦找到以后,就可以打开设备,接着进行读写操作,最后要记得关闭设备。

应用层想要去访问硬件的时候,只需要查找到相应的设备驱动,然后调用统一的接口就能对硬件设备进行操作,不需要关注硬件的实现原理。而对应硬件驱动来讲,我们只需要提供对硬件的访问方法。具体如何去访问,以及访问到的数据如何去处理也跟设备驱动没有关系。也就是说将不同的事情交给不同的层去完成,实现解耦(高内聚、低耦合)

对于一些复杂设备,需要使用到对应的设备驱动框架层,进行注册,它们拥有自己专属的注册函数 如:看门狗定时器

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

IO设备类型

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

RT_Device_Class_Char = 0, /**< character device */

RT_Device_Class_Block, /**< block device */

RT_Device_Class_NetIf, /**< net interface */

RT_Device_Class_MTD, /**< memory device */

RT_Device_Class_CAN, /**< CAN device */

RT_Device_Class_RTC, /**< RTC device */

RT_Device_Class_Sound, /**< Sound device */

RT_Device_Class_Graphic, /**< Graphic device */

RT_Device_Class_I2CBUS, /**< I2C bus device */

RT_Device_Class_USBDevice, /**< USB slave device */

RT_Device_Class_USBHost, /**< USB host bus */

RT_Device_Class_SPIBUS, /**< SPI bus device */

RT_Device_Class_SPIDevice, /**< SPI device */

RT_Device_Class_SDIO, /**< SDIO bus device */

RT_Device_Class_Timer, /**< Timer device */

RT_Device_Class_Miscellaneous, /**< misc device */

RT_Device_Class_Sensor, /**< Sensor device */

RT_Device_Class_Touch, /**< Touch device */

RT_Device_Class_Unknown /**< unknown device */

创建和注册IO设备

  • 驱动层负责创建设备实例,并注册到 I/O 设备管理器中
/*** This function creates a device object with user data size.** @param type, the kind type of this device object.* @param attach_size, the size of user data.** @return the allocated device object, or RT_NULL when failed.*/
rt_device_t rt_device_create(int type, int attach_size)
  • 当一个动态创建的设备不再需要使用时可以通过如下函数来销毁
/*** This function destroy the specific device object.** @param dev, the specific device object.*/
void rt_device_destroy(rt_device_t dev)
  • 设备被创建后,需要实现它访问硬件的操作方法
struct rt_device_ops
{/* common device interface */rt_err_t  (*init)   (rt_device_t dev);rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);rt_err_t  (*close)  (rt_device_t dev);rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);rt_err_t  (*control)(rt_device_t dev, int cmd, void *args);
};
  • 设备被创建后,需要注册到 I/O 设备管理器中,应用程序才能够访问
/*** This function registers a device driver withspecified name.** @param dev the pointer of device driverstructure* @param name the device driver's name* @param flags the capabilities flag ofdevice   设备模式标志** @return the error code, RT_EOK oninitialization successfully.*/
rt_err_t rt_device_register(rt_device_t dev,const char *name,rt_uint16_t flags)#define RT_DEVICE_FLAG_RDONLY 0x001/*只读*/
#define RT_DEVICE_FLAG_WRONLY 0x002/*只写*/
#define RT_DEVICE_FLAG_RDWR 0x003 /*读写*/
#define RT_DEVICE_FLAG_REMOVABLE0x004 /*可移除*/
#define RT_DEVICE_FLAG_STANDALONE0x008 /*独立*/
#define RT_DEVICE_FLAG_SUSPENDED0x020 /*挂起*/
#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发送*/
  • 设备注销后的,设备将从设备管理器中移除,也就不能再通过设备查找搜索到该设备。注销设备不会释放设备控制块占用的内存
/*** This function removes a previouslyregistered device driver** @param dev the pointer of device driverstructure** @return the error code, RT_EOK onsuccessfully.*/
rt_err_t rt_device_unregister(rt_device_t dev)

RTT设备管理程序实现原理

当我们创建一个设备的时候,系统会使用一个结构体描述这个设备的所有信息。当我们创建并注册多个设备的时候,系统就会通过列表的方式将这些结构体统一管理起来。当我们应用层想要找到某个设备的时候,就会调用find函数来找到列表头来根据name遍历查找,找到以后就会调用相应的方法来操作设备。当设备不用的时候,调用unregister函数来移除(将结构体变量从列表中移除),但结构体的空间依然存在,如果我们想要将结构体的空间释放掉,就需要调用destroy函数来进行删除释放。

访问IO设备

应用程序通过 I/O 设备管理接口来访问硬件设备,当设备驱动实现后,应用程序就可以访问该硬件,I/O 设备管理接口与 I/O 设备的操作方法的映射关系下图所示

相应接口函数在设备句柄结构体中

使用应用层接口前,首先要查找到设备

查找设备

返回值为设备句柄指针

/*** This function finds a device driver byspecified name.** @param name the device driver's name** @return the registered device driver onsuccessful, or RT_NULL on failure.*/
rt_device_t rt_device_find(const char*name)

操作接口如下:

初始化设备

/*** This function will initialize the specified device** @param dev the pointer of device driver structure** @return the result*/
rt_err_t rt_device_init(rt_device_t dev)

打开设备

/*** This function will open a device** @param dev the pointer of device driver structure* @param oflag the flags for device open** @return the result*/
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)

注:RT_DEVICE_FLAG_STREAM:流模式用于向串口终端输出字符串:当输出的字符是 "\n"(对应 16 进制值为 0x0A)时,自动在前面输出一个 "\r"(对应 16 进制值为 0x0D)做分行。

流模式 RT_DEVICE_FLAG_STREAM 可以和接收发送模式参数使用或 “|” 运算符一起使用

关闭设备

/*** This function will close a device** @param dev the pointer of device driver structure** @return the result*/
rt_err_t rt_device_close(rt_device_t dev)

 控制设备

/*** This function will perform a variety of control functions on devices.** @param dev the pointer of device driver structure* @param cmd the command sent to device* @param arg the argument of command** @return the result*/
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)

 读写设备

/*** This function will read some data from adevice.** @param dev the pointer of device driverstructure* @param pos the position of reading* @param buffer the data buffer to save read data* @param size the size of buffer** @return the actually read size onsuccessful, otherwise negative returned.** @note since 0.4.0, the unit of size/pos is ablock for block device.*/
rt_size_t rt_device_read(rt_device_tdev,rt_off_t    pos,void       *buffer,rt_size_t   size)
/*** This function will write some data to adevice.** @param dev the pointer of device driverstructure* @param pos the position of written* @param buffer the data buffer to be writtento device* @param size the size of buffer** @return the actually written size onsuccessful, otherwise negative returned.** @note since 0.4.0, the unit of size/pos is ablock for block device.*/
rt_size_trt_device_write(rt_device_t dev,rt_off_t    pos,const void *buffer,rt_size_t   size)

数据收发回调

当硬件设备收到数据时,可以通过如下函数回调另一个函数来设置数据接收指示,通知上层应用线程有数据到达

原理:通过设置数据的收发回调来通知我们的应用层某个线程来接收数据。这样就不需要再接收数据的时候写一个while循环一直去读。让它在没有数据的时候去休眠阻塞,一旦有数据的时候,这个函数就会被回调去通知相应线程唤醒去读写,这样可以减少系统的调用,提高系统调用效率。

数据接收回调

/*** This function will set the receptionindication callback function. * This callback function* is invoked when this device receives data.** @param dev the pointer of device driverstructure* @param rx_ind the indication callbackfunction** @return RT_EOK*/
rt_err_t
rt_device_set_rx_indicate(rt_device_tdev,rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size))

数据发送回调

/*** This function will set the indicationcallback function when device has* written data to physical hardware.** @param dev the pointer of device driverstructure* @param tx_done the indication callbackfunction** @return RT_EOK*/
rt_err_t
rt_device_set_tx_complete(rt_device_tdev,rt_err_t (*tx_done)(rt_device_t dev,void *buffer))

设备模型实例

(1)首先在drivers下创建一个drv_demo.c的驱动文件

(2)然后刷新工程目录,打开drv_demo.c

(3)我们可以参考drv_wdt.c的设备驱动模型来写

在文件最后我们可以发现有一个板级初始化的导出函数:我们使用INIT_BOARD_EXPORT宏将rt_wdt_init函数导出,那么在板级初始化的时候就会调用rt_wdt_init函数

我们再drv_demo.c中导出自己的设备初始化函数,并编写设备初始化函数

(4)接着我们创建设备,使用rt_device_create函数

第一个参数是设备类型,这里用字符设备

第二个参数是用户的数据大小,如果要传入用户数据的话,我们就根据用户数据的大小来传参。因为我们不需要传入用户数据,因此大小可以随便写一个,如32。

返回值为指针类型rt_device_t

(5)设备创建成功以后,我们需要对设备编写相应的接口函数,我们以init、open、close为例

我们可以按F3跳转到rt_device_t中,并将相应接口函数指针复制到我们自己的设备驱动文件下

(6)将函数进行简单完善

并对接口进行赋值

(7)然后我们以读写的方式注册我们的设备模型

(8)最后我们在main函数中使用,首先查找设备,如果查找成功,返回一个设备对象指针,如果查找失败,我们返回错误:变量无效

然后调用相应的应用层接口函数

(10)编译之后发现有一个警告LOG_E未定义

我们需要将添加调试头文件#include

(11)运行结果

通过列举设备,可以查看到demo是我们自己创建的设备;uart2是用来监控当前STM32单片机的,用作用户的调试接口;pin是GPIO引脚。(其中要注意串口也是属于字符设备类型的)

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

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

相关文章

OptaPlanner笔记6 N皇后

N 个皇后 问题描述 将n个皇后放在n大小的棋盘上&#xff0c;没有两个皇后可以互相攻击。 最常见的 n 个皇后谜题是八个皇后谜题&#xff0c;n 8&#xff1a; 约束&#xff1a; 使用 n 列和 n 行的棋盘。在棋盘上放置n个皇后。没有两个女王可以互相攻击。女王可以攻击同一水…

机器人CPP编程基础-04输入Input

机器人CPP编程基础-03变量类型Variables Types ……AI…… C #include<iostream> // 引入iostream库&#xff0c;这个库包含了对输入/输出进行操作所需的函数和对象 using namespace std; // 使用命名空间std&#xff0c;这样我们就可以直接使用std中的名字&#xff0c…

(二)结构型模式:1、适配器模式(Adapter Pattern)(C++实现示例)

目录 1、适配器模式&#xff08;Adapter Pattern&#xff09;含义 2、适配器模式应用场景 3、适配器模式的UML图学习 4、C实现适配器模式的示例 1、适配器模式&#xff08;Adapter Pattern&#xff09;含义 将一个接口转换为客户端所期待的接口&#xff0c;从而使两个接口…

树和二叉树 --- 数据结构

目录 1.树的概念及结构 1.1树的概念 1.2树的表示 1.3树在实际生活中的运用 2.二叉树的概念及结构 2.1概念 2.2特殊的二叉树 2.3二叉树的性质 2.4二叉树的存储结构 1.树的概念及结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n (n>0)个有限结点组成…

【server组件】——mysql连接池的实现原理

目录 1.池化技术 2.数据库连接池的定义 3.为什么要使用连接池 4. 数据库连接池的运行机制 5. 连接池与线程池的关系 6. CResultSet的设计 6.1构造函数 7. CDBConn的设计 6.1.构造函数 6.2.init——初始化连接 8.数据库连接池的设计要点 9.接口设计 9.1 构造函数 …

【LeetCode】617.合并二叉树

题目 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要将这两棵树合并成一棵新二叉树。合并的规则是&#xff1a;如果两个节点重叠…

Azure资源命名和标记决策指南

参考 azure创建虚拟机在虚拟机中选择编辑标签&#xff0c;并添加标记&#xff0c;点击应用 3.到主页中转到所有资源 4. 添加筛选器并应用 5.查看结果&#xff0c;筛选根据给服务器定义的标签筛选出结果。 参考链接: https://learn.microsoft.com/zh-cn/azure/cloud-adoption…

【ArcGIS】经纬度数据转化成平面坐标数据

将点位置导入Gis中&#xff0c;如下&#xff08;经纬度表征位置&#xff09;&#xff1a; 如何利用Gis将其转化为平面坐标呢&#xff1f; Step1 坐标变换 坐标变换&#xff0c;打开ArcToolbox&#xff0c;找到“数据管理工具”->“投影和变换”->“要素”->“投影”…

JZ33二叉搜索树的后序遍历序列

题目地址&#xff1a;二叉搜索树的后序遍历序列_牛客题霸_牛客网 题目回顾&#xff1a; 解题思路&#xff1a; 使用栈 栈的特点是&#xff1a;先进后出。 通读题目后&#xff0c;我们可以得出&#xff0c;二叉搜索树是左子节点小于根节点&#xff0c;右子节点大于根节点。 …

【Tomcat】(Tomcat 下载Tomcat 启动Tomcat 简单部署 基于Tomcat进行网站后端开发)

文章目录 Tomcat下载Tomcat启动Tomcat简单部署 基于Tomcat进行网站后端开发 Tomcat Tomcat 是一个 HTTP 服务器.HTTP 协议就是 HTTP 客户端和 HTTP 服务器之间的交互数据的格式. HTTP 服务器我们可以通过 Java Socket 来实现. 而 Tomcat 就是基于 Java 实现的一个开源免费,也是…

CNN的特性

1、位移不变性 它指的是无论物体在图像中的什么位置&#xff0c;卷积神经网络的识别结果都应该是一样的。 因为CNN就是利用一个kernel在整张图像上不断步进来完成卷积操作的&#xff0c;而且在这个过程中kernel的参数是共享的。换句话说&#xff0c;它其实就是拿了同一张“通…

数据结构:选择排序

简单选择排序 选择排序是一种简单直观的排序算法。首先在未排序序列中找到最大&#xff08;最小&#xff09;的元素&#xff0c;存放到排序学列的其实位置&#xff0c;然后在剩余的未排序的元素中寻找最小&#xff08;最大&#xff09;元素&#xff0c;存放在已排序序列的后面…

cmake扩展(1)——VS+CMake创建Qt项目

创建项目 创建CMakeLists #cmake最低版本 cmake_minimum_required(VERSION 3.10) #项目名 project(regextool)#查找所有*.h,*.ui,*.cpp文件&#xff0c;并存入SOURCES中 file(GLOB SOURCES "*.cpp" "*.ui" "*.h")#开启moc set(CMAKE_AUTOMOC O…

计算机视觉中的特征检测和描述

一、说明 这篇文章是关于计算机视觉中特征检测和描述概念的简要理解。在其中&#xff0c;我们探讨了它们的定义、常用技术、简单的 python 实现和一些限制。 二、什么是特征检测和描述&#xff1f; 特征检测和描述是计算机视觉中的基本概念&#xff0c;在图像识别、对象跟踪和图…

Opencv特征检测之ORB算法原理及应用详解

Opencv特征检测之ORB算法原理及应用详解 特征是图像信息的另一种数字表达形式。一组好的特征对于在指定 任务上的最终表现至关重要。视觉里程 &#xff08;VO&#xff09; 的主要问题是如何根据图像特征来估计相机运动。但是&#xff0c;整幅图像用来计算分析通常比较耗时&…

机器学习终极指南:特征工程(02/2) — 第 -2 部分

接上文&#xff1a;机器学习终极指南&#xff1a;特征工程&#xff08;01/2&#xff09; 五、处理不平衡数据 处理不平衡的数据是机器学习的一个重要方面。不平衡数据是指目标变量的分布不均匀&#xff0c;并且与另一个类相比&#xff0c;一个类的代表性不足。这可能导致模型…

[内网渗透]CFS三层靶机渗透

文章目录 [内网渗透]CFS三层靶机渗透网络拓扑图靶机搭建Target10x01.nmap主机探活0x02.端口扫描0x03.ThinkPHP5 RCE漏洞拿shell0x04.上传msf后门(reverse_tcp)反向连接拿主机权限 内网渗透Target2&#xff08;1&#xff09;路由信息探测&#xff08;2&#xff09;msf代理配置&a…

两个数组的交集-C语言/Java

描述 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序。&#xff08;1 < nums1.length, nums2.length < 1000&#xff0c;0 < nums1[i], nums2[i] < 1000&#xff09; 示例1 输入…

yolov5代码解读之train.py【训练模型】

哇咔咔&#xff0c;登场 代码开头都是一些导包到模块的&#xff1a; 接下来来到入口函数&#xff1a; 我们直接来到main函数的内容&#xff1a;&#xff08;分四个部分&#xff09; 前两部分&#xff1a; 关于main函数的第二部分中的resume参数&#xff08;496行&#xff09;&…

概率图模型(Probabilistic Graphical Model,PGM)

概率图模型&#xff08;Probabilistic Graphical Model&#xff0c;PGM&#xff09;&#xff0c;是一种用图结构来描述多元随机变量之间条件独立性的概率模型。它可以用来表示复杂的概率分布&#xff0c;进行有效的推理和学习&#xff0c;以及解决各种实际问题&#xff0c;如图…