一、 前言
本來我是打算先講完RT-thread的內(nèi)核,再講設(shè)備和組件,但是考慮到后面很多地方都會(huì)用到FinSH控制臺(tái),所以我就先把這個(gè)講了,這樣大家在后面的學(xué)習(xí)就不會(huì)有很多疑問了。
FinSH 是 RT-Thread 的命令行組件(shell),它提供一套供用戶在命令行調(diào)用的操作接口,主要用于調(diào)試或查看系統(tǒng)信息,可以使用串口 / 以太網(wǎng) / USB 等方式與 PC 機(jī)進(jìn)行通信。一般我們默認(rèn)用串口1和PC機(jī)通訊,通過串口我們可以查看單片機(jī)運(yùn)行的情況,也可以通過發(fā)送命令控制單片機(jī)執(zhí)行某些操作。關(guān)于FinSH更多詳細(xì)的內(nèi)容,大家可以在官網(wǎng)上面查看。
FinSH控制臺(tái)組件介紹:https://www.rt-thread.org/document/site/programming-manual/finsh/finsh/#
源碼鏈接
我發(fā)布的所有關(guān)于RT-thread的教程源代碼都在下面這個(gè)鏈接里面,隨著我教程的更新,新的代碼也會(huì)加入進(jìn)去。
教程源碼下載鏈接:https://pan.baidu.com/s/1N2D8dM31deKIqNqaIQfPiA
提取碼:7nsx
二、FinSH控制臺(tái)使用方法
第一步:配置FinSH
在一個(gè)項(xiàng)目工程中打開env,輸入menuconfig,選中finsh shell選項(xiàng)即可,一般默認(rèn)都是打開的。
如果你不知道m(xù)enuconfig怎么使用,可以在下面這個(gè)鏈接查看。
Menuconfig使用方法:https://www.rt-thread.org/document/site/programming-manual/env/env/#bsp-menuconfig
使能串口1,這個(gè)如果沒有修改過的話,也是默認(rèn)打開的
第二步:燒錄程序并把串口連接到PC端
單片機(jī)把配置好的工程下載到板子上,并通過usb轉(zhuǎn)串口把單片機(jī)的串口1連接到電腦上。
第三步:打開xshell或者串口助手
第四步:測(cè)試FinSH命令
復(fù)位一下單片機(jī)就可以看到上電時(shí)串口打印的版本信息
FinSH控制臺(tái)的基本操作和Linux是一樣的
我們可以先輸入tab鍵查看當(dāng)前系統(tǒng)支持的命令。如下圖所示,左邊是命令名稱,右邊是關(guān)于命令的描述,如下圖所示。
我們輸入命令之后按下回車鍵就可以執(zhí)行命令了,例如我輸入list_thread命令,會(huì)返回了所有線程的信息,如下圖所示,led0和led1是我自己創(chuàng)建的線程,另外幾個(gè)則是系統(tǒng)的線程。
這些命令的作用我就不一一描述了,大家可以在官網(wǎng)上面查看。
FinSH內(nèi)置命令詳解:https://www.rt-thread.org/document/site/programming-manual/finsh/finsh/#finsh_2
三、自定義FinSH命令
自定義FinSH命令是這一講我重點(diǎn)要講的內(nèi)容,在項(xiàng)目的實(shí)際應(yīng)用中,為了方便調(diào)試,我們經(jīng)常會(huì)自定義FinSH命令。
Rt-thread支持三種自定義模式
自定義msh命令
這是傳統(tǒng)的命令行模式,也是最常用的一種。
該命令可以導(dǎo)出有參數(shù)的命令,也可以導(dǎo)出無參數(shù)的命令。導(dǎo)出無參數(shù)命令時(shí),函數(shù)的入?yún)?void,示例如下:
void hello(void)
{
rt_kprintf("hello RT-Thread!n");
}
MSH_CMD_EXPORT(hello , say hello to RT-Thread);//hello是命令名稱,say hello to RT-Thread是命令描述
導(dǎo)出有參數(shù)的命令時(shí),函數(shù)的入?yún)?int argc 和 char**argv。argc 表示參數(shù)的個(gè)數(shù),argv 表示命令行參數(shù)字符串指針數(shù)組指針。導(dǎo)出有參數(shù)命令示例如下:
static void atcmd(int argc, char**argv)
{
……
}
MSH_CMD_EXPORT(atcmd, atcmd sample: atcmd <server|client>);
自定義C-Style 命令和變量
自定義C-Style命令能夠解析執(zhí)行大部分 C 語言的表達(dá)式,并使用類似 C 語言的函數(shù)調(diào)用方式訪問系統(tǒng)中的函數(shù)及全局變量,此外它也能夠通過命令行方式創(chuàng)建變量,不過我個(gè)人基本沒怎么用這種方式,最常用的還是msh命令。
以下示例定義了一個(gè) hello 函數(shù),并將它導(dǎo)出成 C-Style 模式下的命令
void hello(void)
{
rt_kprintf("hello RT-Thread!n");
}
FINSH_FUNCTION_EXPORT(hello , say hello to RT-Thread);
以下示例定義了一個(gè) dummy 變量,并將它導(dǎo)出成 C-Style 模式下的變量命令:
static int dummy = 0;
FINSH_VAR_EXPORT(dummy, finsh_type_int, dummy variable for finsh)
自定義命令重命名
FinSH 的函數(shù)名字長(zhǎng)度是有限制的,默認(rèn)是 16 字節(jié)。因此當(dāng)一個(gè)函數(shù)名長(zhǎng)度超過了上限,只有函數(shù)名前16個(gè)字節(jié)會(huì)保留下來,所以如果輸入了全部命令執(zhí)行的時(shí)候就會(huì)出錯(cuò)。這時(shí)就可以使用自定義命令重命名來對(duì)導(dǎo)出的命令進(jìn)行重命名了。
在重命名的命令名字前加 _cmd 就可以將命令導(dǎo)出到 msh 模式,否則,命令會(huì)被導(dǎo)出到 C-Style 模式。以下示例定義了一個(gè) hello 函數(shù),并將它重命名為 ho 后導(dǎo)出成 C-Style 模式下的命令。
void hello(void)
{
rt_kprintf("hello RT-Thread!n");
}
FINSH_FUNCTION_EXPORT_ALIAS(hello , ho, say hello to RT-Thread);
四、項(xiàng)目實(shí)戰(zhàn)
我這里創(chuàng)建了兩個(gè)自定義msh命令,一個(gè)是帶參數(shù)的一個(gè)是不帶參數(shù)的。
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#define LED0_PIN GET_PIN(F, 9)
#define LED1_PIN GET_PIN(F, 10)
#define THREAD_PRIORITY 25 //線程優(yōu)先級(jí)
#define THREAD_TIMESLICE 5 //線程時(shí)間片
/* 靜態(tài)線程參數(shù)定義 */
ALIGN(RT_ALIGN_SIZE)
static char led1_stack[1024]; //線程棧內(nèi)存空間
static struct rt_thread led1; //線程句柄
int main(void)
{
int i = 0;
while (1)
{
rt_thread_mdelay(200);
}
}
/* led0函數(shù) */
void led0_init(void)
{
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
while(1)
{
rt_pin_write(LED0_PIN, PIN_LOW);
rt_kprintf("LED0_ON n");
rt_thread_mdelay(1000);
rt_pin_write(LED0_PIN, PIN_HIGH);
rt_kprintf("LED0_OFF n");
rt_thread_mdelay(1000);
}
}
MSH_CMD_EXPORT(led0_init, led0 init);
/* msh命令測(cè)試函數(shù): argc是輸入變量的個(gè)數(shù),argv是輸入變量的內(nèi)容 */
void msh_test(int argc, char**argv)
{
/* 檢查輸入的變量是否有兩個(gè) */
if (argc < 2)
{
rt_kprintf("Please input'msh_test <a|b>'n");
return;
}
if (!rt_strcmp(argv[1], "a"))
{/* 輸入的是a */
rt_kprintf("Hello world ! n");
}
else if (!rt_strcmp(argv[1], "b"))
{/* 輸入的是b */
rt_kprintf("Hello RT-thread ! n");
}
else
{/* 輸入的是其他內(nèi)容 */
rt_kprintf("Please input'msh_test <a|b>'n");
}
}
MSH_CMD_EXPORT(msh_test, msh test sample : msh_test a|b);
運(yùn)行的結(jié)果如下圖所示:
執(zhí)行“l(fā)ed0_init”指令之后,led燈就跑起來了。
這是帶參數(shù)的指令,輸入的時(shí)候除了指令的輸入還需要再輸入一個(gè)參數(shù),輸入不同的參數(shù)會(huì)有不同的效果,具體要執(zhí)行什么操作可以在函數(shù)里面自己去定義。
到這里可能有些同學(xué)就會(huì)問了,如果我不想用命令導(dǎo)出那要怎么做?這就需要用到自動(dòng)初始化了,比如INIT_APP_EXPORT()函數(shù),用了自動(dòng)初始化函數(shù)之后就不需要手動(dòng)輸入命令去調(diào)用了,關(guān)于自動(dòng)初始化的更多內(nèi)容我后面會(huì)單獨(dú)寫一篇博客。
五、結(jié)束語
好了,關(guān)于FinSH控制臺(tái)的編程講解就到這里,如果還有什么問題可以私信給我。如果需要本文對(duì)應(yīng)的源碼的話可以在博文前言部分的鏈接下載。
如果覺得這篇文章對(duì)你有用,點(diǎn)贊+關(guān)注支持一下博主唄。
后續(xù)我會(huì)繼續(xù)更新RT-thread入門教程系列,如果感興趣的同學(xué)可以關(guān)注一下博主,謝謝!
RT-thread相關(guān)教程匯總:https://blog.csdn.net/ShenZhen_zixian/article/details/120563891