欢迎光临
我们一直在努力

ESP32 ESP-IDF移植letter-shell源码分享!调试简直不要太方便!

ESP32 ESP-IDF移植letter-shell源码分享!调试简直不要太方便!

  • 一、源码分享
    • 1、效果展示
    • 2、开发环境搭建
    • 3、移植流程
      • 3.1、准备一个基础工程
      • 3.2、下载letter-shell源码
      • 3.3、工程新建packages/letter_shell文件夹将letter-shell源码拷贝到工程中
      • 3.4、新建`shell_linker.lf`链接文件
      • 3.5、添加测试功能
      • 3.6、配置参数介绍
      • 3.7、完整工程下载
  • 二、letter-shell介绍
    • 1、核心定位与特点
    • 2、主要组件与工作原理
    • 3、典型使用流程
    • 4、编译与依赖
    • 5、应用场景
    • 6、 优势与局限
    • 7、总结
  • 三、ESP-IDF详解
    • 1、ESP32 概述
    • 2、 ESP-IDF 详解
      • 2.1 、ESP-IDF 的核心组件与架构
      • 2.2 、ESP-IDF 开发环境与工具链
      • 2.3 、ESP-IDF 开发流程简述
      • 2.4、 示例代码结构 (最简单的 Hello World)
      • 2.5、 优势与特点
      • 2.6 、适用场景
    • 3、总结

在这里插入图片描述

一、源码分享

1、效果展示

在这里插入图片描述

2、开发环境搭建

参考我这篇博文:VS Code 在线安装ESP-IDF,ESP32开发环境搭建详细教程

3、移植流程

3.1、准备一个基础工程

在这里插入图片描述

3.2、下载letter-shell源码

https://github.com/NevermindZZT/letter-shell

3.3、工程新建packages/letter_shell文件夹将letter-shell源码拷贝到工程中

在这里插入图片描述 shell_port.c和shell_port.h是自己创建的。 拷贝完成以后工程结构如下图所示 在这里插入图片描述

  • shell_port.h

    #ifndef __SHELL_PORT_H__
    #define __SHELL_PORT_H__

    #include "shell.h"

    extern Shell shell;

    void userShellInit(void);
    #endif

  • shell_port.c

    #include "shell.h"
    #include "freertos/FreeRTOS.h"
    #include "driver/uart.h"

    #define SHELL_UART UART_NUM_0

    Shell shell;
    char shellBuffer[512];

    /**
    * @brief 用户shell写
    *
    * @param data 数据
    * @param len 数据长度
    *
    * @return unsigned short 写入实际长度
    */

    signed short userShellWrite(char *data, unsigned short len)
    {
    return uart_write_bytes(SHELL_UART, (const char *)data, len);
    }

    /**
    * @brief 用户shell读
    *
    * @param data 数据
    * @param len 数据长度
    *
    * @return unsigned short 读取实际长度
    */

    signed short userShellRead(char *data, unsigned short len)
    {
    return uart_read_bytes(SHELL_UART, (uint8_t *)data, len, portMAX_DELAY);
    }

    /**
    * @brief 用户shell初始化
    *
    */

    void userShellInit(void)
    {
    uart_config_t uartConfig = {
    .baud_rate = 115200,
    .data_bits = UART_DATA_8_BITS,
    .parity = UART_PARITY_DISABLE,
    .stop_bits = UART_STOP_BITS_1,
    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
    };
    uart_param_config(SHELL_UART, &uartConfig);
    uart_driver_install(SHELL_UART, 256 * 2, 0, 0, NULL, 0);
    shell.write = userShellWrite;
    shell.read = userShellRead;
    shellInit(&shell, shellBuffer, 512);

    xTaskCreate(shellTask, "shell", 2048, &shell, 10, NULL);
    }

3.4、新建shell_linker.lf链接文件

在这里插入图片描述

填入如下内容:

[sections:shellCommand]
entries:
shellCommand+

[scheme:shell_command]
entries:
shellCommand -> flash_rodata

[mapping:shell]
archive: *
entries:
* (shell_command);
shellCommand -> flash_rodata KEEP() ALIGN(4, pre, post) SURROUND(shell_command)

修改CMakeLists.txt添加LDFRAGMENTS "shell_linker.lf"

set(src_dirs
letterShell)

set(include_dirs
letterShell)

set(requires
driver esp_timer)

idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires} LDFRAGMENTS "shell_linker.lf")

3.5、添加测试功能

int reboot(int argc, char *argv[])
{
esp_restart();
return 0;
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), reboot, reboot, reboot system);

int info(int argc, char *argv[])
{

esp_chip_info_t chip_info;
uint32_t flash_size;
esp_chip_info(&chip_info);
printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",
CONFIG_IDF_TARGET,
chip_info.cores,
(chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
(chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
(chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");

unsigned major_rev = chip_info.revision / 100;
unsigned minor_rev = chip_info.revision % 100;
printf("silicon revision v%d.%d, ", major_rev, minor_rev);
if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
printf("Get flash size failed");
}

printf("%" PRIu32 "MB %s flash\\n", flash_size / (uint32_t)(1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

printf("Minimum free heap size: %" PRIu32 " bytes", esp_get_minimum_free_heap_size());

return 0;
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), info, info, show system info);

3.6、配置参数介绍

在这里插入图片描述 在这里插入图片描述

3.7、完整工程下载

博客顶部下载

二、letter-shell介绍

Letter-Shell 是一款轻量级的、面向嵌入式系统的命令行交互组件(或称为 Shell)。它的核心目标是为资源受限的嵌入式设备提供一个灵活、易集成、功能实用的命令行接口,方便开发者进行调试、配置和交互控制。

1、核心定位与特点

  • 轻量级:设计简洁,代码量小,对内存和 Flash 空间要求低,非常适合资源有限的单片机(MCU)环境。
  • 易移植:采用纯 C 语言实现,与硬件平台和操作系统解耦良好。它主要依赖 printf 和 scanf(或类似功能的输入输出函数),只要提供适配好的输入输出函数,就能轻松移植到不同的平台(如裸机、RTOS 等)。
  • 灵活的命令注册:核心机制是通过注册函数指针来添加命令。开发者可以非常方便地将自定义的函数注册为 Shell 命令。
  • 参数解析:内置了基础的参数解析功能,可以将用户输入的字符串参数转换成数字(整数、浮点数)、字符串等类型,并传递给注册的命令函数。
  • 用户友好:通常提供命令帮助(输入 help 或类似命令列出所有可用命令及简介)、命令补全(按 Tab 键)、历史命令记录(使用方向键 ↑↓)等功能,提升交互体验。
  • 异步执行(可选):部分实现或扩展支持命令的异步执行,允许在执行耗时命令时不阻塞整个 Shell 的输入。
  • 2、主要组件与工作原理

  • 命令解析器:
    • 接收用户通过串口(或其他输入设备)输入的字符串。
    • 按照空格分割命令名和参数。
    • 在注册的命令列表中查找匹配的命令名。
  • 命令注册表:
    • 一个数据结构(通常是结构体数组或链表),存储了所有注册的命令信息。
    • 每条记录至少包含:
      • 命令名字符串(如 "led", "read_temp")。
      • 命令帮助信息字符串(如 "control LED: on/off")。
      • 命令处理函数的函数指针。
  • 命令处理函数:
    • 用户自定义的函数,实现命令的具体功能。
    • 其函数签名通常定义为类似 int cmd_func(int argc, char *argv[]) 的形式。
      • argc: 参数个数(包括命令名本身)。
      • argv: 参数数组指针,argv[0] 是命令名字符串,argv[1], argv[2] … 是用户输入的参数。
    • 函数内部解析 argv 中的参数,执行操作(如控制 GPIO、读取传感器、设置参数),并通过输出函数返回结果或信息。
  • 参数解析器:
    • 辅助功能,提供函数将 argv 中的字符串参数转换为整数、浮点数等类型。
    • 例如:int shell_parse_int(char *arg, int *value)。
  • 输入输出适配层:
    • Shell 核心不直接操作硬件。
    • 开发者需要实现字符输入函数(如 shell_getchar())和字符输出函数(如 shell_putchar(char ch) 或直接利用 printf)。
    • 这些函数需要适配到具体的硬件通信接口(如 UART、USB CDC、网络 Socket 等)。
  • 行编辑功能(可选):
    • 处理退格键删除、方向键移动光标、命令历史、Tab 补全等交互细节。
  • 3、典型使用流程

  • 初始化:调用 shell_init(),设置输入输出函数。
  • 注册命令:在程序初始化阶段,使用类似 SHELL_CMD_REGISTER(cmd_name, cmd_func, cmd_help) 的宏或函数,将自定义的命令处理函数注册到 Shell。
  • 轮询处理:在主循环中,定期调用 shell_task() 或 shell_process() 函数。这个函数会:
    • 检查输入缓冲区是否有新字符。
    • 解析输入行。
    • 查找并执行匹配的命令。
    • 调用命令处理函数。
    • 输出提示符 > 或命令执行结果。
  • 实现命令函数:编写具体的 cmd_func 函数,利用参数解析函数处理输入,执行操作,使用 printf 或类似输出反馈信息。
  • 4、编译与依赖

    • 核心依赖:标准 C 库(string.h, stdio.h 的部分功能或自定义实现)。
    • 平台依赖:开发者必须提供 shell_getchar() 和 shell_putchar(char ch) 的实现(或配置 Shell 使用 printf/scanf)。
    • 配置选项:通常通过宏定义来配置 Shell 的行为,如最大命令数、历史记录条数、是否支持参数解析、是否支持异步等。

    5、应用场景

    • 嵌入式设备调试:查询状态、设置参数、触发测试。
    • 设备配置:配置网络参数、工作模式等。
    • 固件升级:通过命令触发 Bootloader。
    • 远程控制:通过网络或其他通信接口实现远程 Shell。
    • 教学演示:展示嵌入式系统交互概念。

    6、 优势与局限

    • 优势:轻巧、易用、灵活、占用资源少、易于集成。
    • 局限:功能相对基础,不如 bash 或 BusyBox 强大(如不支持管道 |、复杂脚本等);安全性通常不是首要考虑(如无用户权限管理)。

    7、总结

    Letter-Shell 是嵌入式开发者的一个实用工具,它为 MCU 设备提供了一个便捷的命令行交互界面。其轻量化和易移植的特性使其成为资源受限环境下实现设备调试、配置和控制的理想选择。通过简单的命令注册机制,开发者可以快速扩展其功能,适配各种应用需求。

    三、ESP-IDF详解

    1、ESP32 概述

    ESP32 是由乐鑫科技(Espressif Systems)推出的一款高性能、低功耗、高集成度的 Wi-Fi & 蓝牙双模系统级芯片(SoC)。它广泛应用于物联网(IoT)、智能家居、工业控制等领域。其关键特性包括:

    • 双核处理器(通常为 Xtensa LX6,某些型号为 RISC-V)
    • 集成 Wi-Fi (802.11 b/g/n) 和蓝牙 (包括经典蓝牙和低功耗蓝牙 BLE)
    • 丰富的外设接口:

      S

      P

      I

      SPI

      SPI,

      I

      2

      C

      I2C

      I2C,

      I

      2

      S

      I2S

      I2S,

      U

      A

      R

      T

      UART

      UART,

      A

      D

      C

      ADC

      ADC,

      D

      A

      C

      DAC

      DAC,

      P

      W

      M

      PWM

      PWM, 触摸传感器等

    • 充足的内存(RAM 和 Flash 选项多样)
    • 强大的安全特性(如加密加速器)
    • 超低功耗设计,支持多种休眠模式

    2、 ESP-IDF 详解

    ESP-IDF (Espressif IoT Development Framework) 是乐鑫官方为 ESP32、ESP32-S 系列、ESP32-C 系列等芯片提供的开发框架和 SDK(软件开发工具包)。它是开发基于 ESP32 芯片应用程序的首选和官方推荐工具。

    2.1 、ESP-IDF 的核心组件与架构

    ESP-IDF 是一个分层、模块化的框架:

    • 硬件抽象层 (HAL): 提供对芯片硬件资源(如 GPIO、UART、SPI、I2C、定时器、ADC、DAC、RTC、Wi-Fi、蓝牙等)进行操作的统一接口,屏蔽底层硬件细节。
    • 驱动 (Drivers): 在 HAL 之上,提供更易用、功能更丰富的设备驱动(如 SPI Flash 驱动、SD 卡驱动、以太网驱动等)。
    • FreeRTOS: ESP-IDF 深度集成了开源的 FreeRTOS 实时操作系统内核。它提供了任务管理、队列、信号量、软件定时器、中断管理等机制,充分利用 ESP32 的多核特性(任务可以在不同核心上运行)。
    • 中间件:
      • Wi-Fi 协议栈: 实现 Wi-Fi 的 Station(客户端)、SoftAP(接入点)、Promiscuous(监听)模式。
      • 蓝牙协议栈: 实现经典蓝牙和低功耗蓝牙 (BLE) 的各种角色(如 GATT Client/Server, GAP Central/Peripheral)。
      • TCP/IP 协议栈 (lwIP): 轻量级的 TCP/IP 协议栈,支持 IPv4/IPv6 (部分型号)、DHCP、DNS、Socket API 等。
      • 文件系统 (FATFS/VFS): 支持在 SPI Flash 或外部存储设备上使用 FAT 文件系统。
      • 加密库: 提供 AES、SHA、RSA 等加密算法的软件和硬件加速实现。
      • HTTP/WebSocket/MQTT 等协议库: 方便构建网络应用。
    • 应用程序: 用户编写的业务逻辑代码,运行在 FreeRTOS 的任务中,通过调用下层 API 实现功能。

    2.2 、ESP-IDF 开发环境与工具链

    • 工具链: 基于 GNU GCC 编译器(针对 Xtensa 或 RISC-V 架构)。
    • 构建系统: 使用 CMake(早期版本使用 GNU Make)。开发者编写 CMakeLists.txt 文件来定义项目结构、源文件、依赖组件等。
    • 配置工具: menuconfig。这是一个基于文本的图形化配置工具(类似于 Linux Kernel 的 make menuconfig),用于配置 ESP-IDF 的众多选项,如:
      • 选择目标芯片型号
      • 配置 Wi-Fi/BT 参数
      • 调整 FreeRTOS 设置(任务栈大小、优先级等)
      • 配置日志输出级别和方式
      • 配置内存布局
      • 启用/禁用特定功能和外设驱动
    • 核心工具 – idf.py: 这是 ESP-IDF 提供的命令行工具,用于执行构建、烧录、调试、监视串口输出等几乎所有开发任务。常用命令如:
      • idf.py set-target esp32 (设置目标芯片)
      • idf.py menuconfig (启动配置工具)
      • idf.py build (编译项目)
      • idf.py -p PORT flash (烧录固件到设备,PORT 为串口,如 COM3 或 /dev/ttyUSB0)
      • idf.py -p PORT monitor (启动串口监视器,查看设备日志输出)
      • idf.py fullclean (彻底清理构建目录)

    2.3 、ESP-IDF 开发流程简述

  • 环境搭建: 在 Windows、Linux 或 macOS 上安装 ESP-IDF 开发环境(包括工具链、Python、Git 等)。
  • 创建项目: 使用 idf.py create-project 或复制示例项目模板。
  • 编写代码: 在 main 目录下编写应用程序代码 (通常是 main.c 或 app_main() 函数)。
  • 配置项目: 运行 idf.py menuconfig 根据需求进行配置。
  • 编译项目: 运行 idf.py build 生成可执行固件 (.bin 文件)。
  • 烧录固件: 将 ESP32 开发板连接到电脑,运行 idf.py -p PORT flash 将固件烧录到设备 Flash 中。
  • 监视输出: 运行 idf.py -p PORT monitor 查看设备运行日志,进行调试。可以使用 ESP_LOGx (如 ESP_LOGI, ESP_LOGE) 函数打印不同级别的日志。
  • 2.4、 示例代码结构 (最简单的 Hello World)

    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "esp_log.h"

    static const char *TAG = "MAIN";

    void app_main(void)
    {
    while (1) {
    ESP_LOGI(TAG, "Hello World!"); // 打印 Info 级别日志
    vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 1000 毫秒 (FreeRTOS 延时)
    }
    }

    2.5、 优势与特点

    • 官方支持: 由芯片原厂维护,更新及时,与新芯片特性同步快。
    • 功能全面: 提供对 ESP32 所有硬件特性和外设的底层访问。
    • 性能优化: 针对 ESP32 硬件进行了深度优化(如 Wi-Fi/BT 共存)。
    • 稳定性高: 经过大量商业产品验证。
    • 社区活跃: 用户多,社区支持好,问题容易找到解决方案。
    • 文档完善: 官方提供详尽的 API 参考指南、编程指南和示例代码。
    • 模块化: 易于扩展和复用代码,方便管理大型项目。
    • 开源免费: 基于 Apache 2.0 许可证。

    2.6 、适用场景

    ESP-IDF 适用于需要深度控制硬件、追求高性能、高稳定性或需要使用 ESP32 特有功能(如超低功耗协处理器 ULP)的应用开发。对于快速原型开发,也可以考虑基于 ESP-IDF 构建的更高级框架(如 Arduino for ESP32、MicroPython),但这些框架最终都依赖于 ESP-IDF 的底层功能。

    3、总结

    ESP-IDF 是开发 ESP32 系列芯片的强大、灵活且功能完备的官方框架。它提供了从硬件操作到网络协议栈的全套解决方案,结合 FreeRTOS 实现了高效的多任务处理。虽然其学习曲线相对陡峭,尤其是对于不熟悉嵌入式开发和 RTOS 的开发者,但它提供了最直接、最强大的方式来充分利用 ESP32 的潜力,是开发复杂或高性能 ESP32 应用的基石。掌握 idf.py 工具链和 menuconfig 配置是使用 ESP-IDF 的关键。

    在这里插入图片描述

    赞(0)
    未经允许不得转载:171主机测评 » ESP32 ESP-IDF移植letter-shell源码分享!调试简直不要太方便!
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址