從 UART 設備開始學會使用 RT-Thread I/O 設備模型 。
目錄
前言
一、UART 設備操作
1.1 UART 設備控制塊
1.2 UART 操作函數(shù)
1.2.1 查找 UART 設備
1.2.2 打開/關閉 UART 設備
實際應用中的串口讀寫說明
1.2.3 控制 UART 設備
1.2.4 發(fā)送數(shù)據(jù)
1.2.5 設置接收回調函數(shù)
1.2.6 接收數(shù)據(jù)
二、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 專欄記錄的開發(fā)環(huán)境:
RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發(fā)環(huán)境 及 配合CubeMX開發(fā)快速上手)
RT-Thread記錄(二、RT-Thread內(nèi)核啟動流程 — 啟動文件和源碼分析)
RT-Thread 設備篇系列博文鏈接:
RT-Thread記錄(十、全面認識 RT-Thread I/O 設備模型)
RT-Thread記錄(十一、I/O 設備模型之UART設備 — 源碼解析)
一、UART 設備操作
雖然在上一篇文章中,我們已經(jīng)認識過 RT-Thread UART 的操作函數(shù),但是我們并沒有對其參數(shù)進行說明。
學習使用一個設備,在 RT-Thread 系統(tǒng)中就是一個對象, 還是得按照我們之前的流程進行簡單介紹。
1.1 UART 設備控制塊
在我們前面許多文章介紹其他內(nèi)核對象的時候,我們首先都會介紹其對象控制塊,對于 UART 設備而言,它也有自己的控制塊。
但是與其他對象機制不同的是,UART 屬于 I/O 設備,對于上層應用程序而言,所有的 I/O 設備都是屬于 struct rt_device
類。
在我們前面文章《RT-Thread記錄(十、全面認識 RT-Thread I/O 設備模型》初次介紹 I/O 設備模型的時候就已經(jīng)說明了這個統(tǒng)一的控制塊:

上面的控制塊是對于應用程序而言,在我們的 UART 設備的設備驅動框架層,是有定義了 UART 設備自己的控制塊,其繼承了rt_device
的內(nèi)容,同時還增加了 UART 設備特有的一些配置,操作,回調函數(shù)之類的內(nèi)容,如下圖:

上面的 UART 設備控制塊在我們的上一篇文章也有過分析說明。
?? UART 設備屬于 I/O 設備大類中的一個小類,對于上層應用程序而言,UART 設備控制塊rt_serial_device
并不透明,我們用戶操作的還是 I/O 設備模型的控制塊rt_device_t
類型。
1.2 UART 操作函數(shù)
因為 UART 的操作函數(shù) 與 I/O 設備的操作函數(shù)基本一致,所以本小結有點類似《RT-Thread記錄(十、全面認識 RT-Thread I/O 設備模型》中的 2.3 訪問 I/O 設備相關 API 操作,但是針對 UART 設備,也有一些獨有的參數(shù)說明。
老規(guī)矩,函數(shù)介紹部分說明看注釋。
1.2.1 查找 UART 設備
需要先定義一個 I/O 設備結構體(rt_device_t
類型)的指針變量,接收創(chuàng)建好的句柄。
/*
參數(shù) 描述
name 設備名稱,對于UART設備而言,默認一般是 uart0,uart1,uart2,uart3 等
返回 ——
設備句柄 查找到對應設備將返回相應的設備句柄
RT_NULL 沒有找到相應的設備對象
*/
rt_device_t rt_device_find(const char* name);
1.2.2 打開/關閉 UART 設備
先說打開 UART 設備:
/**
參數(shù) 描述
dev 設備句柄
oflags 設備模式標志
oflags可選的的值如下:
#define RT_DEVICE_FLAG_STREAM 0x040 流模式
接收模式參數(shù)
#define RT_DEVICE_FLAG_INT_RX 0x100 中斷接收模式
#define RT_DEVICE_FLAG_DMA_RX 0x200 DMA 接收模式
發(fā)送模式參數(shù)
#define RT_DEVICE_FLAG_INT_TX 0x400 中斷發(fā)送模式
#define RT_DEVICE_FLAG_DMA_TX 0x800 DMA 發(fā)送模式
返回值:
RT_EOK 設備打開成功
-RT_EBUSY 如果設備注冊時指定的參數(shù)中包括 RT_DEVICE_FLAG_STANDALONE 參數(shù),此設備將不允許重復打開
其他錯誤碼 設備打開失敗
*/
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
打開設備時,會檢測設備是否已經(jīng)初始化,沒有初始化則會默認調用初始化接口初始化設備。
如果 oflags 沒有指定使用中斷模式或者 DMA 模式,則默認使用輪詢模式。
這里有個問題,流模式是什么情況下使用的?485通訊? 暫時不知道,希望知道的朋友能夠給個說明。
在官方的文檔中,關于流模式有如下說明:

實際應用中的串口讀寫說明
串口RX:
在我們正常的項目使用中,一般都是 中斷接收 或者 DMA 接收,基本上不會使用 輪詢接收的方式(極大的浪費資源,反正我是沒用過)。
所以我們打開串口設備的時候,基本上都是如下兩種:
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
在 RT-Thread 系統(tǒng)中,我們常用信號量或者消息隊列 來標志是否接收到串口數(shù)據(jù),這樣的好處是當沒有數(shù)據(jù)的時候,會將數(shù)據(jù)處理線程掛機,讓出CPU資源。
串口TX:
對于串口 TX 來說,大部分項目中我自己一直都用的是 輪詢 方式發(fā)送。
對于串口的中斷發(fā)送方式,在上一篇文章我們分析 UART 源碼,雖然沒有詳細說明,但是實際上在設備驅動層 drv_usart.c
驅動文件里,中斷發(fā)送方式最終還是調用了該驅動文件里面的stm32_putc
函數(shù):

我感覺還是和輪詢一樣,將數(shù)據(jù)寫入 數(shù)據(jù)寄存器DR,使用while死等發(fā)送完成(雖然時間很短)。
上面雖然只是 RT-Thread 中的UART設備驅動文件,也多少能說明一些問題,中斷發(fā)送最終無非就是發(fā)送完了多一個中斷通知。
對于另外一種 DMA 發(fā)送,我記得以前聽老人提到過,DMA發(fā)送使用不得當,可能導致發(fā)送數(shù)據(jù)異常,簡單來說就是 DMA 發(fā)送函數(shù)返回后,數(shù)據(jù)都不一定發(fā)送完成了,如果此時修改了 DMA 發(fā)送指定的buffer 區(qū)的內(nèi)容,那么后面的數(shù)據(jù)就錯誤了。
所以,如果沒有特殊需求,我們項目中的串口發(fā)送使用 輪詢發(fā)送 即可(有些特殊情況的根據(jù)自己的實際需求而定)。
所以結合上面所說,我們實際應用中,使用以下兩種方式打開串口設備能滿足大部分場合需求:
/*輪詢方式發(fā)送,中斷接收*/
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
/*輪詢方式發(fā)送,DMA接收*/
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
有打開設備,當然也有關閉設備:
/**
參數(shù) 描述
dev 設備句柄
返回 ——
RT_EOK 關閉設備成功
-RT_ERROR 設備已經(jīng)完全關閉,不能重復關閉設備
其他錯誤碼 關閉設備失敗
*/
rt_err_t rt_device_close(rt_device_t dev)
關閉設備接口和打開設備接口需配對使用,打開一次設備對應要關閉一次設備,這樣設備才會被完全關閉,否則設備仍處于未關閉狀態(tài)。
當然在一般的應用場合,用到串口通訊的地方設備都是需要一直開啟的,所以很多情況下都不需要使用 UART 設備關閉函數(shù)。
1.2.3 控制 UART 設備
rt_device_control
一般用在 rt_device_open
(打開串口設備)之前,對需要使用的串口進行必要的配置。
/**
參數(shù) 描述
dev 設備句柄
cmd 命令控制字,可取值:RT_DEVICE_CTRL_CONFIG
arg 控制的參數(shù),可取類型:
struct serial_configure
{
rt_uint32_t baud_rate; 波特率
rt_uint32_t data_bits :4; 數(shù)據(jù)位
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; 接收數(shù)據(jù)緩沖區(qū)大小
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
數(shù)據(jù)位可取值:
#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
接收數(shù)據(jù)緩沖區(qū)默認大?。?#define RT_SERIAL_RB_BUFSZ 64
返回 ——
RT_EOK 函數(shù)執(zhí)行成功
-RT_ENOSYS 執(zhí)行失敗,dev 為空
其他錯誤碼 執(zhí)行失敗
*/
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
我們已經(jīng)知道,在串口初始化的時候會有一個默認配置:

所以在我們使用串口的時候,如果對應的配置與默認的配置不一樣,就需要使用此函數(shù)修改配置。
接收緩沖區(qū):
當串口使用中斷接收模式打開時,串口驅動框架會根據(jù) RT_SERIAL_RB_BUFSZ 大小開辟一塊緩沖區(qū)用于保存接收到的數(shù)據(jù),底層驅動接收到一個數(shù)據(jù),都會在中斷服務程序里面將數(shù)據(jù)放入緩沖區(qū)。
在修改緩沖區(qū)大小時請注意,緩沖區(qū)大小無法動態(tài)改變,只有在 open 設備之前可以配置。open 設備之后,緩沖區(qū)大小不可再進行更改。但除緩沖區(qū)之外的其他參數(shù),在 open 設備前 / 后,均可進行更改。
串口控制修改使用官方修改示例說明一下:
#define SAMPLE_UART_NAME "uart2" /* 串口設備名稱 */
static rt_device_t serial; /* 串口設備句柄 */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置參數(shù) */
/* step1:查找串口設備 */
serial = rt_device_find(SAMPLE_UART_NAME);
/* step2:修改串口配置參數(shù) */
config.baud_rate = BAUD_RATE_9600; //修改波特率為 9600
config.data_bits = DATA_BITS_8; //數(shù)據(jù)位 8
config.stop_bits = STOP_BITS_1; //停止位 1
config.bufsz = 128; //修改緩沖區(qū) buff size 為 128
config.parity = PARITY_NONE; //無奇偶校驗位
/* step3:控制串口設備。通過控制接口傳入命令控制字,與控制參數(shù) */
rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
/* step4:打開串口設備。以中斷接收及輪詢發(fā)送模式打開串口設備 */
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
1.2.4 發(fā)送數(shù)據(jù)
/**
參數(shù) 描述
dev 設備句柄
pos 寫入數(shù)據(jù)偏移量,此參數(shù)串口設備未使用
buffer 內(nèi)存緩沖區(qū)指針,放置要寫入的數(shù)據(jù)
size 寫入數(shù)據(jù)的大小
返回 ——
寫入數(shù)據(jù)的實際大小 如果是字符設備,返回大小以字節(jié)為單位;
0 需要讀取當前線程的 errno 來判斷錯誤狀態(tài)
*/
rt_size_t rt_device_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
寫其實很好理解,除了多一個設備句柄參數(shù),和我們裸機中使用的發(fā)送函數(shù)一樣,看一下一個普通的裸機串口發(fā)送函數(shù):

這里說明一下,因為我們上面分析過實際應用中的串口讀寫,一般都使用輪詢發(fā)送,所以我這里并不打斷介紹 設置發(fā)送完成回調函數(shù) 。
1.2.5 設置接收回調函數(shù)
/**
參數(shù) 描述
dev 設備句柄
rx_ind 回調函數(shù)指針
回調函數(shù)參數(shù) 描述
dev 設備句柄
size 緩沖區(qū)數(shù)據(jù)大小
返回 ——
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))
若串口以中斷接收模式打開:
當串口接收到一個數(shù)據(jù)產(chǎn)生中斷時,就會調用回調函數(shù),并且會把此時緩沖區(qū)的數(shù)據(jù)大小放在 size 參數(shù)里,把串口設備句柄放在 dev 參數(shù)里供調用者獲取。
若串口以 DMA 接收模式打開:
當 DMA 完成一批數(shù)據(jù)的接收后會調用此回調函數(shù)。
在使用 RT-Thread 時候,一般會用一個信號量通知串口數(shù)據(jù)處理線程有數(shù)據(jù)到達。
在使用 RT-Thread Nano 的時候,其實我也是使用信號量來處理數(shù)據(jù)的接收:

具體詳情可查看博文:RT-Thread 應用篇 — 在STM32L051上使用 RT-Thread (四、無線溫濕度傳感器 之 串口通訊)
回調函數(shù)處理的示例我們使用官方示例說明,與下面的接收數(shù)據(jù)函數(shù)一起展示。
1.2.6 接收數(shù)據(jù)
數(shù)據(jù)接收處理函數(shù),在接收回調函數(shù)運行之后運行。
/**
參數(shù) 描述
dev 設備句柄
pos 讀取數(shù)據(jù)偏移量,此參數(shù)串口設備未使用
buffer 緩沖區(qū)指針,讀取的數(shù)據(jù)將會被保存在緩沖區(qū)中
size 讀取數(shù)據(jù)的大小
返回 ——
讀到數(shù)據(jù)的實際大小 如果是字符設備,返回大小以字節(jié)為單位
0 需要讀取當前線程的 errno 來判斷錯誤狀態(tài)
*/
rt_size_t rt_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
我們與上面的設置接收回調函數(shù)一起使用官方示例作為說明:
#define SAMPLE_UART_NAME "uart2" /* 串口設備名稱 */
static rt_device_t serial; /* 串口設備句柄 */
static struct rt_semaphore rx_sem; /* 用于接收消息的信號量 */
/* 接收數(shù)據(jù)回調函數(shù) */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
/* 串口接收到數(shù)據(jù)后產(chǎn)生中斷,調用此回調函數(shù),然后發(fā)送接收信號量 */
rt_sem_release(&rx_sem);
return RT_EOK;
}
/* 接收數(shù)據(jù)的線程 */
static void serial_thread_entry(void *parameter)
{
char ch;
while (1)
{
/* 從串口讀取一個字節(jié)的數(shù)據(jù),沒有讀取到則等待接收信號量 */
while (rt_device_read(serial, -1, &ch, 1) != 1)
{
/* 阻塞等待接收信號量,等到信號量后再次讀取數(shù)據(jù) */
rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
}
/* 讀取到的數(shù)據(jù)通過串口錯位輸出 */
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);
/* 以中斷接收及輪詢發(fā)送模式打開串口設備 */
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
/* 初始化信號量 */
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
/* 設置接收回調函數(shù) */
rt_device_set_rx_indicate(serial, uart_input);
}
示例中使用的是信號量,收到一個數(shù)據(jù),便會喚醒接收數(shù)據(jù)的線程,所以其實是一個字節(jié)一個字節(jié)(一個字符等于一個字節(jié))的讀取, 示例處理方式只能使用 RT_DEVICE_FLAG_INT_RX
方式接收。
?? 接收數(shù)據(jù)rt_device_read
函數(shù)的返回值需要注意一下,返回值為讀到的數(shù)據(jù)實際大小,就是接收到的數(shù)據(jù)長度。
二、UART 設備使用步驟
簡單介紹一下在 RT-Thread Studio 開發(fā)環(huán)境下 UART的使用步驟。
2.1 RT-Thread setting
如果需要使用某個設備,是需要在 ENV 工具中配置的,現(xiàn)在有了 RT-Thread Studio ,所以可以直接通過工程目錄下的 RT-Thread setting 進行圖形化界面的配置,如下圖:

因為Shell 工具需要使用串口,所以默認串口這里已經(jīng)是勾選中的,這里說明只是為了讓大家知道,在以后的 I/O 設備使用的時候,第一步就是在 RT-Thread setting 中使能設備。
2.2 board.h 設置
完成設備使能,我們還需要使用宏定義進行串口的基本設置,該設置在board.h
文件中進行,如下圖:

board.h
中包括了很多外設的使用說明,除了 UART,還有I2C、SPI、ADC等設備,我們在后面學習這些設備使用的時候,需要經(jīng)常用到這個頭文件,一些基本的使能配置都是在這個文件中用宏定義使能。
2.3 應用程序流程
完成上面 2 步的基本配置以后,我們就可以在應用程序通過上文介紹的 UART 設備操作函數(shù)進行串口的使用,具體的步驟概括如下:
UART 設備使用步驟 :
/
#include "rtdevice.h"
/
1、使用rt_device_find查找串口設備;
/
2、根據(jù)需求使用rt_device_control設置串口;
/
3、初始化回調函數(shù)中使用的信號量(在接收回調函數(shù)中 發(fā)送信號量 喚醒數(shù)據(jù)處理線程),如果使用消息隊列接收初始化消息隊列;
/
4、使用rt_device_open打開串口設備(根據(jù)自己的情況判斷使用什么方式接收,發(fā)送前面分析過了,一本應用使用輪詢發(fā)送即可);
/
5、使用rt_device_set_rx_indicate設置串口設備的接收回調函數(shù)
/
6、創(chuàng)建數(shù)據(jù)讀取的線程。
按照上面的步驟,我進行了如下的示例測試,不要忘記 #include "rtdevice.h"
:

上圖其實是根據(jù)官方示例代碼,使用的 ESP8266 WIFI 模塊做了一個簡單的測試:

三、UART 示例測試
在上面介紹應用程序流程的時候,其實已經(jīng)做了一個簡單的示例測試。
同時在官方已經(jīng)也提供了3種典型的示例程序:
中斷接收及輪詢發(fā)送、DMA 接收及輪詢發(fā)送、串口接收不定長數(shù)據(jù)
作為以應用為目的系列博文,我自己還是根據(jù)自己的工作需求進行串口通訊的測試,使用的是 Enocean 無線通訊模塊,當時在 RT-Thread 的應用篇,RT-Thread Nano 使用記錄的時候就使用的這個無線模塊。
要說明的是,用什么模塊做通訊并不是重點,重點在于使用過程中對串口數(shù)據(jù)的處理方式。
3.1 與無線模塊串口通訊
雖然換了一個通訊設備,但是官方給的例程:中斷接收及輪詢發(fā)送 還是適用的,我們先來看一看直接使用官方的例程做的測試:
/* 接收數(shù)據(jù)回調函數(shù) */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
/* 串口接收到數(shù)據(jù)后產(chǎn)生中斷,調用此回調函數(shù),然后發(fā)送接收信號量 */
rt_sem_release(&rx_sem);
return RT_EOK;
}
static void test_thread_entry(void *par){
uint8_t ch;
while (1)
{
/* 從串口讀取一個字節(jié)的數(shù)據(jù),沒有讀取到則等待接收信號量 */
while (rt_device_read(testuart, -1, &ch, 1) != 1)
{
/* 阻塞等待接收信號量,等到信號量后再次讀取數(shù)據(jù) */
rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
}
rt_kprintf("%x ",ch);
}
}
其測試結果如下:

為了更好的做數(shù)據(jù)解析,我們需要對原始的程序進行修改,使得能夠針對一幀數(shù)據(jù)一幀數(shù)據(jù)進行接收處理:
uint8_t USART_Enocean_BUF[64];
uint8_t Enocean_Data = 0;
/* 接收數(shù)據(jù)回調函數(shù) */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
Enocean_Data = size;
/* 串口接收到數(shù)據(jù)后產(chǎn)生中斷,調用此回調函數(shù),然后發(fā)送接收信號量 */
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;
}
}
測試結果如下,實現(xiàn)了我們所需要的的針對每一幀數(shù)據(jù)的接收(既然都已經(jīng)可以區(qū)別每一幀數(shù)據(jù)了,所那么后續(xù)的處理也就簡單了):

對于數(shù)據(jù)的接收處理信號量只是其中一種。
即便是信號量,也有多種可實現(xiàn)行的方式,而上面我測試使用的方式也只不過其中的一種:收到第一個數(shù)據(jù)的時候等待一定的時間,然后認為是一幀數(shù)據(jù)接收完成。
這也只是判斷一幀數(shù)據(jù)接收完成的方法中的一種 = =!
3.2 示例說明
在上面我們用了信號量作為通知的方式接收串口數(shù)據(jù),官方的示: DMA 接收及輪詢發(fā)送 采用了消息隊列的方式進行處理,表面上看起來與我們上面那種方式不一樣。
其實本質都是一樣的,都不過是給線程一個通知,并沒有“真正意義上的傳遞了消息”(比如串口接收到的數(shù)據(jù)):

如果想要使用消息隊列作為緩存正常的傳輸串口接收的數(shù)據(jù),不使用 I/O 設備模型的情況下更加適合,究其原因,如下圖分析:

如上面表格所說,使用了I/O 設備模型之后,我們底層串口初始化的時候已經(jīng)有了一段數(shù)據(jù)接收的buffer了,所以我們直接使用 rt_device_read 函數(shù)從驅動層的 buffer 讀取數(shù)據(jù),用臨時 buffer 來處理就可以了(不過如果需要對處理程序,單獨設計函數(shù),也可以用一個全局 buffer 來處理),也不過是2個buffer 的內(nèi)存占用。
所以在官方的示例中,雖然給的是信號量,和消息隊列的不同的處理方式,但是究其根本還是一樣的。只是給了一個通知,這個其他的 IPC機制 比如 事件集一樣可以做到,即便不用 IPC 機制,普通簡單的應用,全局變量也未嘗不可。(對于消息隊列傳遞串口接收數(shù)據(jù)的應用,以后我還是會單獨的說明的,本文在于說明 UART 基于 I/O 設備模型的使用,所以就不做測試了 = =?。?/p>
?? 使用了 UART 設備模型,最終還是需要使用rt_device_read
函數(shù),從內(nèi)部緩存讀取串口數(shù)據(jù),IPC只不過是給線程一個通知。
結語
一個 UART 設備畫了兩篇文章,還算是比較值得的,通過上一篇文章加深對 RT-Thread I/O 設備模型的理解,通過本文實際體驗了一把 UART 設備。
體驗上來說,還是感覺特別方便簡單的。但是這個前提條件時,能夠真正的理解 RT-Thread I/O 設備模型,理解到位才能用起來游刃有余,也能夠在以后出問題的時候更容易的發(fā)現(xiàn)問題,解決問題。
?? 學會了使用一個東西當然是一件慶幸的事情,但是能夠理解它才是更加重要的事情! ??
-
uart
+關注
關注
22文章
1286瀏覽量
105477 -
RT-Thread
+關注
關注
32文章
1496瀏覽量
43475
發(fā)布評論請先 登錄
RT-Thread記錄(十四、I/O 設備模型之ADC設備)

RT-Thread全球技術大會:RT-Thread上的單元測試框架與運行測試用例

評論