Lettershell之移植篇

lettershell项目链接 https://github.com/NevermindZZT/letter-shell

更多精彩内容欢迎关注微信公众号:码农练功房
在这里插入图片描述

letter shell是一个C语言编写的,可以嵌入在程序中的嵌入式shell。主要面向嵌入式设备,以C语言函数为运行单位,可以通过命令行调用,运行程序中的函数。

letter-shell为调试单片机程序提供了极大的便利。它使得开发者能够在不连接调试器的情况下通过命令行界面与单片机进行交互,这对于快速迭代和调试非常有用。

目录

物理结构

本文基于letter-shell 3.x版本。

.
├── demo
│   ├── esp-idf
│   ├── segger-rtt
│   ├── stm32-freertos
│   └── x86-gcc
├── doc
│   └── img
├── extensions
│   ├── cpp_support
│   ├── fs_support
│   ├── game
│   ├── log
│   ├── shell_enhance
│   └── telnet
├── LICENSE
├── README.md
├── src
│   ├── shell.c
│   ├── shell_cfg.h
│   ├── shell_cmd_list.c
│   ├── shell_companion.c
│   ├── shell_ext.c
│   ├── shell_ext.h
│   └── shell.h
└── tools

demo目录下提供了各个平台移植示例,使用者根据需要可以参考。

extensions目录下是一些拓展功能。

src目录下的文件为letter-shell的核心源码。

STM32裸机移植

demo/stm32-freertos提供了基于freertos的移植示例。裸机移植与之类似,将src下的文件全部拷贝到MDK工程下,同时新建shell_port.h、shell_port.c文件,加入工程:

请添加图片描述

移植其实就是配置shell_cfg.h中定义的宏、针对具体平台实现shell读写函数,如果我们需要使用单片机的串口实现shell的功能:

// shell_port.c
#include "shell.h"
#include "shell_port.h"
#include "stm32f10x_usart.h"
/* 1. 创建shell对象,开辟shell缓冲区 */
Shell shell;
char shell_buffer[512];
/* 2. 自己实现shell写函数 */
signed short User_Shell_Write(char *data, unsigned short size)
{
	for(int i = 0;i <size;++i)
	{
		USART_SendData(USART1,data[i]);
		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	 
	}
	return size;
}
signed short User_Shell_Read(char *data, unsigned short size)
{   	   
	if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
	{  
		return 0;
	}
	*data = USART_ReceiveData(USART1); 
	return 1;
}
/* 3. 编写初始化函数 */
void userShellInit(void)
{
	//注册自己实现的写函数
    shell.write = User_Shell_Write;
	shell.read = User_Shell_Read;
	//调用shell初始化函数
    shellInit(&shell, shell_buffer, 512);
}

对应头文件如下:

// shell_port.h
#ifndef __SHELL_PORT_H__
#define __SHELL_PORT_H__

#include "shell.h"
extern Shell shell;
void userShellInit(void);
#endif

对于裸机环境,有两种建立shell任务的方式:

方式一为轮询方式,在主循环中调用shellTask,需要使能SHELL_TASK_WHILE宏:

int main(void)
{  
    SystemInit();	//配置系统时钟为 72M 
	SysTick_Configuration();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	USART1_Config(); //USART1 配置 	
    LED_GPIO_Config();	
	userShellInit();
	shellTask(&shell);
}
// shell.c
void shellTask(void *param)
{
    Shell *shell = (Shell *)param;
    char data;
#if SHELL_TASK_WHILE == 1
    while(1)
    {
#endif
        if (shell->read && shell->read(&data, 1) == 1)
        {
            shellHandler(shell, data);
        }
#if SHELL_TASK_WHILE == 1
    }
#endif
}

方式二为中断方式,这种方式下不用注册shell->read,但需要在中断中调用shellHandler

void USART1_IRQHandler(void)   //串口1中断服务程序
{
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
	  u8 Res =USART_ReceiveData(USART1);
	  shellHandler(&shell,Res);
  } 
} 

两种方式选择一种即可。两种方式内部其实都是调用了shellHandler,这个函数十分重要,是获取数据的入口

使用MDK编译时,需要在keil的target option中增加–keep shellCommand*,防止定义的命令被优化掉。

对于命令定义先按下不表,后面文章我们会详细分析命令注册机制。

Linux平台移植

demo/x86-gcc下已经为我们完成了Linux平台下的移植,这里我们比较Linux平台下的移植和单片机下的移植有何差异。

这里仅截取Linux平台下,涉及到基础功能相关的移植代码:

// shell_port.c
unsigned short userShellWrite(char *data, unsigned short len)
{
    unsigned short length = len;
    while (length--)
    {
        putchar(*data++);
    }
    return len;
}

unsigned short userShellRead(char *data, unsigned short len)
{
    unsigned short length = len;
    while (length--)
    {
        *data++ = getchar();
    }
    return len;
}

void userShellInit(void)
{
    // ......
    shell.write = userShellWrite;
    shell.read = userShellRead;
    // ......
    shellInit(&shell, shellBuffer, 512);
    // ......
}
// main.c
int main(void)
{
    signal(SIGINT, signalHandler);
    system("stty -echo");
    system("stty -icanon");
    userShellInit();
    shellTask(&shell);
    return 0;
}

和STM32相比,注册的write、read函数不同了。在Linux平台下底层读写依赖于getchar、putchar,而对于STM32依赖于固件库中的串口读写。

总结

  1. letter-shell通过write、read函数注册的方式确实提高了它的灵活性,使得 letter-shell 可以适应不同的平台和环境,无论是单片机还是 Linux 系统。这种方式允许开发者根据自己的需求选择合适的输入输出机制,这种方式不仅提高了可移植性,还增强了 letter-shell 的实用性。
<think>好的,用户想了解如何将Lettershell的HAL库进行移植,需要提供教程或指南。首先,我需要回忆一下Lettershell是什么。Lettershell是一个用于嵌入式系统的命令行工具,允许通过串口或其他接口执行命令。移植HAL库的话,可能需要适配硬件相关的驱动,比如串口通信、GPIO等。 接下来,用户提到的HAL库应该是指STM32的HAL库,因为之前的参考引用都是关于STM32和HAL库的移植,比如MLX90640和LWIP的移植。所以用户可能是在STM32平台上使用Lettershell,需要将Lettershell与HAL库结合。 我需要考虑Lettershell移植步骤。通常,这类库的移植需要实现底层接口,比如串口的初始化和读写函数。用户可能需要修改Lettershell的硬件抽象层,使其调用STM32的HAL库函数。 根据参考引用中的例子,比如引用[2]提到修改GPIO引脚配置,可能用户需要类似地调整Lettershell的底层驱动代码,使用正确的HAL函数和引脚设置。此外,可能还需要处理中断、DMA等,具体取决于Lettershell的要求。 需要注意的问题包括:确保串口发送和接收函数正确对接HAL库的函数,处理可能的缓冲区管理,以及配置正确的时钟和引脚。另外,可能需要调整编译选项,将Lettershell的源码加入工程,并处理可能的依赖关系。 用户可能遇到的问题包括链接错误、函数未实现、或者串口无法正常通信。因此,在步骤中需要详细说明如何添加源文件,实现必要的函数,并进行测试。同时,要提醒用户检查硬件连接和配置,比如波特率是否匹配,引脚是否正确。 最后,生成相关问题需要考虑用户可能进一步的需求,比如如何添加自定义命令、优化性能、移植到其他平台,或者结合其他外设如WiFi模块。这样可以帮助用户更深入地应用Lettershell,并解决后续可能出现的问题。</think>### Lettershell HAL库移植指南 Lettershell是一个嵌入式命令行工具,通过适配硬件抽象层(HAL)可实现与不同MCU的兼容。以下是基于STM32 HAL库的移植步骤: 1. **基础工程准备** - 创建或打开已有STM32 HAL库工程(如CubeMX生成) - 下载最新Lettershell源码(建议从GitHub获取官方版本) 2. **文件添加与配置** ```c // 工程目录添加以下文件 shell.c // shell核心逻辑 shell_port.c // 移植接口文件 shell_cmd.c // 示例命令集 ``` 3. **串口驱动适配** ```c // 在shell_port.c中实现关键函数 int shellWrite(char* buf, unsigned short len) { return HAL_UART_Transmit(&huart1, (uint8_t*)buf, len, 0xFFFF); // 使用HAL库串口发送 } int shellRead(char* buf, unsigned short len) { return HAL_UART_Receive(&huart1, (uint8_t*)buf, len, 0xFFFF); // 使用HAL库串口接收 } ``` 4. **中断配置** ```c // 在stm32xxx_it.c中修改串口中断处理 void USART1_IRQHandler(void) { HAL_UART_IRQHandler(&huart1); shellHandler(&shell); // 添加shell中断处理 } ``` 5. **时钟与引脚配置** - 通过CubeMX配置USART的GPIO和时钟(参考引用[2]的GPIO修改方法) - 确保波特率与终端软件设置一致(如115200) 6. **功能验证** ```c // 在main函数中初始化 Shell shell; shell.write = shellWrite; shell.read = shellRead; shellInit(&shell); // 添加测试命令 SHELL_EXPORT_CMD(help, shellHelp, show all commands); ``` **注意要点** - 需要根据实际硬件调整`huart1`实例名称 - 若使用DMA传输需实现相应回调函数 - 建议启用`SHELL_USING_TASK`宏实现后台任务处理 [^1]: 引用[1]中提到的HAL库移植方法可参考硬件配置部分 [^2]: GPIO修改方法参考引用[2]中的引脚适配流程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值