在STM32与GCC平台上移植letter-shell

letter-shell介绍

letter-shell是一个体积小巧,功能完善的嵌入式shell。

创建项目

先使用STM32CubeMX创建一个CMake项目,由于我们需要使用串口收发数据,所以把串口1打开。

安装letter-shell

letter-shell Github仓库下载letter-shell。把下载好的文件解压,存放至项目目录下的letter-shell文件夹中。

letter-shell文件夹中,创建CMakeLists.txt文件,写入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cmake_minimum_required(VERSION 3.22)

# letter-shell - A lightweight embedded shell
# https://github.com/NevermindZZT/letter-shell

add_library(letter-shell STATIC
${CMAKE_CURRENT_SOURCE_DIR}/src/shell.c
${CMAKE_CURRENT_SOURCE_DIR}/src/shell_cmd_list.c
${CMAKE_CURRENT_SOURCE_DIR}/src/shell_companion.c
${CMAKE_CURRENT_SOURCE_DIR}/src/shell_ext.c
)

target_include_directories(letter-shell PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)

# Inherit STM32 HAL include paths (needed for HAL_GetTick in shell_cfg.h)
target_link_libraries(letter-shell PUBLIC stm32cubemx)

之后在项目的CMakeLists.txt中,导入此库。

1
2
3
4
5
6
7
8
9
10
11
12
# Add letter-shell (lightweight embedded command shell)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/letter-shell ${CMAKE_CURRENT_BINARY_DIR}/letter-shell)

# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
stm32cubemx
...
letter-shell
...
# Add user defined libraries
)

配置letter-shell

letter-shell/src目录下的shell.cfg文件中,修改

1
2
3
#define     SHELL_USING_CMD_EXPORT      1

#define SHELL_GET_TICK() HAL_GetTick()

配置链接文件

由于我们在配置中使用了命令导出方式,故需要修改链接文件。

STM32F103xx_FLASH.ld文件中,

添加下述内容:

1
2
3
4
5
6
7
8
9
/* letter-shell command export section */
.shell_command :
{
. = ALIGN(4);
_shell_command_start = .;
KEEP(*(shellCommand))
. = ALIGN(4);
_shell_command_end = .;
} >FLASH

创建接口

此处我们使用中断方式,因此只需要初始化shellWrite,以及在合适时机调用shellHandler即可。

在项目创建serial_shell.h/c文件,并加入到CMakeLists.txt中。

1
2
3
4
# Create an executable object type
add_executable(${CMAKE_PROJECT_NAME}
Core/Inc/serial_shell.h
Core/Src/serial_shell.c)

我们一共需要准备shell初始化,串口写入和解析串口读取三个接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// serial_shell.h

#pragma once

#include <shell.h>
#include <stdint.h>

extern Shell shell;

signed short shell_write(char* bytes, unsigned short len);

void shell_init();

void shell_parse_input(uint16_t size);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// serial_shell.c

#include "serial_shell.h"

#include <usart.h>

Shell shell;
char shellBuffer[512];
uint8_t buffer[32];

signed short shell_write(char* bytes, unsigned short len) {
HAL_UART_Transmit(&huart1, (uint8_t*)bytes, len, 50);
return len;
}

void shell_init() {
shell.write = shell_write;
shellInit(&shell, shellBuffer, sizeof(shellBuffer));
HAL_UARTEx_ReceiveToIdle_IT(&huart1, buffer, sizeof(buffer));
}

void shell_parse_input(uint16_t size) {
for (size_t i = 0; i < size; i++) {
shellHandler(&shell, buffer[i]);
}
HAL_UARTEx_ReceiveToIdle_IT(&huart1, buffer, sizeof(buffer));
}

之后在main.c中,调用初始化函数与串口解析函数即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* @brief The application entry point.
* @retval int
*/
int main(void) {
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick.
*/
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
shell_init();
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart == &huart1) {
shell_parse_input(Size);
}
}

效果呈现

编译并烧录程序后,打开串口调试工具,推荐SecureCRT,即可看到启动后的效果。

1
2
3
4
5
6
7
8
9
10
11
 _         _   _                  _          _ _
| | ___| |_| |_ ___ _ __ ___| |__ ___| | |
| | / _ \ __| __/ _ \ '__| / __| '_ \ / _ \ | |
| |__| __/ |_| || __/ | \__ \ | | | __/ | |
|_____\___|\__|\__\___|_| |___/_| |_|\___|_|_|

Build: Jul 30 2026 17:52:22
Version: 3.1.2
Copyright: (c) 2020 Letter

letter:/$

自定义使用

函数定义

详见官方Github链接

变量调用

详见官方Github链接


在STM32与GCC平台上移植letter-shell
https://blog.faneter.top/2026/07/30/在STM32与GCC平台上移植letter-shell/
作者
Faneter
发布于
2026年7月30日
许可协议