1. 简介
Letter shell 是一个 C 语言编写的,可以嵌入在程序中的嵌入式 shell,主要面向嵌入式设备,以 C 语言函数为运行单位,可以通过命令行调用,运行程序中的函数。
1.1. 主要特性
- 命令自动补全
- 快捷键功能定义
- 命令权限管理
- 用户管理
- 变量支持
- 代理函数和参数代理解析
2. 获取 Letter shell 源码
Letter shell 的 github 仓库地址为: https://github.com/NevermindZZT/letter-shell
这里我下载最新版的3.1.2版本
3.CubeMX 新建工程
3.1 FreeRTOS 移植letter-shell
为什么以FreeRTOS移植 Letter shell 官方给的例程就是FreeRTOS的,基于开发板新建工程,主要配置串口。根据自己的开发板选择相应的串口。串口配置默认就好,波特率1152000 ,注意一定要将中断打开。
由于使用了FreeRTOS,简单配置一下,随便新建一个任务。
在这里为避免生成代码时出现警告,重新配置下SYS将滴答定时器换成TIM6;
CubeMX就配置完成了。
4. STM32G474 Letter shell 移植
4.1. 工程文件结构
新建Letter_shell 文件夹,导入 Letter_shell 核心文件, 将 extensions、 src 和 tools 文件夹直接拷贝到 Letter_shell 文件夹里,新建 port 文件夹,用于存放移植接口文件 shell_cfg.h、 shell_port.h和 shell_port.c 文件,这三个文件在下载的源码letter-shell-master->demo->stm32-freertos文件夹内。
直接添加到自己新建的port文件夹内。
4.2. 搭建 Keil 工程框架
以Keil这个IDE为例(其他IDE工程搭建情况类似,这里不做赘述), 在工程里添加Letter_shell,并将 src 文件夹和 port 文件夹下的 c 文件添加进来。
在 Setup Compiler Include Paths 中将 src 和 port 文件夹里的头文件包含进来。
在 Keil 工程的 Linker 选项卡里,添加–keep shellCommand*, 以防被编译优化。
4.3. 编写移植接口文件
重写shell_port.c
/**
* @file shell_port.c
* @author Letter (NevermindZZT@gmail.com)
* @brief
* @version 0.1
* @date 2019-02-22
*
* @copyright (c) 2019 Letter
*
*/
#include "FreeRTOS.h"
#include "task.h"
#include "shell.h"
//#include "serial.h"
#include "stm32g4xx_hal.h"
#include "usart.h"
//#include "cevent.h"
//#include "log.h"
Shell shell;
char shellBuffer[512];
//static SemaphoreHandle_t shellMutex;
/**
* @brief 用户shell写
*
* @param data 数据
* @param len 数据长度
*
* @return short 实际写入的数据长度
*/
short userShellWrite(char *data, unsigned short len)
{
HAL_UART_Transmit(&huart2, (uint8_t *)data, len, 0x1FF);
return len;
}
/**
* @brief 用户shell读
*
* @param data 数据
* @param len 数据长度
*
* @return short 实际读取到
*/
short userShellRead(char *data, unsigned short len)
{
//return HAL_UART_Receive(&hlpuart1, (uint8_t *)data, len, 0);
if(HAL_UART_Receive(&huart2, (uint8_t *)data, 1, 0xFFFF) != HAL_OK)
{
return 0;
}
else
{
return 1;
}
}
/**
* @brief 用户shell上锁
*
* @param shell shell
*
* @return int 0
*/
int userShellLock(Shell *shell)
{
// xSemaphoreTakeRecursive(shellMutex, portMAX_DELAY);
return 0;
}
/**
* @brief 用户shell解锁
*
* @param shell shell
*
* @return int 0
*/
int userShellUnlock(Shell *shell)
{
// xSemaphoreGiveRecursive(shellMutex);
return 0;
}
/**
* @brief 用户shell初始化
*
*/
void userShellInit(void)
{
// shellMutex = xSemaphoreCreateMutex();
shell.write = userShellWrite;
shell.read = userShellRead;
// shell.lock = userShellLock;
// shell.unlock = userShellUnlock;
shellInit(&shell, shellBuffer, 512);
// if (xTaskCreate(shellTask, "shell", 256, &shell, 5, NULL) != pdPASS)
// {
// logError("shell task creat failed");
// }
}
//CEVENT_EXPORT(EVENT_INIT_STAGE2, userShellInit);
编写串口回调函数,这里我放在main.c.
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart ->Instance == USART2)
{
shellHandler(&shell, recv_buf);
HAL_UART_Receive_IT(&huart2, (uint8_t*)&recv_buf, 1);
}
}
/* USER CODE END 4 */
Letter shell 函数调用,由于使用了操作系统只需要初始化,在shell_cfg.h中已经配置好了。
/* USER CODE BEGIN 2 */
userShellInit();
HAL_UART_Receive_IT(&huart2, (uint8_t*)&recv_buf, 1);
/* USER CODE END 2 */
5.🆗大功告成,MobaXtermh展示结果
6.总结
提示:
- 打开串口中断,确定能进入回调函数。
- 注意shell_cfg.h文件里的配置
- 最好选择USART