色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

RT-Thread記錄(十、全面認識 I/O 設備模型)

矜辰所致 ? 來源:矜辰所致 ? 作者:矜辰所致 ? 2022-06-30 10:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

學完 RT-Thread 內核,從本文開始熟悉了解 RT-Thread I/O 設備管理相關知識。

目錄

前言
一、RT-Thread 的 I/O設備管理

1.1 什么是 I/O 設備模型
1.2 I/O 設備模型框架解析
1.2.1 應用程序
1.2.2 I/O 設備管理層
1.2.3 設備驅動框架層
1.2.4 設備驅動層
1.2.5 硬件層
1.3 I/O 設備操作邏輯說明
1.4 I/O 設備模型框架有什么用?

二、I/O 設備模型操作 API

2.1 I/O 設備控制塊
2.1.1 設備類型 type
2.1.2 設備注冊 flag
2.1.3 設備訪問 open_flag
2.2 創建 I/O 設備相關
2.2.1 創建設備
2.2.2 銷毀設備
2.2.3 設備注冊
2.2.4 設備注銷
2.3 訪問 I/O 設備相關
2.3.1 查找設備
2.3.2 初始化設備
2.3.3 打開和關閉設備
2.3.4 讀寫設備
2.3.5 控制設備
2.3.6 數據收發回調

三、新建 I/O 設備模型實例
結語

前言

我們已經把 RT-Thread 內核學習完成,也已經使用 RT-Thread 做了一個實例應用。

但是作為一個操作系統, RT-Thread 除了內核部分還有自己的設備框架,類似于 Linux 操作系統設備的管理方式的 I/O 設備模型。

從本文開始,我們要開始學習了解 RT-Thread 的 I/O 設備模型。

說明,概念性質的說明主要還是使用引用方式,畢竟有權威的官方在,對于一些細節的理解,我會闡述自己的看法,同時會設計一些實例加深我們對基本概念的理解。

?? 我想做到的是,僅此一片文章,讓所有人都能明白RT-Thread 的I/O 設備模型 ??

一、RT-Thread 的 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設備提供給應用程序相同的接口,如下圖:

pYYBAGK9DJWALOWBAAOPg3TZ6Ho023.png

1.2 I/O 設備模型框架解析

根據上圖,結合工程代碼,我們對每個層分別說:

1.2.1 應用程序

我們寫的應用程序,調用 I/O 設備管理層給的接口進行底層硬件操作;

對應 main.c :

poYBAGK9DJWAK43VAAA3FT2lzKM769.png

1.2.2 I/O 設備管理層

I/O 設備管理層實現了對設備驅動程序的封裝。
應用程序通過 I/O 設備管理接口獲得正確的設備驅動,然后通過這個設備驅動與底層 I/O 硬件設備進行數據交互。
設備驅動程序的升級、更替不會對上層應用產生影響。這種方式使得設備的硬件操作相關的代碼能夠獨立于應用程序而存在,雙方只需關注各自的功能實現,從而降低了代碼的耦合性、復雜性,提高了系統的可靠性。

對應 device.c

pYYBAGK9DJWAEce_AAApcEWezF4881.png

1.2.3 設備驅動框架層

設備驅動框架層對同類硬件設備驅動的抽象,將不同廠家的同類硬件設備驅動中相同的部分抽取出來,將不同部分留出接口,由驅動程序實現。

對應的比如 serial.c 等

poYBAGK9DJaAG9KJAAA3hwS3nZU266.png

?? 上面的 I/O 設備管理層 和 設備驅動框架層 是屬于RT-Thread 系統的范疇,官方已寫好,所以在項目中的位置存放于 rt-thread 文件夾下面。

1.2.4 設備驅動層

設備驅動層是一組驅使硬件設備工作的程序,實現訪問硬件設備的功能。它負責創建和注冊 I/O 設備,就類似于使用裸機編寫程序時候的底層驅動。
裸機的驅動是直接被應用層調用,這里的驅動是提供給 設備驅動框架層調用 或者 直接給 I/O 設備管理層調用的。

對于一些常用的芯片或者與官方有合作的芯片,官方也會提供了寫好的驅動,比如STM32,下圖就是官方已經寫好的基于STM32 的設備驅動層的代碼。

對應比如 drv_gpio.c 、drv_usart.c 這些 :

pYYBAGK9DJaAf10ZAAA651d5Q04796.png

?? 設備驅動層的編寫是需要基于芯片或外設的手冊、SDK,是需要額外實現的。
但是有些常用芯片和外設官方已經幫我們寫好了,比如基于 STM32 的 HAL 庫,RT-Thread官方已經實現了基于 STM32 的設備驅動層 。

1.2.5 硬件層

比如Flash芯片,SD卡,stm32芯片等外設和MCU設備。

1.3 I/O 設備操作邏輯說明

簡單介紹一下 I/O 設備操作邏輯,這部分應用官方的說明。

對于操作邏輯簡單的設備,可以不經過設備驅動框架層,直接將設備注冊到 I/O 設備管理器中,過程如下:

在我們本文后面的新建設備模型實例中就舉了個簡單設備的例子。

poYBAGK9DJaASOvsAADEkSQNTGw266.png

對于復雜點的設備,需要經過設備驅動框架層:

pYYBAGK9DJaAXsODAACyCrlrinY973.pngpoYBAGK9DJaADCALAADNyf5MhT0777.png

為了更好的理解上面的流程,可以結合工程源碼理解,多看源碼,比如下圖所示:

pYYBAGK9DJeAKfIJAAD8rGHr6D0552.png

1.4 I/O 設備模型框架有什么用?

有很多初學者會問, I/O 設備模型意義在哪里? 在裸機使用中,比如操作一個IO口,直接調用驅動函數,不是更簡單,更直接,使用了設個模型,反而變得復雜了?

在某些時候,如果你只使用一種芯片一種方案,或許某種意義上說, I/O 設備模型確實可能會比直接調用驅動函數復雜。 也可以說,你使用的方案單一,項目簡單,沒有必要使用 I/O 設備模型,甚至可能連 RTOS 都不一定需要。

總之就是,只用一種芯片方案簡單項目或者內存空間實在有限,完全是可以不用這個框架,直接用 RT-Thread Nano 完成功能,和我們前面講的項目實例一樣完成,是沒有問題的!

但是作為一個工程師,不能局限在一種方案上面,尤其當今芯片市場變幻莫測,指不定哪天需要換芯片,換方案呢? 而且 RT-Thread 作為一個面向對象思想設計的操作系統,必須得全面考慮,需要降低了代碼的耦合性、復雜性,提高了系統的可靠性,能夠使得系統運行與不同的芯片設備上。

如果沒有 I/O 設備模型,那么每次換方案,從底層到應用層所有的代碼基本上都得重寫,對于簡單的項目無所謂,對于復雜一點的項目,那可是需要花費大量功夫。

使用了 RT-Thread 的 I/O 設備模型,不管你使用哪種MCU,應用層對設備操作的函數一模一樣,設備驅動程序的升級、更替不會對上層應用產生影響。這種方式使得設備的硬件操作相關的代碼能夠獨立于應用程序而存在,雙方只需關注各自的功能實現。

如果學過 Linux 的朋友肯定知道,RT-Thread 的 I/O 設備模型 思想 是和 Linux 類似的,作為嵌入式工程師,如果你懂 Linux,那么就應該知道 I/O 設備模型框架 的優點。如果你不懂 Linux,那么學會了 RT-Thread 操作系統的 I/O 設備模型,對于以后深入學習 Linux 操作系統,也是有幫助的 。 這話沒毛病! 感覺怎么說怎么有道理,人往高處走嘛!= =!

所有最終結果就是,反正就是好,人往高處走,學會了沒壞處 = =!

二、I/O 設備模型操作 API

上文我們說明了RT-Thread I/O 設備模型的基本概念先關內容,也了解了 I/O 設備模型框架以及操作邏輯,那么我們用戶該如何來實現這一流程呢?

所以現在我們就來學習一下I/O設備模型操作的相關API函數,包括創建、注冊、訪問等 。。。

2.1 I/O 設備控制塊

我們不止一次的說明了 RT-Thread 的面向對象的思想,在RT-Thread中,設備也是一種內核對象,那么他和以前說的線程,IPC機制,定時器等對象一樣,有自己的對象控制塊。

在以前博文:RT-Thread記錄(六、IPC機制之信號量、互斥量和事件集)這里再次額外說明一下,因為只要理解了這種思想,對于學會他們的使用就更加簡單了,在IPC機制的時候我們使用圖片說明過:

poYBAGK9DJeAZ3NoAAPLTvh7m9w388.pngpYYBAGK9DJiACQcdAAQfsPD-ENk782.png

其實我們可以看一下設備對象的控制塊:

poYBAGK9DJiAIzRcAAEkupi7DCI510.png

上源碼方便以后復制:

/**
 * Device structure 設備控制塊
 */
struct rt_device
{
    struct rt_object          parent;                   /**< inherit from rt_object */

    enum rt_device_class_type type;                     /**< device type */
    rt_uint16_t               flag;                     /**< device flag */
    rt_uint16_t               open_flag;                /**< device open flag */

    rt_uint8_t                ref_count;                /**< reference count */
    rt_uint8_t                device_id;                /**< 0 - 255 */

    /* device call back */
    rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
    rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

#ifdef RT_USING_DEVICE_OPS
    const struct rt_device_ops *ops;
#else
    /* 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);
#endif

#if defined(RT_USING_POSIX)
    const struct dfs_file_ops *fops;
    struct rt_wqueue wait_queue;
#endif

    void                     *user_data;                /**< device private data */
};

2.1.1 設備類型 type

設備對象的控制塊中對于設備類型使用了一個rt_device_class_type枚舉的方式,其可能的設備類型如下(簡單的沒有注釋,還有部分嗎不太清楚的,以后更新):

pYYBAGK9DJiAIFJlAAEf0PiIGlg009.png

設備類型 需要在創建的時候選擇好,寫驅動的時候應該知道自己寫的是什么類型的設備。

2.1.2 設備注冊 flag

設備對象的控制塊中有一個 flag 參數,設備模式標志 ,表示設備是屬于什么狀態的設備,可讀、可寫、收發等,其可以有的參數如下:

poYBAGK9DJiAO5iiAADbHHtBd0s404.png

注意,該標志可以采用或的方式支持多種參數。

設備注冊 flag 需要在創建的時候選擇好,寫驅動的時候應該知道自己寫的設備是什么狀態,比如只讀。只寫,中斷接收之類的。

2.1.3 設備訪問 open_flag

設備對象的控制塊中有一個 open_flag 參數,設備打開模式標志 ,表示對設備進行什么操作,其可以有的參數如下:

pYYBAGK9DJiAQMcEAACi9CQYMmU840.png

設備訪問的時候,需要使用這個 open_flag 來判斷需要對設備進行什么操作,是讀?還是寫? 還是發送等。。。

?? 介紹了 I/O 設備控制塊,讓我們清楚我們要操作的對象是什么,我們在 設備驅動層 要寫的設備驅動以及上層應用對 I/O 設備的訪問, 就是基于這個控制塊來進行的。

2.2 創建 I/O 設備相關

我們按照 先創建設備,再訪問設備 的順序來介紹對于的 API 函數。

2.2.1 創建設備

老規矩用源碼,解釋看注釋(使用起來也方便復制 ~ ~!):

/*
參數的含義:
1、type 		設備類型,上面 2.1.1 小結說明的設備類型
2、attach_size  用戶數據大小
返回值:
創建成功,返回設備的控制塊指針
創建失敗,返回RT_BULL 
*/

rt_device_t rt_device_create(int type, int attach_size)

/**
 * device (I/O) class type  設備類型
 */
enum rt_device_class_type
{
    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_PM,                                 /**< PM pseudo device */
    RT_Device_Class_Pipe,                               /**< Pipe device */
    RT_Device_Class_Portal,                             /**< Portal device */
    RT_Device_Class_Timer,                              /**< Timer device */
    RT_Device_Class_Miscellaneous,                      /**< Miscellaneous device */
    RT_Device_Class_Sensor,                             /**< Sensor device */
    RT_Device_Class_Touch,                              /**< Touch device */
    RT_Device_Class_PHY,                                /**< PHY device */
    RT_Device_Class_Unknown                             /**< unknown device */
};

設備被創建后,需要實現它訪問硬件的操作方法,要按照下面的函數指針實現這些對于設備的操作函數:

/* 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);

這里引用官方的說明:

poYBAGK9DJmAbYFbAAI0qwEx3Bg850.png

2.2.2 銷毀設備

此函數不一定需要使用,但是有創建就應該有銷毀:

/*
參數的含義:
dev 	設備句柄
*/
void rt_device_destroy(rt_device_t dev)

2.2.3 設備注冊

設備被創建后,需要注冊到 I/O 設備管理器中,應用程序才能夠訪問:

/*
參數的含義:
dev 	設備句柄
name 	設備名稱,
設備名稱的最大長度由 rtconfig.h 中定義的宏 RT_NAME_MAX 指定,多余部分會被自動截掉
flags 	設備模式標志,就是上面介紹的 2.1.2 設備注冊 flag
返回值:
RT_EOK 	注冊成功
-RT_ERROR 	注冊失敗,dev 為空或者 name 已經存在
*/
rt_err_t rt_device_register(rt_device_t dev,
                            const char *name,
                            rt_uint16_t flags)


/*設備注冊 flag*/
#define RT_DEVICE_FLAG_DEACTIVATE       0x000           /**< device is not not initialized */

#define RT_DEVICE_FLAG_RDONLY           0x001           /**< read only */
#define RT_DEVICE_FLAG_WRONLY           0x002           /**< write only */
#define RT_DEVICE_FLAG_RDWR             0x003           /**< read and write */

#define RT_DEVICE_FLAG_REMOVABLE        0x004           /**< removable device */
#define RT_DEVICE_FLAG_STANDALONE       0x008           /**< standalone device */
#define RT_DEVICE_FLAG_ACTIVATED        0x010           /**< device is activated */
#define RT_DEVICE_FLAG_SUSPENDED        0x020           /**< device is suspended */
#define RT_DEVICE_FLAG_STREAM           0x040           /**< stream mode */

#define RT_DEVICE_FLAG_INT_RX           0x100           /**< INT mode on Rx */
#define RT_DEVICE_FLAG_DMA_RX           0x200           /**< DMA mode on Rx */
#define RT_DEVICE_FLAG_INT_TX           0x400           /**< INT mode on Tx */
#define RT_DEVICE_FLAG_DMA_TX           0x800           /**< DMA mode on Tx */
上面需要額外說明的一點,設備流模式 `RT_DEVICE_FLAG_STREAM` 參數用于向串口終端輸出字符串:
當輸出的字符是 “\n” 時,自動在前面補一個 “\r” 做分行。

2.2.4 設備注銷

創建對銷毀,注冊對注銷:

/**
參數 	描述
dev 	設備句柄
返回 	——
RT_EOK 	成功
 */
rt_err_t rt_device_unregister(rt_device_t dev)

當設備注銷后的,設備將從設備管理器中移除,也就不能再通過設備查找搜索到該設備。注銷設備不會釋放設備控制塊占用的內存。
注銷只是把這個 設備對象結構體 從管理鏈表中去掉,并不會釋放這個對象結構體的空間,要釋放空間需要調用銷毀設備函數。

?? 創建 I/O 設備相關的函數,和 I/O 設備模型框架中 設備驅動層 有關,在我們底層寫驅動的時候需要使用。

2.3 訪問 I/O 設備相關

上面我們說的創建 I/O 設備相關是和 設備驅動層 有關的代碼,本小結說的訪問 I/O 設備就是和 應用程序有關的代碼,就是告訴我們應用程序怎么去操作我們上面創建的設備。

I/O 設備管理接口與 I/O 設備的操作方法的映射關系下圖:

pYYBAGK9DJmAYOf9AAERyxaJSRg014.png

2.3.1 查找設備

注冊過的設備才能被查找到,名字對應注冊時候使用的名字:

/**
參數 	描述
name 	設備名稱
返回 	——
設備句柄 	查找到對應設備將返回相應的設備句柄
RT_NULL 	沒有找到相應的設備對象
 */
rt_device_t rt_device_find(const char *name)

2.3.2 初始化設備

對應底層rt_err_t (*init) (rt_device_t dev); 的實現函數:

/**
參數 	描述
dev 	設備句柄
返回 	——
RT_EOK 	設備初始化成功
錯誤碼 	設備初始化失敗
 */
rt_err_t rt_device_init(rt_device_t dev)

當一個設備已經初始化成功后,調用這個接口將不再重復做初始化 0。

2.3.3 打開和關閉設備

打開設備:

對應底層rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag); 的實現函數:

/*
參數 	描述
dev 	設備句柄
oflags 	設備打開模式標志,上面 2.1.3 小結說明的設備訪問 open_flag
返回 	——
RT_EOK 	設備打開成功
-RT_EBUSY 	如果設備注冊時指定的參數中包括 RT_DEVICE_FLAG_STANDALONE 參數,此設備將不允許重復打開
其他錯誤碼 	設備打開失敗
*/
rt_err_t  rt_device_open (rt_device_t dev, rt_uint16_t oflag);

#define RT_DEVICE_FLAG_INT_RX           0x100           /**< INT mode on Rx */
#define RT_DEVICE_FLAG_DMA_RX           0x200           /**< DMA mode on Rx */
#define RT_DEVICE_FLAG_INT_TX           0x400           /**< INT mode on Tx */
#define RT_DEVICE_FLAG_DMA_TX           0x800           /**< DMA mode on Tx */

#define RT_DEVICE_OFLAG_CLOSE           0x000           /**< 設備已經關閉(內部使用) */
#define RT_DEVICE_OFLAG_RDONLY          0x001           /**< read only access */
#define RT_DEVICE_OFLAG_WRONLY          0x002           /**< write only access */
#define RT_DEVICE_OFLAG_RDWR            0x003           /**< read and write */
#define RT_DEVICE_OFLAG_OPEN            0x008           /**< device is opened */
#define RT_DEVICE_OFLAG_MASK            0xf0f           /**< mask of open flag */

注:如果上層應用程序需要設置設備的接收回調函數,則必須以 RT_DEVICE_FLAG_INT_RX 或者 RT_DEVICE_FLAG_DMA_RX 的方式打開設備,否則不會回調函數。

關閉設備:

對應底層rt_err_t (*close) (rt_device_t dev); 的實現函數:

/*
dev 	設備句柄
返回 	——
RT_EOK 	關閉設備成功
-RT_ERROR 	設備已經完全關閉,不能重復關閉設備
其他錯誤碼 	關閉設備失敗
*/
rt_err_t  rt_device_open (rt_device_t dev, rt_uint16_t oflag);

關閉設備接口和打開設備接口需配對使用,打開一次設備對應要關閉一次設備,這樣設備才會被完全關閉,否則設備仍處于未關閉狀態。

2.3.4 讀寫設備

讀設備:

對應底層rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); 的實現函數:

/**
參數 	描述
dev 	設備句柄
pos 	讀取數據偏移量
buffer 	內存緩沖區指針,讀取的數據將會被保存在緩沖區中
size 	讀取數據的大小
返回 	——
讀到數據的實際大小 	如果是字符設備,返回大小以字節為單位,如果是塊設備,返回的大小以塊為單位
0 	需要讀取當前線程的 errno 來判斷錯誤狀態
 */
rt_size_t rt_device_read(rt_device_t dev,
                         rt_off_t    pos,
                         void       *buffer,
                         rt_size_t   size)

調用這個函數,會從 dev 設備中讀取數據,并存放在 buffer 緩沖區中,這個緩沖區的最大長度是 size,pos 根據不同的設備類別有不同的意義。

寫設備:

對應底層rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); 的實現函數:

/**
參數 	描述
dev 	設備句柄
pos 	寫入數據偏移量
buffer 	內存緩沖區指針,放置要寫入的數據
size 	寫入數據的大小
返回 	——
寫入數據的實際大小 	如果是字符設備,返回大小以字節為單位;如果是塊設備,返回的大小以塊為單位
0 	需要讀取當前線程的 errno 來判斷錯誤狀態
 */
rt_size_t rt_device_write(rt_device_t dev,
                          rt_off_t    pos,
                          const void *buffer,
                          rt_size_t   size)

調用這個函數,會把緩沖區 buffer 中的數據寫入到設備 dev 中,寫入數據的最大長度是 size,pos 根據不同的設備類別存在不同的意義。

2.3.5 控制設備

對應底層rt_err_t (*control)(rt_device_t dev, int cmd, void *args); 的實現函數:

/**
參數 	描述
dev 	設備句柄
cmd 	命令控制字,這個參數通常與設備驅動程序相關,見下面列出的參數
arg 	控制的參數
返回 	——
RT_EOK 		函數執行成功
-RT_ENOSYS 	執行失敗,dev 為空
其他錯誤碼 	執行失敗
 */
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)


/**
 * general device commands 上面 cmd 的參數
 */
#define RT_DEVICE_CTRL_RESUME           0x01            /**< resume device */
#define RT_DEVICE_CTRL_SUSPEND          0x02            /**< suspend device */
#define RT_DEVICE_CTRL_CONFIG           0x03            /**< configure device */
#define RT_DEVICE_CTRL_CLOSE            0x04            /**< close device */

#define RT_DEVICE_CTRL_SET_INT          0x10            /**< set interrupt */
#define RT_DEVICE_CTRL_CLR_INT          0x11            /**< clear interrupt */
#define RT_DEVICE_CTRL_GET_INT          0x12            /**< get interrupt status */

2.3.6 數據收發回調

這個對于 設備控制塊中參數中的兩個設備回調函數:

poYBAGK9DJmAQ-FvAAAjUuLwMOc015.png

硬件設備收到數據:

/**
參數 	描述
dev 	設備句柄
rx_ind 	回調函數指針
返回 	——
RT_EOK 	設置成功
 */
rt_err_t
rt_device_set_rx_indicate(rt_device_t dev,
                          rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size))

該函數的回調函數由調用者提供。當硬件設備接收到數據時,會回調這個函數并把收到的數據長度放在 size 參數中傳遞給上層應用。上層應用線程應在收到指示后,立刻從設備中讀取數據。

硬件設備發送數據:

在應用程序調用 rt_device_write() 寫入數據時,如果底層硬件能夠支持自動發送,那么上層應用可以設置一個回調函數。
這個回調函數會在底層硬件數據發送完成后 (例如 DMA 傳送完成或 FIFO 已經寫入完畢產生完成中斷時) 調用。

通過如下函數設置設備發送完成指示:

/**
參數 	描述
dev 	設備句柄
tx_done 	回調函數指針
返回 	——
RT_EOK 	設置成功
 */
rt_err_t
rt_device_set_tx_complete(rt_device_t dev,
                          rt_err_t (*tx_done)(rt_device_t dev, void *buffer))

調用這個函數時,回調函數由調用者提供,當硬件設備發送完數據時,由驅動程序回調這個函數并把發送完成的數據塊地址 buffer 作為參數傳遞給上層應用。上層應用(線程)在收到指示時會根據發送 buffer 的情況,釋放 buffer 內存塊或將其作為下一個寫數據的緩存。

?? 訪問 I/O 設備相關的函數,和 I/O 設備模型框架中 應用程序 有關,是我們上層寫應用程序直接調用的函數。

三、新建 I/O 設備模型實例

RT-Thread 驅動都是在 drivers 目錄下面:

poYBAGK9DJmAYVBuAABCG9j0hGQ134.png

我們在目錄下新建一個文件,作為驅動示例:

pYYBAGK9DJmAbSWvAADKwnU6FFs295.png

我們寫一個簡單的基本框架:

1、創建一個設備;
   使用 rt_device_create 創建一個設備,需要定義一個 rt_device_t 接口體接收設備設備句柄。

2、實現設備操作的函數:
   實現設備對象中對于 設備操作的init,open,close等 函數。

3、注冊設備到 I/O 設備管理器;
   使用 rt_device_register 將設備注冊到設備管理器。

drv_demo.c中,我們實現如下代碼:

poYBAGK9DJmALQEkAABuTuaInAY314.png

其次,我們需要實現一下設備操作的函數:

pYYBAGK9DJqAQYcpAABPqLr1W74608.png

最后,別忘了使用 INIT_BOARD_EXPORT 把設備初始化的代碼加入板級硬件初始化:

poYBAGK9DJqABG66AAAffT8TlJ8363.png

上一下設備模型實例代碼:

#include 
#include 

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

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 -1;
    }

    demo_dev->init=demo_init;
    demo_dev->open=demo_open;
    demo_dev->close=demo_cloes;

    rt_device_register(demo_dev,"drvdemo",RT_DEVICE_FLAG_RDWR);
    return 0;
}


INIT_BOARD_EXPORT(rt_drvdemo_init);

上面我們完成的是 設備驅動層的 代碼,接下來我們還需要簡單演示一下,如果在應用層 使用這個 demo 設備。

我們根據上文所介紹的 訪問 I/O 設備 進行對應操作,這里直接上圖說明一下使用流程:

pYYBAGK9DJqAJv7QAACs50bc4uU608.png

看一下測試結果,我們實現的 3 個驅動函數都只有打印輸出,所以我們可以通過打印信息查看是否正確執行的驅動函數的內容:

poYBAGK9DJqAR76DAACrGvu2Bvw047.png

通過上面的測試,我們實現了一個簡單的設備驅動的設計,雖然demo比較簡單,但是經過這么一個過程可以讓我們更加的理解 RT-Thread I/O 設備模型的工作方式和流程。

結語

本文全面了解了 RT-Thread I/O 設備模型,說明了設備模型存在的意義,描述了一下設備模型相關的操作函數,最后使用了一個新建 I/O設備模型的例子,說明了 I/O 設備模型 的工作方式。

在我們使用 RT-Thread 的時候,其實大部分常用的設備 RT-Thread 已經幫我們寫好了驅動,我們直接在應用層調用操作接口即可,接下來的系列文章我們將要學習 RT-Thread 常用的 I/O 設備模型。


?? 希望開頭的愿景能夠實現,通過本文讓所有人了解 RT-Thread I/O 設備模型 (* ̄︶ ̄) ??

本文就到這里,謝謝大家!

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    3

    文章

    1416

    瀏覽量

    41374
  • Linux
    +關注

    關注

    87

    文章

    11508

    瀏覽量

    213607
  • 模型
    +關注

    關注

    1

    文章

    3516

    瀏覽量

    50360
  • RT-Thread
    +關注

    關注

    32

    文章

    1402

    瀏覽量

    41856
收藏 1人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

  • jf_519550031
  • 晨起晨雨1
  • just_20101

評論

相關推薦
熱點推薦

RT-Thread榮獲2025優秀開源項目 | 新聞速遞

6月底,RT-Thread睿賽德受邀參與由上海開源信息技術協會主辦的2025上海開源創新精英薈。上海市商委副主任張杰出席會議并致辭。RT-Thread嵌入式操作系統項目憑借其卓越的技術創新與開源生態
的頭像 發表于 07-04 09:04 ?1390次閱讀
<b class='flag-5'>RT-Thread</b>榮獲2025優秀開源項目 | 新聞速遞

RT-Thread BSP全面支持玄鐵全系列RISC-V 處理器 | 技術集結

RT-Thread標準版已全面適配玄鐵E、R、C系列內核,并在C906內核上支持RT-Smart微內核操作系統。本文將以E906運行RT-Thread和C906運行
的頭像 發表于 07-03 18:03 ?1439次閱讀
<b class='flag-5'>RT-Thread</b> BSP<b class='flag-5'>全面</b>支持玄鐵全系列RISC-V 處理器 | 技術集結

揭秘RT-Thread上的AUTOSAR CP系統

本文探討了RT-Thread與AUTOSARCP的融合,解決車載ECU開發中實時性、安全性與靈活性的平衡問題。通過分層安全內核(rt-safetyos/autoos)和工具鏈整合,兼容AUTOSAR
的頭像 發表于 06-23 20:22 ?2288次閱讀
揭秘<b class='flag-5'>RT-Thread</b>上的AUTOSAR CP系統

RT-Thread審核團招募: 深度參與開源RTOS社區治理與演進

全球開發者招募:RT-Thread審核團(ReviewTeam)正式開放申請!在開源的世界里,代碼審查(CodeReview)是保證軟件質量、促進技術交流的關鍵環節。RT-Thread作為全球領先
的頭像 發表于 05-21 18:02 ?630次閱讀
<b class='flag-5'>RT-Thread</b>審核團招募: 深度參與開源RTOS社區治理與演進

如何將RT-Thread移植到NXP MCUXPressoIDE上

RT-Thread默認支持的IDE只有IAR 和 Keil, 那如何將RT-Thread移植到NXP MCUXPressoIDE上呢?本文內容比較簡單但稍有瑣碎,希望對有需要的小伙伴有所幫助。
的頭像 發表于 02-13 10:37 ?1893次閱讀
如何將<b class='flag-5'>RT-Thread</b>移植到NXP MCUXPressoIDE上

Deepseek上單片機?RT-Thread上跑通大語言模型

前言單片機也能聊天?RT-Thread上跑通大語言模型RT-Thread論壇上忽然看到了單片機和大模型對話的文章,想著春節期間看到大語言模型
的頭像 發表于 02-07 18:59 ?1429次閱讀
Deepseek上單片機?<b class='flag-5'>RT-Thread</b>上跑通大語言<b class='flag-5'>模型</b>

RT-Smart首次線下培訓,鎖定2024 RT-Thread開發者大會!

2024年RT-Thread開發者大會將于12月21日正式拉開帷幕!本次大會以“開源共生商業共贏”為主題,RT-Thread將攜手合作伙伴、客戶伙伴、行業專家,以及全球開發者,共同探索如何在開源
的頭像 發表于 12-11 18:41 ?1969次閱讀
<b class='flag-5'>RT</b>-Smart首次線下培訓,鎖定2024 <b class='flag-5'>RT-Thread</b>開發者大會!

RT-Thread上CAN實踐

開箱測試RT-Thread官方已完成了對英飛凌XMC7200EVK的移植,通過shell可以看到做好了uart3的console。本文將介紹如何進行RT-ThreadCan移植。接下來我們要完成CAN_FD的驅動移植,并正常啟動RT-T
的頭像 發表于 11-13 01:03 ?2094次閱讀
<b class='flag-5'>RT-Thread</b>上CAN實踐

開源共生 商業共贏 | RT-Thread 2024開發者大會報名啟動!

親愛的RT-Thread開發者我們很高興地宣布,一年一度的RDC(RT-ThreadDeveloperConference,RT-Thread開發者大會)正式啟動報名!2024RT-Threa
的頭像 發表于 10-29 08:06 ?949次閱讀
開源共生 商業共贏 | <b class='flag-5'>RT-Thread</b> 2024開發者大會報名啟動!

跟著RT-Thread學嵌入式?我們開班了!

RT-Thread官方即將發起為期三天的嵌入式操作系統專業培訓班!本次培訓將會深入講解RT-Thread嵌入式實時操作系統的核心概念、實戰技巧和應用場景!無論企業團隊/工程師是剛接觸嵌入式開發,還是
的頭像 發表于 10-22 08:05 ?519次閱讀
跟著<b class='flag-5'>RT-Thread</b>學嵌入式?我們開班了!

新書發布——《RT-Thread嵌入式實時操作系統內核、驅動和應用開發技術》

成,旨在深入淺出地介紹RT-Thread的內核設計、設備驅動開發及應用開發技術。書中將理論與實踐相結合,幫助讀者全面理解和掌握RT-Thread的各項關鍵技術。全書共
的頭像 發表于 09-03 08:06 ?1334次閱讀
新書發布——《<b class='flag-5'>RT-Thread</b>嵌入式實時操作系統內核、驅動和應用開發技術》

【大連】9月7日RT-Thread巡回線下培訓-OpenMV機器視覺

親愛的RT-Thread社區成員們:2024年RT-Thread全球開發者線下培訓拉開帷幕啦!24年全球巡回培訓將覆蓋超10座城市及國家,為開發者提供一個深入學習RT-Thread嵌入式開發的絕佳
的頭像 發表于 09-01 08:02 ?3712次閱讀
【大連】9月7日<b class='flag-5'>RT-Thread</b>巡回線下培訓-OpenMV機器視覺

2024 RT-Thread全球巡回 線下培訓火熱來襲!

親愛的RT-Thread社區成員們:我們非常高興地宣布,2024年RT-Thread全球開發者線下培訓即將拉開帷幕!24年全球巡回培訓將覆蓋超10座城市及國家,為開發者提供一個深入學習RT-Thread嵌入式開發的絕佳機會。
的頭像 發表于 08-07 08:35 ?2873次閱讀
2024 <b class='flag-5'>RT-Thread</b>全球巡回 線下培訓火熱來襲!

【好書推薦】RT-Thread設備驅動開發指南

強烈,他們迫切地希望有一本可以指導他們在RT-Thread上開發驅動的指南。為了解決開發者的燃眉之急,《RT-Thread設備驅動開發指南》來了!希望幫助RT-Thre
的頭像 發表于 08-01 08:35 ?1314次閱讀
【好書推薦】<b class='flag-5'>RT-Thread</b><b class='flag-5'>設備</b>驅動開發指南

RT-Thread內部機制大揭秘,帶你深入操作系統內核

一、RT-Thread概述RT-Thread是一款具有顯著優勢的開源嵌入式實時操作系統。它不僅具備輕量級、實時性強的特點,還擁有廣泛的開源社區支持和豐富的應用場景。在輕量級方面,RT-Thread
的頭像 發表于 08-01 08:11 ?5111次閱讀
<b class='flag-5'>RT-Thread</b>內部機制大揭秘,帶你深入操作系統內核
主站蜘蛛池模板: 欧美美女性生活 | 性欧美sexovideotv | 甜性涩爱在线播放 | 美国兽皇zoo在线播放 | 亚洲福利天堂网福利在线观看 | 51精品少妇人妻AV一区二区 | 亚洲国产成人久久一区www妖精 | 性夜影院午夜看片 | 三级黄色在线视频 | 美女被j进去动态 | 中文字幕永久在线观看 | 国产专区青青草原亚洲 | 亚洲免费人成 久久 | 欧美高清视频www夜色资源网 | 久久久无码精品亚洲日韩按摩 | 吃春药后的女教师 | 国产在线观看黄 | 午夜熟女插插XX免费视频 | 黄色直接观看 | 欧美人与禽zoz0性伦交app | 一个人日本的视频免费完整版 | 久久三级网站 | jiizzyou欧美喷液 | 99久久蜜臀AV免费看蛮 | 国产精品资源在线观看网站 | 久久成人亚洲 | 国产精品AV视频一二三区 | 免费视频网站嗯啊轻点 | 精品亚洲永久免费精品 | 久久re视频精品538在线 | 久久视热频国产这里只有精品23 | 久久国产精品免费A片蜜芽 久久国产精品萌白酱免费 久久国产精品麻豆AV影视 | 亚洲精品线在线观看 | 美女叉腿掰阴大胆艺术照 | 亚洲三级在线看 | 国产成久久免费精品AV片天堂 | 东北真实仑乱 | qvod电影网| 国产人成精品综合欧美成人 | 黄A无码片内射无码视频 | 欧美激情一区二区三区视频 |

電子發燒友

中國電子工程師最喜歡的網站

  • 2931785位工程師會員交流學習
  • 獲取您個性化的科技前沿技術信息
  • 參加活動獲取豐厚的禮品