星標(biāo)公眾號(hào),讓嵌入式知識(shí) “投喂” 不停歇!
2026打造你的職場(chǎng)核心競(jìng)爭(zhēng)力(Linux技術(shù)棧)
大家好,我是雜燴君。
之前的文章有朋友留言推薦了 CherrySH,今天我們就來(lái)一起看下。


↑↓ 按鍵$作為前綴,例如$PATHHOME、END 切換光標(biāo)Ctrl + \<key\>Alt + \<key\> ``F1-F12` 等SIGINT和Ctrl+ZSIGTSTP,可中斷當(dāng)前執(zhí)行的 shell 任務(wù)一句話說(shuō)清楚:CherrySH 就是讓你在 MCU 上敲命令,還能有方向鍵、歷史、TAB 補(bǔ)全這些體驗(yàn),而且不用 malloc。
它怎么做到的??jī)烧校?/span>

說(shuō)明:
staticintmy_cmd(int argc, char **argv)
{
chry_shell_t *csh = (void *)argv[argc + 1];
csh_printf(csh, "====== 嵌入式大雜燴 ======\r\n");
return0;
}
CSH_CMD_EXPORT(my_cmd, );

這個(gè)宏展開后,會(huì)在 FSymTab 段里放一個(gè)結(jié)構(gòu)體:
// csh.h 里的定義
typedefstruct {
constchar *path; // 命令路徑,如 "/bin"
constchar *name; // 命令名
constchar *usage; // 簡(jiǎn)短說(shuō)明
constchar *help; // 詳細(xì)幫助
int (*func)(int argc, char **argv); // 函數(shù)指針
} chry_syscall_t;
鏈接器把所有這種結(jié)構(gòu)體收集到一起,形成一個(gè)"命令表"。
看 chry_shell_task_repl() 核心邏輯:
// 讀一行
char *line = chry_readline(&csh->rl, buffer, size, &linesize);
// 解析成 argc/argv(原地切割,空格變 \0)
argc = chry_shell_parse(line, linesize, argv, MAX_ARG);
// 遍歷命令表找匹配
for (call = csh->cmd_tbl_beg; call < csh->cmd_tbl_end; call++) {
if (路徑+名字匹配) {
call->func(argc, argv); // 找到就調(diào)用
break;
}
}
用流程圖表示:

CherrySH/
├── chry_shell.c/h # Shell 核心(解析、執(zhí)行、用戶管理)
├── csh.h # 配置 + 導(dǎo)出宏
├── cherryrl/ # ReadLine 模塊(行編輯、歷史、補(bǔ)全)
├── builtin/ # 內(nèi)置命令示例(help、clear 等)
└── samples/ # 移植示例(HPM、STM32)
以先楫半導(dǎo)體hpm5301evklite為例。
.text : {
.....
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
}
#include"csh.h"
staticchry_shell_t csh;
staticuint16_tcsh_sput_cb(chry_readline_t *rl, constvoid *data, uint16_t size)
{
uint16_t i;
(void)rl;
for (i = 0; i < size; i++) {
if (status_success != uart_send_byte(HPM_UART0, ((uint8_t *)data)[i])) {
break;
}
}
return i;
}
staticuint16_tcsh_sget_cb(chry_readline_t *rl, void *data, uint16_t size)
{
uint16_t i;
(void)rl;
for (i = 0; i < size; i++) {
if (status_success != uart_receive_byte(HPM_UART0, (uint8_t *)data + i)) {
break;
}
}
return i;
}
chry_shell_task_exec 和 chry_shell_task_repl,參考 samples 中實(shí)現(xiàn)#define __ENV_PATH "/sbin:/bin"
constchar ENV_PATH[] = __ENV_PATH;
CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH));
#define __ENV_ZERO ""
constchar ENV_ZERO[] = __ENV_ZERO;
CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO));
CSH_CMD_EXPORT 導(dǎo)出命令staticintwrite_led(int argc, char **argv)
{
if (argc < 2) {
printf("usage: write_led <status>\r\n\r\n");
printf(" status 0 or 1\r\n\r\n");
return-1;
}
board_led_write(atoi(argv[1]) == 0);
return0;
}
CSH_CMD_EXPORT(write_led, );
優(yōu)點(diǎn):
缺點(diǎn):
如果覺得文章有幫助,麻煩幫忙轉(zhuǎn)發(fā),謝謝!
猜你喜歡:
2026打造你的職場(chǎng)核心競(jìng)爭(zhēng)力(Linux技術(shù)棧)
嵌入式協(xié)議處理:流式解析 vs 一次性解析