1.1 前言說明
串口是MCU上最常見和使用最為頻繁的外設(shè)之一,可以用作打印調(diào)試信息、遠(yuǎn)程登陸、控制支持串口通訊的外設(shè)等功能,了解和掌握串口是嵌入式開發(fā)中的一項必備技能。
1.1.1 本章內(nèi)容
使用RT-Thread Studio創(chuàng)建開發(fā)板的程序,編寫UART的程序,實現(xiàn)串口打印數(shù)據(jù)的功能,同時使用Finsh Shell控制開發(fā)板上的LED。
1.1.2 模塊介紹
開發(fā)板上提供了兩個串口連接,分別是在P109和P110的串口9,通過調(diào)試器的虛擬串口與上位機通訊。
另一個串口位于P205和P206的串口4,TXD和RXD引腳引出到Ardinuo接口上,在開發(fā)板上也直接標(biāo)出了。
1.1.3 開發(fā)軟件
根據(jù)《實踐指南說明》安裝fsp3.5.0和RT-Thread Studio(2.2.6)。
1.2 步驟說明
安裝好開發(fā)環(huán)境后,首先對RT-Thread Studio的SDK Manager中安裝包進(jìn)行檢查,確定相關(guān)的軟件支持包已經(jīng)安裝。
1.2.1 新建工程
點擊工具欄中的文件->新建->RT-Thread項目
選擇目標(biāo)開發(fā)板以及工程默認(rèn)位置,這里一定要選擇HMI_Board,對應(yīng)的BSP版本為1.0.3,如果選擇RA6M3-HMI-Board,對應(yīng)的BSP版本為1.0.2,在使用串口時有Bug存在,會導(dǎo)致程序無法正常運行。
給項目一個合適的名字
點擊完成后,就可以得到一個打印信息以及一秒鐘翻轉(zhuǎn)LED的程序。
這個程序是一個完整的程序,點擊編譯后可以直接下載運行。在此基礎(chǔ)上我們就可以根據(jù)自己的需要編寫相應(yīng)的驅(qū)動程序。
如果在下載過程中遇到上述問題,可以通過更新pyocd的版本來修正,這一問題的原因是pyocd的版本過低導(dǎo)致。安裝0.2.0的pyocd添加對瑞薩的支持就可以解決這個問題。
由RT-Thread Studio創(chuàng)建的軟件工程本身就是一個演示了LED翻轉(zhuǎn)和串口功能的例程,我們上來就可以得到可以運行的使用了串口輸出信息的程序。需要注意的是,rtthread為了方便開發(fā)者調(diào)試,在系統(tǒng)中嵌入了Finsh這個簡易的控制臺程序,根據(jù)用戶使能的模塊提供了不同的控制指令。
新創(chuàng)建的工程編譯通過后,利用板載的daplink將固件燒寫到開發(fā)板上。
在串口終端中輸入help,可以查看當(dāng)前支持的指令。
其中l(wèi)ist的功能很多,后面跟隨不同的參數(shù)可以實現(xiàn)不同的功能,
如圖所示,可以產(chǎn)看當(dāng)前系統(tǒng)中的線程、定時器、信號量、互斥量、事件、郵箱、消息隊列以及設(shè)備的實例個數(shù)??梢詭椭_發(fā)者掌握當(dāng)前系統(tǒng)的運行狀態(tài)。另外reboot功能可以減少設(shè)備上下電的次數(shù),方便遠(yuǎn)程調(diào)試。
Finsh的除了上述已經(jīng)定義好的功能,還支持自定義指令,可以幫助開發(fā)者自定義一些測試函數(shù),方便針對特定情境進(jìn)行測試。
開發(fā)板默認(rèn)使用uart9作為調(diào)試串口,在開發(fā)板上的Ardinuo接口上,引出了uart4。開發(fā)板默認(rèn)是不開啟uart4,為了能使用uart4,首先使用FSP工具配置相關(guān)的引腳。
點擊工程中的RA Smart Configurator,可以啟動代碼配置工具對MCU的外設(shè)進(jìn)行配置。
在Stack欄中的New Stack->Connnectivity->UART添加新的UART實例。
修改General欄中的通道和設(shè)備名稱
在Pins引腳欄中設(shè)定使用的引腳和引腳的工作模式。
點擊“Generate Project Content”,即可關(guān)閉FSP工具。
回到工程中點擊RT-Thread Settings,對工程中要使用的硬件進(jìn)行配置。
在配置界面的硬件一欄中勾選Enable UART4
保存文件后,就可以在工程中添加uart4,并在工程調(diào)用相關(guān)的串口函數(shù)。
1.3 代碼驗證
通過串口發(fā)送字符串,是嵌入式應(yīng)用中的基本程序,檢驗串口是否正常工作。在hal_entry.c中添加以下代碼:
#include
#include "hal_data.h"
#include
#define LED_PIN BSP_IO_PORT_02_PIN_09 /* Onboard LED pins /
#define SAMPLE_UART_NAME "uart4" / 串口設(shè)備名稱 /
static rt_device_t serial; / 串口設(shè)備句柄 /
char str[] = "hello RT-Thread!rn";
void hal_entry(void)
{
rt_kprintf("nHello RT-Thread!n");
/ 查找串口設(shè)備 /
serial = rt_device_find(SAMPLE_UART_NAME);
rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); // 串口設(shè)備使用模式為 (發(fā)送阻塞 接收非阻塞) 模式
while (1)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
/ 發(fā)送字符串 */
rt_device_write(serial, 0, str, (sizeof(str) - 1));
}
}
串口打印的效果如下圖所示。
下面使用Finsh的自定義功能實現(xiàn)uart4的回環(huán)功能。具體的代碼如下
#include
#include "hal_data.h"
#include
#define LED_PIN BSP_IO_PORT_02_PIN_09 /* Onboard LED pins /
#define SAMPLE_UART_NAME "uart4" / 串口設(shè)備名稱 /
static rt_device_t serial; / 串口設(shè)備句柄 /
/ 串口接收消息結(jié)構(gòu) /
struct rx_msg
{
rt_device_t dev;
rt_size_t size;
};
/ 消息隊列控制塊 /
static struct rt_messagequeue rx_mq;
/ 接收數(shù)據(jù)回調(diào)函數(shù) /
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
struct rx_msg msg;
rt_err_t result;
msg.dev = dev;
msg.size = size;
result = rt_mq_send(&rx_mq, &msg, sizeof(msg));
if (result == -RT_EFULL)
{
/ 消息隊列滿 */
rt_kprintf("message queue full!n");
}
return result;
}
static void serial_thread_entry(void parameter)
{
struct rx_msg msg;
rt_err_t result;
rt_uint32_t rx_length;
static char rx_buffer[BSP_UART4_RX_BUFSIZE + 1];
while (1)
{
rt_memset(&msg, 0, sizeof(msg));
/ 從消息隊列中讀取消息 /
result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
if (result == RT_EOK)
{
/ 從串口讀取數(shù)據(jù) /
rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
rx_buffer[rx_length] = '?';
/ 通過串口設(shè)備 serial 輸出讀取到的消息 /
rt_device_write(serial, 0, rx_buffer, rx_length);
/ 打印數(shù)據(jù) */
rt_kprintf("%sn",rx_buffer);
}
}
}
static int uart_loop_sample(int argc, char argv[])
{
rt_err_t ret = RT_EOK;
char uart_name[RT_NAME_MAX];
static char msg_pool[256];
char str[] = "hello RT-Thread!rn";
if (argc == 2)
{
rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
}
else
{
rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
}
/ 查找串口設(shè)備 /
serial = rt_device_find(uart_name);
if (!serial)
{
rt_kprintf("find %s failed!n", uart_name);
return RT_ERROR;
}
/ 初始化消息隊列 /
rt_mq_init(&rx_mq, "rx_mq",
msg_pool, / 存放消息的緩沖區(qū) /
sizeof(struct rx_msg), / 一條消息的最大長度 /
sizeof(msg_pool), / 存放消息的緩沖區(qū)大小 /
RT_IPC_FLAG_FIFO); / 如果有多個線程等待,按照先來先得到的方法分配消息 /
/ 以 非阻塞接收及阻塞發(fā)送方式打開串口設(shè)備 /
rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
/ 設(shè)置接收回調(diào)函數(shù) /
rt_device_set_rx_indicate(serial, uart_input);
/ 發(fā)送字符串 /
rt_device_write(serial, 0, str, (sizeof(str) - 1));
/ 創(chuàng)建 serial 線程 /
rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
/ 創(chuàng)建成功則啟動線程 /
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
ret = RT_ERROR;
}
return ret;
}
/ 導(dǎo)出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_loop_sample, uart device loop sample);
void hal_entry(void)
{
while (1)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
在串口界面中輸入控制指令
測試效果如圖所示:
1.4 章節(jié)總結(jié)
使用RT-Thread和FSP進(jìn)行開始還是很方便的,在FSP中修改相關(guān)引腳的功能,RT-Thread中使用配置工具對BSP進(jìn)行使能。同時RT-Thread官網(wǎng)上還有詳細(xì)的文檔和示例代碼,幫助新手快速搭建工程和入門嵌入式開發(fā)是一個不錯的選擇。
評論
查看更多