0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

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

3天內(nèi)不再提示

單片機上如何做shell命令行交互

麥辣雞腿堡 ? 來源:嵌入式軟件那些事 ? 作者:靜以修身 ? 2023-11-01 15:16 ? 次閱讀

做過嵌入式Linux開發(fā)或使用過桌面Linux系統(tǒng)的童鞋們,肯定對shell命令交互印象比較深刻,然而我們大多數(shù)搞嵌入式軟件開發(fā)的碼農(nóng)都是基于單片機,比如51、STM32等進行開發(fā)的,在單片機上能否做個shell命令行交互?答案當然是可以的,在網(wǎng)上類似的文章和代碼一搜一籮筐, 基本原理: 監(jiān)測用戶的輸入,然后到一個命令查找表里過濾是否可以找到該命令,如果可以則調(diào)用對應的處理函數(shù),當然做的好點的話還可以向處理函數(shù)傳遞參數(shù)。

主要的數(shù)據(jù)結(jié)構(gòu)及解析函數(shù)定義如下,注意這里函數(shù)指針的定義,Argc代表參數(shù)的個數(shù),可以為0、1、2...,Argv用于存放具體的參數(shù),可能有些童鞋要問為啥定義成CHAR **,這是因為我們在shell交互窗口輸入的內(nèi)容都會被當作ASCII碼字符串,所以只能用CHAR *來指向它們,另外又因為我們可能會輸入多個字符串參數(shù)(多個參數(shù)以空格進行間隔),所以要使用二級指針CHAR **,可能有的同學會發(fā)現(xiàn),我們平時見的標準main函數(shù)的原型就是這樣定義的

int main(int argc, char *argv[])

char *argv[]與char **argv是等價的,這個就不需要解釋了吧,采用這種定義方式可以非常靈活,具體見下面的用法示例:

#define SHELL_MAX_PARA_NUM      20                         //最多支持20個命令參數(shù)


// 函數(shù)指針
typedef UINT8 (* Cmd_Analys_Fun_P)(UINT8 Argc, CHAR **Argv);


typedef struct
{
    CHAR *pName;
    Cmd_Analys_Fun_P pCmdFunc;    // 命令解析函數(shù)
} S_Shell_Cmd;


/***************************************************************
* 函數(shù)名稱: Shell_Proc
* 功能描述: Shell交互處理
* 輸入?yún)?shù): 
* 輸出參數(shù): 
* 返 回 值: 
****************************************************************/
UINT8 Shell_Proc(CHAR *ucCmd, UINT8 ucCmdLength)
{
    UINT8 Result;


    Result = Cmd_Analys(Shell_Cmd, S_NUM(Shell_Cmd), ucCmd, ucCmdLength);
    if ((Result EQ 1) || (Result EQ 2))
    {
        //vConsoleLog("[shell]#");
    }


    return Result;
}


/***************************************************************
* 函數(shù)名稱: Cmd_Analys
* 功能描述: 命令解析
* 輸入?yún)?shù): 
* 輸出參數(shù): 
* 返 回 值:  
****************************************************************/
LOCAL UINT8 Cmd_Analys(CONST S_Shell_Cmd Shell_Cmd[], UINT8 Num, CHAR Cmd[], UINT8 Len)
{
    UINT8 i, j;
    UINT8 Argc, Cmd_Len;
    CHAR  *(Argv[SHELL_MAX_PARA_NUM]);


    Cmd_Len = 0;
    for (i = 0; i < Len; i++)
    {
        if ((Cmd[i] EQ 'r') || (Cmd[i] EQ 'n')) // 找到回車換行鍵, 說明已經(jīng)輸入了一條完整命令
        {
            Cmd_Len = i;            // 記錄命令長度
            Cmd[i] = '?';
            break;
        }
        else if (Cmd[i] EQ ' ')     // 空格全部替換成'?'
        {
            Cmd[i] = '?';
        }
    }


    if (i EQ Len)                   // 沒有找到命令
    {
        return 0;
    }


    if (Cmd_Len EQ 0)               // 全部輸入的是空格或者回車
    {
        vConsoleLog("rnShell:");  // 提示輸入新的命令
        return 1;
    }


    for (i = 0; i < Num; i++)
    {
        if (strcmp(Shell_Cmd[i].pName, Cmd) != 0)
        {
            continue;
        }


        j = (UINT8)strlen(Cmd);
        Argc = 0;
        while (j < Cmd_Len)
        {
            if (Cmd[j] EQ '?' && Cmd[j + 1] != '?') // 前一個是空格,后一個非空格,說明是一個新參數(shù)
            {
                if (Argc < SHELL_MAX_PARA_NUM)
                {
                    Argv[Argc] = &Cmd[j + 1];
                    Argc++;
                }
                else
                {
                    break;
                }
            }


            j++;
        }


        // 執(zhí)行命令
        (*Shell_Cmd[i].pCmdFunc)(Argc, Argv);
        break;
    }


    if (i EQ Num)
    {
        vConsoleLog("Cmd Error!");
        return 2;
    }


    return 1;
}

**用法1:**只有命令,沒有參數(shù)

/***************************************************************
* 函數(shù)名稱: RebootTerminal
* 功能描述: 重啟終端
* 輸入?yún)?shù): 
* 輸出參數(shù): 
* 返 回 值: 
****************************************************************/
LOCAL UINT8 RebootTerminal(UINT8 argc, CHAR **argv)
{
    //發(fā)起復位請求
    udwResetTimeCounter = 0;
    blResetRequestFlag  = TRUE;
    vConsoleLog("Terminal Prepare Reboot ...");


    return 1;
}

**用法2:**命令+1個參數(shù)

/***************************************************************
* 函數(shù)名稱: ConsoleOutputRedirect
* 功能描述: console輸出重定向
* 輸入?yún)?shù): 
* 輸出參數(shù): 
* 返 回 值: 
****************************************************************/
LOCAL UINT8 ConsoleOutputRedirect(UINT8 argc, CHAR **argv)
{
    if (argc != 1)
    {
        vConsoleLog("miss argumentrn");
        return 0;
    }

    if (!strcmp(argv[0], "on"))
    {
        ucConsoleRedirectFlag = 1;
        vConsoleLog("console output redirect to tcpconsolern");
    }
    else if (!strcmp(argv[0], "off"))
    {
        ucConsoleRedirectFlag = 0;
        vConsoleLog("console output redirect to localconsolern");
    }
    else
    {
        vConsoleLog("error argumentrn");
        return 0;
    }


    return 1;
}

**用法3:**命令+N個參數(shù)

/***************************************************************
* 函數(shù)名稱: SetTerminalTime
* 功能描述: 設置終端時間
* 輸入?yún)?shù): 
* 輸出參數(shù): 
* 返 回 值: 
****************************************************************/
LOCAL UINT8 SetTerminalTime(UINT8 argc, CHAR **argv)
{
    UINT8 ucTime[6];


    if (argc != 6)
    {
        vConsoleLog("Param Err! argc = %d", argc);
        return 0;
    }


    ucTime[0] = strtoul(argv[0], NULL, 0);
    ucTime[1] = strtoul(argv[1], NULL, 0);
    ucTime[2] = strtoul(argv[2], NULL, 0);
    ucTime[3] = strtoul(argv[3], NULL, 0);
    ucTime[4] = strtoul(argv[4], NULL, 0);
    ucTime[5] = strtoul(argv[5], NULL, 0);


    ucTimeTestFlag = 1;


    stCurrentTime.ucYear  = ucTime[0];
    stCurrentTime.ucMonth = ucTime[1];
    stCurrentTime.ucDay   = ucTime[2];
    stCurrentTime.ucHour  = ucTime[3];
    stCurrentTime.ucMin   = ucTime[4];
    stCurrentTime.ucSec   = ucTime[5];


    vConsoleLog("SetTerminalTime: %02d/%02d/%02d %02d:%02d:%02d", ucTime[0], ucTime[1], ucTime[2], 
                                                                  ucTime[3], ucTime[4], ucTime[5]);


    return 1;
}

以上三種用法,基本可以涵蓋現(xiàn)實中的各種使用需求!

以上就是shell命令的基本用法,至于如何捕捉用戶的輸入,方式和方法就很多了,不過常用的就下面的幾種情況:

  1. 終端設備上的串口(這種最常見)
  2. 終端設備上的網(wǎng)口(稍微有點門檻,后面會專門寫一篇STM32的文章介紹這種用法)
  3. 如果終端設備已經(jīng)登錄了后臺主站云平臺,直接在云平臺上給終端設備下發(fā)shell命令
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5046

    文章

    18817

    瀏覽量

    298523
  • Linux
    +關注

    關注

    87

    文章

    11123

    瀏覽量

    207909
  • 函數(shù)
    +關注

    關注

    3

    文章

    4237

    瀏覽量

    61967
  • 系統(tǒng)
    +關注

    關注

    1

    文章

    1002

    瀏覽量

    21219
收藏 人收藏

    評論

    相關推薦

    HarmonyOS開發(fā):【基于命令行(安裝庫和工具集)】

    使用命令行進行設備開發(fā)時,可以通過以下步驟安裝編譯OpenHarmony需要的庫和工具。
    的頭像 發(fā)表于 04-25 21:03 ?279次閱讀
    HarmonyOS開發(fā):【基于<b class='flag-5'>命令行</b>(安裝庫和工具集)】

    idea如何輸入命令行參數(shù)

    在許多軟件開發(fā)和系統(tǒng)管理的任務中,我們經(jīng)常需要向應用程序傳遞命令行參數(shù)。命令行參數(shù)是在運行時傳遞給程序的值,用于指定程序的行為和配置選項。本文將詳細介紹如何在不同的編程語言和操作系統(tǒng)中輸入命令行參數(shù)
    的頭像 發(fā)表于 12-06 15:01 ?822次閱讀

    eclipse怎么使用命令行

    命令行中使用Eclipse來完成一些特定的任務。本文將詳細介紹如何在命令行中使用Eclipse。 首先,我們需要確保已經(jīng)正確安裝了JDK(Java Development Kit)和Eclipse
    的頭像 發(fā)表于 12-06 11:26 ?1908次閱讀

    Uboot啟動延時和讀取命令行輸入

    就會中斷等待,進入命令行輸入模式。 如果沒有配置啟動延時功能或者啟動延時超過了設置的時間, U-Boot 運行啟動命令行參數(shù),啟動命令參數(shù)在頂層配置文件中,由 CONFIG_BOOTCOMMAND 宏定義。 2.讀取
    的頭像 發(fā)表于 12-04 17:16 ?1170次閱讀

    python shell怎么用

    Python Shell是一種交互式解釋器,可以通過命令行直接運行Python代碼。在Shell中,可以輸入一行代碼并立即得到結(jié)果,非常適合于測試、嘗試新代碼或進行簡單的任務。本文將詳
    的頭像 發(fā)表于 11-29 14:36 ?863次閱讀

    pycharm命令行終端運行代碼

    Python是一種非常流行的編程語言,許多開發(fā)者使用它來編寫各種應用程序和腳本。為了方便開發(fā)者編寫和測試代碼,PyCharm是一種集成開發(fā)環(huán)境(IDE),它提供了許多功能和工具,其中包括命令行終端
    的頭像 發(fā)表于 11-22 11:20 ?3301次閱讀

    linux命令行運行步驟

    運行Linux命令行涉及以下步驟: 打開終端 在Linux系統(tǒng)中,打開命令行界面的方式有多種,最常見的是打開終端應用程序??梢栽趹贸绦虿藛沃姓业浇K端,點擊打開。 熟悉命令行提示符 在終端中,會發(fā)
    的頭像 發(fā)表于 11-17 10:18 ?630次閱讀

    linux虛擬機怎么調(diào)出命令行

    Linux虛擬機是一種模擬運行Linux操作系統(tǒng)的虛擬環(huán)境,它可以在Windows、Mac、Linux等主機系統(tǒng)上運行。在Linux虛擬機中,你可以通過終端或命令行界面來操作系統(tǒng)和執(zhí)行命令。 調(diào)出
    的頭像 發(fā)表于 11-17 09:55 ?3177次閱讀

    linux切換到命令行模式

    在Linux中,可以通過以下步驟切換到命令行模式: 打開終端。可以在應用菜單中找到終端或命令行終端。 在終端中輸入命令“exit”或“l(fā)ogout”,然后按回車鍵。 系統(tǒng)會提示您輸入管理員密碼。輸入
    的頭像 發(fā)表于 11-13 16:47 ?1466次閱讀

    linux虛擬機怎么調(diào)出命令行

    在Linux虛擬機中調(diào)出命令行界面,可以通過以下步驟實現(xiàn): 打開虛擬機,進入到Linux系統(tǒng)。 在桌面或應用菜單中找到終端或命令行圖標,點擊打開。 輸入命令行指令,執(zhí)行相應的操作。 另外,也可以通過
    的頭像 發(fā)表于 11-08 11:28 ?2510次閱讀

    linux命令行shell編程實戰(zhàn)

    Linux命令行Shell編程實戰(zhàn)主要涉及以下內(nèi)容: Linux命令行基礎:學習Linux命令行的基本操作,如文件管理、進程管理、網(wǎng)絡配置等。熟悉使用
    的頭像 發(fā)表于 11-08 10:57 ?622次閱讀

    linux命令shell編程有什么聯(lián)系

    Linux命令Shell編程之間存在密切的聯(lián)系。 首先,Shell是Linux命令行下的解釋器,它提供了一個用戶界面,使用戶能夠與Linux內(nèi)核進行
    的頭像 發(fā)表于 11-08 10:53 ?771次閱讀

    一個開源MCU級的命令行交互組件

    一個開源MCU級命令行交互組件~
    的頭像 發(fā)表于 10-17 16:26 ?326次閱讀
    一個開源MCU級的<b class='flag-5'>命令行</b><b class='flag-5'>交互</b>組件

    如何在單片機中實現(xiàn)命令交互

    在進行調(diào)試和維護時,常常需要與單片機進行交互,獲取、設置某些參數(shù)或執(zhí)行某些操作,nr_micro_shell正是為滿足這一需求,針對資源較少的MCU編寫的基本命令行工具。
    發(fā)表于 09-27 09:31 ?988次閱讀
    如何在<b class='flag-5'>單片機</b>中實現(xiàn)<b class='flag-5'>命令</b><b class='flag-5'>交互</b>

    命令行下配置防火墻的基礎上網(wǎng)步驟

    部分用戶需要在命令行界面下進行防火墻基礎上網(wǎng)配置,本文展示如何在命令行下配置防火墻的基礎上網(wǎng)步驟。
    的頭像 發(fā)表于 09-24 11:37 ?766次閱讀
    在<b class='flag-5'>命令行</b>下配置防火墻的基礎上網(wǎng)步驟