嵌入式面向对象学习 RT-Thread I/O 设备管理框架 设备驱动层 案例测试

news2024/11/16 0:49:14

嵌入式面向对象 RT-Thread I/O 设备管理框架 设备驱动层

注:本文介绍性内容转载于《RT-Thread记录(十、全面认识 RT-Thread I/O 设备模型)》

注: 本次使用的开发板 :

​ 兆易创新GD32F407VET6开发板

​ 雅特力科技AT32A403A开发板

在这里插入图片描述
在这里插入图片描述

一、RT-Thread 的 I/O设备管理

1.1 什么是 I/O 设备模型
1.2 I/O 设备模型框架解析
1.3 I/O 设备操作逻辑说明
1.4 I/O 设备模型框架用处

二、I/O 设备模型操作 API

2.1 I/O 设备控制块
2.2 创建 I/O 设备相关
2.3 访问 I/O 设备相关

三、新建 I/O 设备模型实例

3.1 设备驱动层编写
3.2 应用层测试

一、RT-Thread 的 I/O设备管理

我们先从基本概念说起,了解RT-Thread 对 I/O 设备的管理方式,以及 I/O 设备模型框架的用途:

1.1 什么是 I/O 设备模型

有些小伙伴在刚接触到这个概念的时候还不太明白, I/O 设备模型,IO口?IO口的模型?

注意这里的 I/O 指的是 Input/Output。I/O 设备,就是指的输入 / 输出设备。

所谓 I/O 设备模型,指的是 RT-Thread 把所有的 输入 / 输出设备当做一类对象,然后通过自己的一套体系对这类对象进行管理,这类 I/O 设备对象就可以认为是 I/O 设备模型。

RT-Thread 提供了一套模型框架用来对所有的输入/输出设备进行管理的,名叫 I/O 设备模型框架 ,其 位于硬件层和应用程序之间,包括IO设备管理层、设备驱动框架层和设备驱动层, 向上层层抽象,目标是针对各种不同的I/O设备提供给应用程序相同的接口,如下图:
在这里插入图片描述
内容太多,具体内容在 嵌入式面向对象学习 RT-Thread I/O 设备管理框架 设备驱动层

三、新建 I/O 设备模型实例

前面的大部分内容都是参考文章的东西,对于I/O 设备模型进行了大量的说明。接下来进行案例测试

RT-Thread 驱动都是在 drivers 目录下面:
在这里插入图片描述

我们在目录下新建一个文件,作为驱动示例:

我们写一个简单的基本框架:

1、创建一个设备;
使用 rt_device_create 创建一个设备,需要定义一个 rt_device_t 接口体接收设备设备句柄。

2、实现设备操作的函数:
实现设备对象中对于 设备操作的init,open,close,read,write,control等 函数。在这里插入图片描述
3、注册设备到 I/O 设备管理器;
使用 rt_device_register 将设备注册到设备管理器。

drv_demo.c 中,我们实现如下代码:

在这里插入图片描述
其次,我们需要实现一下设备操作的函数:
在这里插入图片描述
最后,别忘了使用 INIT_BOARD_EXPORT 把设备初始化的代码加入板级硬件初始化:

设备模型实例代码:

#include <rtdevice.h>
#include <rtdbg.h>

rt_err_t  demo_init(rt_device_t dev)
{
    rt_kprintf("demo_init ok!\n");
    return RT_EOK;
}
rt_err_t  demo_open(rt_device_t dev, rt_uint16_t oflag)
{
    rt_kprintf("demo_open ok!\n");
    return RT_EOK;
}
rt_err_t  demo_cloes(rt_device_t dev)
{
    rt_kprintf("demo_cloes ok!\n");
    return RT_EOK;
}

rt_ssize_t demo_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
	  buffer = "this is device read example";
	  rt_kprintf("read example: %s\n",buffer);
	  return RT_EOK;
}
rt_ssize_t demo_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
	  buffer = "this is device write example";
	  rt_kprintf("write example: %s\n",buffer);
	  return RT_EOK;
}
rt_err_t  demo_control(rt_device_t dev, int cmd, void *args)
{
	switch(cmd)
	{
		case 0:
			rt_kprintf("this is demo_control example cmd-1!\n");	
			break;
		case 1:
			rt_kprintf("this is demo_control example  cmd-2!\n");	
			break;
		case 2:
			rt_kprintf("this is demo_control example  cmd-3!\n");	
			break;
		default:
			break;
	}
}


int rt_drvdemo_init(void)
{

    rt_device_t demo_dev = RT_NULL;

    demo_dev = rt_device_create(RT_Device_Class_Char, 0);
    if(demo_dev == RT_NULL){
        LOG_E("demo device create failed...\n");
        return RT_ERROR;
    }

    demo_dev->init=demo_init;
    demo_dev->open=demo_open;
    demo_dev->close=demo_cloes;
	demo_dev->read = demo_read;
    demo_dev->write = demo_write;
	demo_dev->control =demo_control;
    rt_device_register(demo_dev,"drvdemo",RT_DEVICE_FLAG_RDWR);
    return 0;
}


INIT_BOARD_EXPORT(rt_drvdemo_init);

上面我们完成的是 设备驱动层的 代码,接下来我们还需要简单演示一下,如果在应用层 使用这个 demo 设备。

我们根据上文所介绍的 访问 I/O 设备 进行对应操作,这里直接上图说明一下使用流程:

应用测试函数

rt_device_t dev = RT_NULL;

void *read_buf;
void *write_buf;

int main(void)
{

	dev = rt_device_find("drvdemo");
	
	  rt_device_init(dev);
	  rt_thread_mdelay(1000);
	  rt_device_open(dev,RT_DEVICE_OFLAG_OPEN);
	  rt_device_read(dev,0,read_buf,20);
	  rt_device_write(dev,0,write_buf,20);
	  rt_device_control(dev,0,RT_NULL);
	  rt_device_close(dev);
		
		
    return RT_EOK;
}

看一下测试结果,我们实现的 3 个驱动函数都只有打印输出,所以我们可以通过打印信息查看是否正确执行的驱动函数的内容:

下面是在雅特力AT32开发板的测试结果。

(原本打算使用gd32去做实验的,但是从官方的MDK工程打开一直存在问题,然后就换了一块板子,进行测试,从这里可以发现,统一的API接口的好处,应用层无缝对接)

在这里插入图片描述
在这里插入图片描述
下面是在对于立创开发板GD32F407进行详细实验。

  1. 下载rt-thread 源码
  2. 寻找bsp-gd32工程,gd32有两个类型一个是arm,一个risc-v
  3. 寻找立创开发板GD32F407模板工程 gd32f407v-lckfb
  4. 使用env工具进行配置

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  1. 如果直接编译,会报一个错误bug,需要修改,解决方法是添加condvar.c文件即可。

在这里插入图片描述

  1. 添加编写的drv_demo.c文件,完成设备驱动的添加

在这里插入图片描述
7. 编写应用层程序 测试

/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-01-13     yuanzihao    first implementation
 */

#include <stdio.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

/* defined the LED1 pin: PB2 */
#define LED_PIN GET_PIN(B, 2)
rt_device_t dev = RT_NULL;

void *read_buf;
void *write_buf;
int main(void)
{
    int count = 1;
    dev = rt_device_find("drvdemo");
	
	  rt_device_init(dev);
	  rt_thread_mdelay(1000);
	  rt_device_open(dev,RT_DEVICE_OFLAG_OPEN);
	  rt_device_read(dev,0,read_buf,20);
	  rt_device_write(dev,0,write_buf,20);
	  rt_device_control(dev,1,RT_NULL);
	  rt_device_close(dev);
		
    /* set LED1 pin mode to output */
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
   
    while (count++)
    {
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
			  //rt_kprintf("this is led_control on  [ok]!\n");	
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_thread_mdelay(500);
			  //rt_kprintf("this is led_control off [ok]!\n");	
    }

    return RT_EOK;
}

在这里插入图片描述
在这里插入图片描述

通过上面的测试,我们实现了一个简单的设备驱动的设计,虽然demo比较简单,但是经过这么一个过程可以让我们更加的理解 RT-Thread I/O 设备模型的工作方式和流程。

在这里,同时介绍一个开源项目mr-library。

mr-library 是一个开源项目,设备抽象层应该比RT-Thread更加轻量级,是一个学习设备框架,设备驱动,面向对象操作的好东西。

设备抽象层的开源库 mr-library

mr-library 框架是专为嵌入式系统设计的轻量级框架。充分考虑了嵌入式系统在资源和性能方面的需求。 通过提供标准化的设备管理接口,极大简化了嵌入式应用开发的难度,帮助开发者快速构建嵌入式应用程序。

框架为开发者提供了标准化的开启(open)、关闭(close)、控制(ioctl)、读(read)、写(write) 等接口。它将应用程序与底层硬件驱动进行解耦。应用程序无需了解驱动的实现细节。 当硬件发生改变时,只需要适配底层驱动,应用程序就可以无缝迁移到新硬件上。这大大提高了软件的可重用性和应对新硬件的可扩展性。


在这里插入图片描述

关键特性

  • 标准化的设备访问接口
  • 应用程序和驱动开发解耦
  • 简化底层驱动和应用程序开发
  • 轻量易上手,资源占用低
  • 模块化设计,各部分解耦合并独立开发,极低的硬件迁移成本
  • 支持在裸机环境和操作系统环境下使用

主要组成

  • 设备框架:提供设备访问标准接口
  • 内存管理:动态内存管理
  • 工具:链表、队列、平衡树等常用数据结构
  • 各类功能组件

标准化设备接口

设备的所有操作都可通过以下接口实现:

接口描述
mr_dev_register注册设备
mr_dev_open打开设备
mr_dev_close关闭设备
mr_dev_ioctl控制设备
mr_dev_read从设备读取数据
mr_dev_write向设备写入数据

测试案例

在这里插入图片描述

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

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

相关文章

c++的学习之路:7、类和对象(3)

目录 一、初始化列表 二、static成员 三、友元 四、内部类 五、匿名对象 六、类和对象的思维导图 一、初始化列表 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个"成员变量"后面跟一个放在括号中的初始…

求m和n的最大公约数(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int remainder 1;int m 0;int n 0;int middle 0;//提示用户&#xff1b;printf("请输入整数m和n的值&#xff…

辅助PC端教程

使用谷歌浏览器打开京东,并登录好账号进入到 https://home.jd.com/ ,在根据下面操作 更多工具 - 开发者工具,会有一个窗口打开,选择network,点击XHR

撸代码时,有哪些习惯一定要坚持?

我从2011年开始做单片机开发&#xff0c;一直保持以下撸代码的习惯。 1.做好代码版本管理 有些人&#xff0c;喜欢一个程序干到底&#xff0c;直到实现全部的产品功能&#xff0c;我以前做51单片机的项目就是这样。 如果功能比较多的产品&#xff0c;我不建议这样做&#xff0…

编译原理实验2(自上而下语法分析)

一、实验目的 给出 PL/0 文法规范&#xff0c;要求编写 PL/0 语言的语法分析程序。通过设计、编制、调试一个典型的自上而下语法分析程序&#xff0c;实现对词法分析程序所提供的单词序列进行语法检查和结构分析&#xff0c;进一步掌握常用的语法分析方法。选择有代表性的语法…

一款轻量、干净的 Vue 后台管理框架

开始之前 在开始介绍之前我想谈谈为什么要自己做一个后台管理&#xff0c;我知道很多人都用一些开源的后台管理项目&#xff0c;这些老前辈有很多亮点值得学习&#xff0c;但是存在的一些问题同样不可忽视&#xff0c;我认为很多开发者会被困扰(仅代表个人观点) 技术栈老旧不升…

面试(03)————多线程和线程池

一、多线程 1、什么是线程?线程和进程的区别? 2、创建线程有几种方式 &#xff1f; 3、Runnable 和 Callable 的区别&#xff1f; 4、如何启动一个新线程、调用 start 和 run 方法的区别&#xff1f; 5、线程有哪几种状态以及各种状态之间的转换&#xff1f; 6、线程…

Docker容器与虚拟化技术:OpenEuler 部署 ES 与 Kibana

目录 一、实验 1.环境 2.OpenEuler 部署 ES (EalasticSearch) 3.OpenEuler 部署 Kibana 4.部署 Elasticvue插件 5.使用cpolar内网穿透 6.使用Elasticvue 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注LinuxopenEuler22.03 LTS SP2 1…

flex布局align-items和align-content、justfiy-content的区别

justfiy-content&#xff1a;定义主轴的对齐方式align-items&#xff1a;定义交叉轴的对齐方式align-content&#xff1a;将flex子项作为一个整体起作用 只在两种情况下有效果&#xff1a; ①子项多行且flex容器高度固定 ②子项单行&#xff0c;flex容器高度固定且设置了fle…

Mac安装配置Appium

一、安装 nodejs 与 npm 安装方式与 windows 类似 &#xff0c;官网下载对应的 mac 版本的安装包&#xff0c;双击即可安装&#xff0c;无须配置环境变量。官方下载地址&#xff1a;https://nodejs.org/en/download/ 二、安装 appium Appium 分为两个版本&#xff0c;一个是…

HarmonyOS实战开发-屏幕属性(仅对系统应用开放)

介绍 本示例主要展示了屏幕管理相关的功能&#xff0c;使用ohos.display、ohos.screen接口&#xff0c;ohos.display接口提供获取默认display对象、获取所有display对象&#xff0c;开启监听、关闭监听功能&#xff1b;ohos.screen接口提供创建虚拟屏幕、销毁虚拟屏幕、扩展屏…

LeetCode-热题100:118. 杨辉三角

题目描述 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows 1 输出: [[1]]…

什么软件可以保密公司文件?

#天锐绿盾# 天锐绿盾是一款专为企业设计的文件加密与数据防泄密软件&#xff0c;旨在通过一系列高级安全功能来保护公司的敏感信息和重要文件不被未经授权的访问、窃取或泄露。 PC地址&#xff1a; https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfe…

蓝奏云直链获取在线解析网站源码

源码简介 蓝奏云直链获取在线解析网站源码 蓝奏云链接解析 本地API接口 支持有无密码和短期直链和永久直链&#xff0c;同时还可以显示文件名和大小。 这个解析器无需数据库即可搭建&#xff0c;API接口已经本地化&#xff0c;非常简单易用。 安装环境 php5.6 搭建教程 …

HTML - 你如何使H5页面禁止手动缩放

难度级别:初级及以上 提问概率:40% 我们知道,这道题其实是在考察meta标签的viewport属性,正常情况下设置viewport的代码为 <head><meta name="viewport" content="width=device-width,initial-scale=1.0" …

全网最详细的网络安全自学笔记

1.选择方向 首先是选择方向的问题&#xff0c;网络安全是一个很宽泛的专业&#xff0c;包含的方向特别多。比如 web安全&#xff0c;系统安全&#xff0c;无线安全&#xff0c;二进制安全&#xff0c;运维安全&#xff0c;渗透测试&#xff0c;软件安全&#xff0c;IOT安全&am…

【运输层】网络数据报协议 UDP

目录 1、UDP 的特点 2、UDP 的首部格式 UDP 只在 IP 协议之上增加了很少的一些功能&#xff0c;比如复用、分用以及差错检测等。 1、UDP 的特点 UDP是无连接的&#xff0c;即发送数据之前不需要建立连接&#xff0c;因此减少了开销和发送数据之前的时延。 UDP使用尽最大努力…

python函数练习2

找出10000以内能被5或6整除&#xff0c;但不能被两者同时整除的数&#xff08;函数&#xff09; def func():for i in range(1,50):if (i % 5 0 or i % 6 0 ):if i % 5 0 and i % 6 0:continue #利用continue跳过能被5和6整除的数print(i) func()写一个方法&#xff0c;计算…

Windbg查看函数调用过程中的内存布局

我们在分析问题的时候经常会需要查看进程的栈和帧中的值&#xff0c;下面我们就用一个简单的例子来分析一下这个过程。 源代码&#xff1a; #include <iostream> int add(int a, int b) {return a b; }int main() {int a, b;a 3;b 4;int ret add(a, b);std::cout &…

【Python】快速排序法 Leetcode 148. 排序链表

题目 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 代码 第一次使用朴素快速排序&#xff0c;基准值为头节点值&#xff0c;居然超时了&#xff0c;然后…