從 UART 設備開始學會使用 RT-Thread I/O 設備模型 。
目錄
前言
一、UART 設備操作
1.1 UART 設備控制塊
1.2 UART 操作函數
1.2.1 查找 UART 設備
1.2.2 打開/關閉 UART 設備
實際應用中的串口讀寫說明
1.2.3 控制 UART 設備
1.2.4 發送數據
1.2.5 設置接收回調函數
1.2.6 接收數據
二、UART 設備使用步驟
2.1 RT-Thread setting
2.2 board.h 設置
2.3 應用程序流程
三、UART 示例測試
3.1 與無線模塊串口通訊
3.2 示例說明
結語
前言
通過前面的兩篇文章,我們基本上完全明白了 RT-Thread I/O 設備模型的基本原理,當然我們的最終目的還是應用,所以本文開始我們就開始進行常用設備的使用學習和測試,就從 UART 設備開始。
從本文開始,就開始進行常用 I/O 設備的學習測試。
本 RT-Thread 專欄記錄的開發環境:
RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發環境 及 配合CubeMX開發快速上手)
RT-Thread記錄(二、RT-Thread內核啟動流程 — 啟動文件和源碼分析)
RT-Thread 設備篇系列博文鏈接:
RT-Thread記錄(十、全面認識 RT-Thread I/O 設備模型)
RT-Thread記錄(十一、I/O 設備模型之UART設備 — 源碼解析)
一、UART 設備操作
雖然在上一篇文章中,我們已經認識過 RT-Thread UART 的操作函數,但是我們并沒有對其參數進行說明。
學習使用一個設備,在 RT-Thread 系統中就是一個對象, 還是得按照我們之前的流程進行簡單介紹。
1.1 UART 設備控制塊
在我們前面許多文章介紹其他內核對象的時候,我們首先都會介紹其對象控制塊,對于 UART 設備而言,它也有自己的控制塊。
但是與其他對象機制不同的是,UART 屬于 I/O 設備,對于上層應用程序而言,所有的 I/O 設備都是屬于 struct rt_device
類。
在我們前面文章《RT-Thread記錄(十、全面認識 RT-Thread I/O 設備模型》初次介紹 I/O 設備模型的時候就已經說明了這個統一的控制塊:
![poYBAGK_zLyAHSI4AAFJTr2oFO8861.png](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zLyAHSI4AAFJTr2oFO8861.png)
上面的控制塊是對于應用程序而言,在我們的 UART 設備的設備驅動框架層,是有定義了 UART 設備自己的控制塊,其繼承了rt_device
的內容,同時還增加了 UART 設備特有的一些配置,操作,回調函數之類的內容,如下圖:
![pYYBAGK_zLyAGs_VAABHg_EJRBM341.png](https://file.elecfans.com//web2/M00/4F/4C/pYYBAGK_zLyAGs_VAABHg_EJRBM341.png)
上面的 UART 設備控制塊在我們的上一篇文章也有過分析說明。
?? UART 設備屬于 I/O 設備大類中的一個小類,對于上層應用程序而言,UART 設備控制塊rt_serial_device
并不透明,我們用戶操作的還是 I/O 設備模型的控制塊rt_device_t
類型。
1.2 UART 操作函數
因為 UART 的操作函數 與 I/O 設備的操作函數基本一致,所以本小結有點類似《RT-Thread記錄(十、全面認識 RT-Thread I/O 設備模型》中的 2.3 訪問 I/O 設備相關 API 操作,但是針對 UART 設備,也有一些獨有的參數說明。
老規矩,函數介紹部分說明看注釋。
1.2.1 查找 UART 設備
需要先定義一個 I/O 設備結構體(rt_device_t
類型)的指針變量,接收創建好的句柄。
/*
參數 描述
name 設備名稱,對于UART設備而言,默認一般是 uart0,uart1,uart2,uart3 等
返回 ——
設備句柄 查找到對應設備將返回相應的設備句柄
RT_NULL 沒有找到相應的設備對象
*/
rt_device_t rt_device_find(const char* name);
1.2.2 打開/關閉 UART 設備
先說打開 UART 設備:
/**
參數 描述
dev 設備句柄
oflags 設備模式標志
oflags可選的的值如下:
#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_EOK 設備打開成功
-RT_EBUSY 如果設備注冊時指定的參數中包括 RT_DEVICE_FLAG_STANDALONE 參數,此設備將不允許重復打開
其他錯誤碼 設備打開失敗
*/
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
打開設備時,會檢測設備是否已經初始化,沒有初始化則會默認調用初始化接口初始化設備。
如果 oflags 沒有指定使用中斷模式或者 DMA 模式,則默認使用輪詢模式。
這里有個問題,流模式是什么情況下使用的?485通訊? 暫時不知道,希望知道的朋友能夠給個說明。
在官方的文檔中,關于流模式有如下說明:
![poYBAGK_zLyAA2QVAAB8BN8W5nI975.png](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zLyAA2QVAAB8BN8W5nI975.png)
實際應用中的串口讀寫說明
串口RX:
在我們正常的項目使用中,一般都是 中斷接收 或者 DMA 接收,基本上不會使用 輪詢接收的方式(極大的浪費資源,反正我是沒用過)。
所以我們打開串口設備的時候,基本上都是如下兩種:
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
在 RT-Thread 系統中,我們常用信號量或者消息隊列 來標志是否接收到串口數據,這樣的好處是當沒有數據的時候,會將數據處理線程掛機,讓出CPU資源。
串口TX:
對于串口 TX 來說,大部分項目中我自己一直都用的是 輪詢 方式發送。
對于串口的中斷發送方式,在上一篇文章我們分析 UART 源碼,雖然沒有詳細說明,但是實際上在設備驅動層 drv_usart.c
驅動文件里,中斷發送方式最終還是調用了該驅動文件里面的stm32_putc
函數:
![pYYBAGK_zLyAKHpmAACFz153GM8372.png](https://file.elecfans.com//web2/M00/4F/4C/pYYBAGK_zLyAKHpmAACFz153GM8372.png)
我感覺還是和輪詢一樣,將數據寫入 數據寄存器DR,使用while死等發送完成(雖然時間很短)。
上面雖然只是 RT-Thread 中的UART設備驅動文件,也多少能說明一些問題,中斷發送最終無非就是發送完了多一個中斷通知。
對于另外一種 DMA 發送,我記得以前聽老人提到過,DMA發送使用不得當,可能導致發送數據異常,簡單來說就是 DMA 發送函數返回后,數據都不一定發送完成了,如果此時修改了 DMA 發送指定的buffer 區的內容,那么后面的數據就錯誤了。
所以,如果沒有特殊需求,我們項目中的串口發送使用 輪詢發送 即可(有些特殊情況的根據自己的實際需求而定)。
所以結合上面所說,我們實際應用中,使用以下兩種方式打開串口設備能滿足大部分場合需求:
/*輪詢方式發送,中斷接收*/
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
/*輪詢方式發送,DMA接收*/
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
有打開設備,當然也有關閉設備:
/**
參數 描述
dev 設備句柄
返回 ——
RT_EOK 關閉設備成功
-RT_ERROR 設備已經完全關閉,不能重復關閉設備
其他錯誤碼 關閉設備失敗
*/
rt_err_t rt_device_close(rt_device_t dev)
關閉設備接口和打開設備接口需配對使用,打開一次設備對應要關閉一次設備,這樣設備才會被完全關閉,否則設備仍處于未關閉狀態。
當然在一般的應用場合,用到串口通訊的地方設備都是需要一直開啟的,所以很多情況下都不需要使用 UART 設備關閉函數。
1.2.3 控制 UART 設備
rt_device_control
一般用在 rt_device_open
(打開串口設備)之前,對需要使用的串口進行必要的配置。
/**
參數 描述
dev 設備句柄
cmd 命令控制字,可取值:RT_DEVICE_CTRL_CONFIG
arg 控制的參數,可取類型:
struct serial_configure
{
rt_uint32_t baud_rate; 波特率
rt_uint32_t data_bits :4; 數據位
rt_uint32_t stop_bits :2; 停止位
rt_uint32_t parity :2; 奇偶校驗位
rt_uint32_t bit_order :1; 高位在前或者低位在前
rt_uint32_t invert :1; 模式
rt_uint32_t bufsz :16; 接收數據緩沖區大小
rt_uint32_t reserved :4; 保留位
};
波特率可取值:
#define BAUD_RATE_2400 2400
#define BAUD_RATE_4800 4800
#define BAUD_RATE_9600 9600
#define BAUD_RATE_19200 19200
#define BAUD_RATE_38400 38400
#define BAUD_RATE_57600 57600
#define BAUD_RATE_115200 115200
#define BAUD_RATE_230400 230400
#define BAUD_RATE_460800 460800
#define BAUD_RATE_921600 921600
#define BAUD_RATE_2000000 2000000
#define BAUD_RATE_3000000 3000000
數據位可取值:
#define DATA_BITS_5 5
#define DATA_BITS_6 6
#define DATA_BITS_7 7
#define DATA_BITS_8 8
#define DATA_BITS_9 9
停止位可取值:
#define STOP_BITS_1 0
#define STOP_BITS_2 1
#define STOP_BITS_3 2
#define STOP_BITS_4 3
極性位可取值:
#define PARITY_NONE 0
#define PARITY_ODD 1
#define PARITY_EVEN 2
高低位順序可取值:
#define BIT_ORDER_LSB 0
#define BIT_ORDER_MSB 1
模式可取值:
#define NRZ_NORMAL 0
#define NRZ_INVERTED 1
接收數據緩沖區默認大小:
#define RT_SERIAL_RB_BUFSZ 64
返回 ——
RT_EOK 函數執行成功
-RT_ENOSYS 執行失敗,dev 為空
其他錯誤碼 執行失敗
*/
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
我們已經知道,在串口初始化的時候會有一個默認配置:
![poYBAGK_zL2AVRCOAABcGXgNRJw568.png](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zL2AVRCOAABcGXgNRJw568.png)
所以在我們使用串口的時候,如果對應的配置與默認的配置不一樣,就需要使用此函數修改配置。
接收緩沖區:
當串口使用中斷接收模式打開時,串口驅動框架會根據 RT_SERIAL_RB_BUFSZ 大小開辟一塊緩沖區用于保存接收到的數據,底層驅動接收到一個數據,都會在中斷服務程序里面將數據放入緩沖區。
在修改緩沖區大小時請注意,緩沖區大小無法動態改變,只有在 open 設備之前可以配置。open 設備之后,緩沖區大小不可再進行更改。但除緩沖區之外的其他參數,在 open 設備前 / 后,均可進行更改。
串口控制修改使用官方修改示例說明一下:
#define SAMPLE_UART_NAME "uart2" /* 串口設備名稱 */
static rt_device_t serial; /* 串口設備句柄 */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置參數 */
/* step1:查找串口設備 */
serial = rt_device_find(SAMPLE_UART_NAME);
/* step2:修改串口配置參數 */
config.baud_rate = BAUD_RATE_9600; //修改波特率為 9600
config.data_bits = DATA_BITS_8; //數據位 8
config.stop_bits = STOP_BITS_1; //停止位 1
config.bufsz = 128; //修改緩沖區 buff size 為 128
config.parity = PARITY_NONE; //無奇偶校驗位
/* step3:控制串口設備。通過控制接口傳入命令控制字,與控制參數 */
rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
/* step4:打開串口設備。以中斷接收及輪詢發送模式打開串口設備 */
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
1.2.4 發送數據
/**
參數 描述
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)
寫其實很好理解,除了多一個設備句柄參數,和我們裸機中使用的發送函數一樣,看一下一個普通的裸機串口發送函數:
![在這里插入圖片描述](https://file.elecfans.com//web2/M00/4F/4C/pYYBAGK_zL2Ac2JCAABS0PYvv7U156.png)
這里說明一下,因為我們上面分析過實際應用中的串口讀寫,一般都使用輪詢發送,所以我這里并不打斷介紹 設置發送完成回調函數 。
1.2.5 設置接收回調函數
/**
參數 描述
dev 設備句柄
rx_ind 回調函數指針
回調函數參數 描述
dev 設備句柄
size 緩沖區數據大小
返回 ——
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 參數里,把串口設備句柄放在 dev 參數里供調用者獲取。
若串口以 DMA 接收模式打開:
當 DMA 完成一批數據的接收后會調用此回調函數。
在使用 RT-Thread 時候,一般會用一個信號量通知串口數據處理線程有數據到達。
在使用 RT-Thread Nano 的時候,其實我也是使用信號量來處理數據的接收:
![poYBAGK_zL2AfCgPAACDwyGuchk435.png](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zL2AfCgPAACDwyGuchk435.png)
具體詳情可查看博文:RT-Thread 應用篇 — 在STM32L051上使用 RT-Thread (四、無線溫濕度傳感器 之 串口通訊)
回調函數處理的示例我們使用官方示例說明,與下面的接收數據函數一起展示。
1.2.6 接收數據
數據接收處理函數,在接收回調函數運行之后運行。
/**
參數 描述
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)
我們與上面的設置接收回調函數一起使用官方示例作為說明:
#define SAMPLE_UART_NAME "uart2" /* 串口設備名稱 */
static rt_device_t serial; /* 串口設備句柄 */
static struct rt_semaphore rx_sem; /* 用于接收消息的信號量 */
/* 接收數據回調函數 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
/* 串口接收到數據后產生中斷,調用此回調函數,然后發送接收信號量 */
rt_sem_release(&rx_sem);
return RT_EOK;
}
/* 接收數據的線程 */
static void serial_thread_entry(void *parameter)
{
char ch;
while (1)
{
/* 從串口讀取一個字節的數據,沒有讀取到則等待接收信號量 */
while (rt_device_read(serial, -1, &ch, 1) != 1)
{
/* 阻塞等待接收信號量,等到信號量后再次讀取數據 */
rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
}
/* 讀取到的數據通過串口錯位輸出 */
ch = ch + 1;
rt_device_write(serial, 0, &ch, 1);
}
}
static int uart_sample(int argc, char *argv[])
{
serial = rt_device_find(SAMPLE_UART_NAME);
/* 以中斷接收及輪詢發送模式打開串口設備 */
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
/* 初始化信號量 */
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
/* 設置接收回調函數 */
rt_device_set_rx_indicate(serial, uart_input);
}
示例中使用的是信號量,收到一個數據,便會喚醒接收數據的線程,所以其實是一個字節一個字節(一個字符等于一個字節)的讀取, 示例處理方式只能使用 RT_DEVICE_FLAG_INT_RX
方式接收。
?? 接收數據rt_device_read
函數的返回值需要注意一下,返回值為讀到的數據實際大小,就是接收到的數據長度。
二、UART 設備使用步驟
簡單介紹一下在 RT-Thread Studio 開發環境下 UART的使用步驟。
2.1 RT-Thread setting
如果需要使用某個設備,是需要在 ENV 工具中配置的,現在有了 RT-Thread Studio ,所以可以直接通過工程目錄下的 RT-Thread setting 進行圖形化界面的配置,如下圖:
![pYYBAGK_zL2AOO30AAGiQw6GNs0322.png](https://file.elecfans.com//web2/M00/4F/4C/pYYBAGK_zL2AOO30AAGiQw6GNs0322.png)
因為Shell 工具需要使用串口,所以默認串口這里已經是勾選中的,這里說明只是為了讓大家知道,在以后的 I/O 設備使用的時候,第一步就是在 RT-Thread setting 中使能設備。
2.2 board.h 設置
完成設備使能,我們還需要使用宏定義進行串口的基本設置,該設置在board.h
文件中進行,如下圖:
![poYBAGK_zL6AXbZVAAGLwOlBCiI124.png](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zL6AXbZVAAGLwOlBCiI124.png)
board.h
中包括了很多外設的使用說明,除了 UART,還有I2C、SPI、ADC等設備,我們在后面學習這些設備使用的時候,需要經常用到這個頭文件,一些基本的使能配置都是在這個文件中用宏定義使能。
2.3 應用程序流程
完成上面 2 步的基本配置以后,我們就可以在應用程序通過上文介紹的 UART 設備操作函數進行串口的使用,具體的步驟概括如下:
UART 設備使用步驟 :
/
#include "rtdevice.h"
/
1、使用rt_device_find查找串口設備;
/
2、根據需求使用rt_device_control設置串口;
/
3、初始化回調函數中使用的信號量(在接收回調函數中 發送信號量 喚醒數據處理線程),如果使用消息隊列接收初始化消息隊列;
/
4、使用rt_device_open打開串口設備(根據自己的情況判斷使用什么方式接收,發送前面分析過了,一本應用使用輪詢發送即可);
/
5、使用rt_device_set_rx_indicate設置串口設備的接收回調函數
/
6、創建數據讀取的線程。
按照上面的步驟,我進行了如下的示例測試,不要忘記 #include "rtdevice.h"
:
![pYYBAGK_zL6AT6liAAGDq_PkBNc310.png](https://file.elecfans.com//web2/M00/4F/4C/pYYBAGK_zL6AT6liAAGDq_PkBNc310.png)
上圖其實是根據官方示例代碼,使用的 ESP8266 WIFI 模塊做了一個簡單的測試:
![poYBAGK_zL-AcCXrAAShKhg1Xhs811.png](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zL-AcCXrAAShKhg1Xhs811.png)
三、UART 示例測試
在上面介紹應用程序流程的時候,其實已經做了一個簡單的示例測試。
同時在官方已經也提供了3種典型的示例程序:
中斷接收及輪詢發送、DMA 接收及輪詢發送、串口接收不定長數據
作為以應用為目的系列博文,我自己還是根據自己的工作需求進行串口通訊的測試,使用的是 Enocean 無線通訊模塊,當時在 RT-Thread 的應用篇,RT-Thread Nano 使用記錄的時候就使用的這個無線模塊。
要說明的是,用什么模塊做通訊并不是重點,重點在于使用過程中對串口數據的處理方式。
3.1 與無線模塊串口通訊
雖然換了一個通訊設備,但是官方給的例程:中斷接收及輪詢發送 還是適用的,我們先來看一看直接使用官方的例程做的測試:
/* 接收數據回調函數 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
/* 串口接收到數據后產生中斷,調用此回調函數,然后發送接收信號量 */
rt_sem_release(&rx_sem);
return RT_EOK;
}
static void test_thread_entry(void *par){
uint8_t ch;
while (1)
{
/* 從串口讀取一個字節的數據,沒有讀取到則等待接收信號量 */
while (rt_device_read(testuart, -1, &ch, 1) != 1)
{
/* 阻塞等待接收信號量,等到信號量后再次讀取數據 */
rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
}
rt_kprintf("%x ",ch);
}
}
其測試結果如下:
![pYYBAGK_zL-ATCMPAADTmylu_Ro038.png](https://file.elecfans.com//web2/M00/4F/4C/pYYBAGK_zL-ATCMPAADTmylu_Ro038.png)
為了更好的做數據解析,我們需要對原始的程序進行修改,使得能夠針對一幀數據一幀數據進行接收處理:
uint8_t USART_Enocean_BUF[64];
uint8_t Enocean_Data = 0;
/* 接收數據回調函數 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
Enocean_Data = size;
/* 串口接收到數據后產生中斷,調用此回調函數,然后發送接收信號量 */
rt_sem_release(&rx_sem);
return RT_EOK;
}
static void test_thread_entry(void *par){
uint8_t i = 0;
while (1)
{
if(rt_sem_take(&rx_sem, RT_WAITING_FOREVER) == RT_EOK){
while(!rt_sem_take(&rx_sem, 7));
rt_device_read(testuart, -1, USART_Enocean_BUF, Enocean_Data);
}
for (i = 0; i < Enocean_Data; ++i) {
rt_kprintf("%x ",USART_Enocean_BUF[i]);
}
rt_kprintf("\r\n");
rt_memset(&USART_Enocean_BUF, 0, sizeof(USART_Enocean_BUF));
Enocean_Data = 0;
}
}
測試結果如下,實現了我們所需要的的針對每一幀數據的接收(既然都已經可以區別每一幀數據了,所那么后續的處理也就簡單了):
![poYBAGK_zL-AVwbpAAB6DlwoloM296.png](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zL-AVwbpAAB6DlwoloM296.png)
對于數據的接收處理信號量只是其中一種。
即便是信號量,也有多種可實現行的方式,而上面我測試使用的方式也只不過其中的一種:收到第一個數據的時候等待一定的時間,然后認為是一幀數據接收完成。
這也只是判斷一幀數據接收完成的方法中的一種 = =!
3.2 示例說明
在上面我們用了信號量作為通知的方式接收串口數據,官方的示: DMA 接收及輪詢發送 采用了消息隊列的方式進行處理,表面上看起來與我們上面那種方式不一樣。
其實本質都是一樣的,都不過是給線程一個通知,并沒有“真正意義上的傳遞了消息”(比如串口接收到的數據):
![pYYBAGK_zMCAZ5zKAAEJr-YrcQ8317.png](https://file.elecfans.com//web2/M00/4F/4C/pYYBAGK_zMCAZ5zKAAEJr-YrcQ8317.png)
如果想要使用消息隊列作為緩存正常的傳輸串口接收的數據,不使用 I/O 設備模型的情況下更加適合,究其原因,如下圖分析:
![在這里插入圖片描述](https://file.elecfans.com//web2/M00/4E/B2/poYBAGK_zMCAMe11AAB10ryecoM120.png)
如上面表格所說,使用了I/O 設備模型之后,我們底層串口初始化的時候已經有了一段數據接收的buffer了,所以我們直接使用 rt_device_read 函數從驅動層的 buffer 讀取數據,用臨時 buffer 來處理就可以了(不過如果需要對處理程序,單獨設計函數,也可以用一個全局 buffer 來處理),也不過是2個buffer 的內存占用。
所以在官方的示例中,雖然給的是信號量,和消息隊列的不同的處理方式,但是究其根本還是一樣的。只是給了一個通知,這個其他的 IPC機制 比如 事件集一樣可以做到,即便不用 IPC 機制,普通簡單的應用,全局變量也未嘗不可。(對于消息隊列傳遞串口接收數據的應用,以后我還是會單獨的說明的,本文在于說明 UART 基于 I/O 設備模型的使用,所以就不做測試了 = =!)
?? 使用了 UART 設備模型,最終還是需要使用rt_device_read
函數,從內部緩存讀取串口數據,IPC只不過是給線程一個通知。
結語
一個 UART 設備畫了兩篇文章,還算是比較值得的,通過上一篇文章加深對 RT-Thread I/O 設備模型的理解,通過本文實際體驗了一把 UART 設備。
體驗上來說,還是感覺特別方便簡單的。但是這個前提條件時,能夠真正的理解 RT-Thread I/O 設備模型,理解到位才能用起來游刃有余,也能夠在以后出問題的時候更容易的發現問題,解決問題。
?? 學會了使用一個東西當然是一件慶幸的事情,但是能夠理解它才是更加重要的事情! ??
-
uart
+關注
關注
22文章
1245瀏覽量
101816 -
RT-Thread
+關注
關注
31文章
1306瀏覽量
40426
發布評論請先 登錄
相關推薦
RT-Thread記錄(十四、I/O 設備模型之ADC設備)
![<b class='flag-5'>RT-Thread</b><b class='flag-5'>記錄</b>(十四、I/O <b class='flag-5'>設備</b>模型之ADC<b class='flag-5'>設備</b>)](https://file.elecfans.com//web2/M00/4E/D6/poYBAGLCbGOATRfLAABhGCiaEOo170.png)
RT-Thread全球技術大會:RT-Thread上的單元測試框架與運行測試用例
![<b class='flag-5'>RT-Thread</b>全球技術大會:<b class='flag-5'>RT-Thread</b>上的單元<b class='flag-5'>測試</b>框架與運行<b class='flag-5'>測試</b>用例](https://file.elecfans.com/web2/M00/46/20/pYYBAGKQiKqAbP-1AAbvdJ36ehM486.png)
評論