ESP-Dongle 双重功能嵌入式系统软件设计与实现
关注微信公众号,提前获取相关推文

项目简介
ESP-Dongle 是一款基于 ESP 系列芯片(例如 ESP32 或 ESP8266)开发的嵌入式设备,旨在提供便捷的无线网络连接和移动存储功能。该设备通过 USB 接口连接到主机(例如电脑),并能够一键切换两种工作模式:
- 无线网卡模式: ESP-Dongle 作为无线网卡,允许主机通过 WiFi 网络连接到互联网。这对于没有内置无线网卡或者需要更稳定、更快速 WiFi 连接的设备非常有用。
- U 盘模式: ESP-Dongle 作为 USB 大容量存储设备(U 盘),允许用户存储和传输文件。用户可以将文件存储在 Dongle 内部的 Flash 存储器中,并通过 USB 接口访问这些文件。
项目目标
我们的目标是设计并实现 ESP-Dongle 的嵌入式软件系统,确保系统具备以下关键特性:
- 可靠性: 系统能够稳定运行,不易崩溃,数据传输准确无误。
- 高效性: 系统资源利用率高,运行速度快,响应及时。
- 可扩展性: 系统架构设计灵活,易于添加新功能或修改现有功能。
- 易维护性: 代码结构清晰,注释详尽,方便后续维护和升级。
系统设计架构
为了实现上述目标,我们采用分层架构来设计 ESP-Dongle 的嵌入式软件系统。分层架构能够将系统分解为多个独立的模块,每个模块负责特定的功能,模块之间通过清晰的接口进行通信。这有助于提高代码的模块化程度、可维护性和可重用性。
我们的系统架构主要分为以下几个层次:
硬件抽象层 (HAL - Hardware Abstraction Layer):
- 作用: 屏蔽底层硬件差异,为上层软件提供统一的硬件接口。
- 模块:
- GPIO 驱动: 控制 GPIO 引脚的输入输出状态,用于 LED 指示、按键检测等。
- SPI 驱动: 控制 SPI 接口,用于与 Flash 存储器、SD 卡等外部设备通信。
- UART 驱动: 控制 UART 接口,用于调试信息输出、串口通信等。
- USB 驱动: 控制 USB 接口,实现 USB 设备功能。
- WiFi 驱动: 控制 WiFi 模块,实现无线网络连接功能。
- 定时器驱动: 提供定时器功能,用于任务调度、延时等。
- 优势: 提高代码的可移植性,方便更换硬件平台。
板级支持包 (BSP - Board Support Package):
- 作用: 针对具体的硬件平台,提供初始化和配置功能,以及硬件相关的支持函数。
- 模块:
- 系统初始化: 初始化时钟、中断、内存等系统资源。
- 外设初始化: 初始化 GPIO、SPI、UART、USB、WiFi 等外设。
- Flash 存储器管理: 提供 Flash 存储器的读写、擦除等操作接口。
- 电源管理: 实现低功耗模式切换、电源状态监控等功能。
- 优势: 针对特定硬件平台进行优化,提高系统性能和稳定性。
操作系统层 (OS - Operating System):
- 作用: 提供任务调度、内存管理、进程间通信等操作系统核心功能,简化并发编程。
- 选择: 我们选择 FreeRTOS 作为嵌入式操作系统。FreeRTOS 是一款轻量级、开源的实时操作系统,非常适合资源受限的嵌入式系统。
- 功能:
- 任务管理: 创建、删除、挂起、恢复任务,实现多任务并发执行。
- 任务调度: 根据优先级或时间片轮转等策略,调度任务执行。
- 内存管理: 动态内存分配和释放,避免内存泄漏和碎片。
- 同步与互斥: 提供信号量、互斥锁、事件组等机制,实现任务间的同步和互斥。
- 队列: 提供消息队列,实现任务间的数据传递。
- 定时器服务: 提供软件定时器,用于周期性任务或延时操作。
- 优势: 提高系统并发性、实时性和可靠性,简化复杂系统的开发。
中间件层 (Middleware):
- 作用: 提供通用的软件组件和服务,简化应用开发,提高代码重用率。
- 模块:
- TCP/IP 协议栈: 实现 TCP/IP 协议,支持网络通信。我们选择 lwIP 协议栈,lwIP 是一款轻量级、高性能的 TCP/IP 协议栈,非常适合嵌入式系统。
- WiFi 驱动适配层: 封装 WiFi 驱动,提供更高级别的 WiFi 功能接口,例如 WiFi 连接管理、AP 扫描、数据传输等。
- USB 设备栈: 实现 USB 设备协议栈,支持 USB 设备功能。我们选择 TinyUSB 协议栈,TinyUSB 是一款小巧、模块化的 USB 设备栈,支持多种 USB 设备类。
- 文件系统: 提供文件系统功能,用于管理 Flash 存储器上的文件。我们选择 FatFS 文件系统,FatFS 是一款通用的 FAT 文件系统,兼容性好,易于使用。
- 配置管理: 管理系统配置参数,例如 WiFi SSID、密码、设备名称等。
应用层 (Application Layer):
- 作用: 实现 ESP-Dongle 的核心功能,即无线网卡模式和 U 盘模式的切换和具体功能实现。
- 模块:
- 模式管理: 负责模式切换逻辑,例如通过按键或特定命令切换无线网卡模式和 U 盘模式。
- 无线网卡模式应用: 实现无线网卡模式的具体功能,包括 WiFi 连接、网络数据转发等。
- U 盘模式应用: 实现 U 盘模式的具体功能,包括 USB 大容量存储设备枚举、文件读写操作等。
- 用户界面 (UI - User Interface): 通过 LED 指示灯等方式,向用户反馈设备状态。 (Dongle 设备 UI 相对简单)
系统架构图
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 48 49 50
| +---------------------+ | 应用层 (Application Layer) | +---------------------+ | 模式管理 | | 无线网卡模式应用 | | U 盘模式应用 | | 用户界面 (UI) | +---------------------+ | 中间件层 (Middleware) | +---------------------+ | TCP/IP 协议栈 (lwIP) | | WiFi 驱动适配层 | | USB 设备栈 (TinyUSB) | | 文件系统 (FatFS) | | 配置管理 | +---------------------+ | 操作系统层 (OS - FreeRTOS) | +---------------------+ | 任务管理 | | 任务调度 | | 内存管理 | | 同步与互斥 | | 队列 | | 定时器服务 | +---------------------+ | 板级支持包 (BSP - Board Support Package) | +---------------------+ | 系统初始化 | | 外设初始化 | | Flash 存储器管理 | | 电源管理 | +---------------------+ | 硬件抽象层 (HAL - Hardware Abstraction Layer) | +---------------------+ | GPIO 驱动 | | SPI 驱动 | | UART 驱动 | | USB 驱动 | | WiFi 驱动 | | 定时器驱动 | +---------------------+ | 硬件 | +---------------------+ | ESP 系列芯片 (ESP32/ESP8266) | | Flash 存储器 | | USB 接口 | | WiFi 模块 | | LED 指示灯 | | 按键 | +---------------------+
|
代码实现 (C 语言)
以下是 ESP-Dongle 嵌入式系统核心功能的 C 代码实现,涵盖了上述架构中的各个层次,并包含了详细的注释和错误处理。为了方便阅读和理解,代码将分模块展示,并逐步完善。
1. 硬件抽象层 (HAL)
hal_gpio.h:
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
#ifndef HAL_GPIO_H #define HAL_GPIO_H
#include <stdint.h> #include <stdbool.h>
typedef enum { GPIO_PORT_0, GPIO_PORT_1, GPIO_PORT_MAX } gpio_port_t;
typedef enum { GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_MAX } gpio_pin_t;
typedef enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_INPUT_PULLUP, GPIO_MODE_INPUT_PULLDOWN } gpio_mode_t;
typedef enum { GPIO_LEVEL_LOW, GPIO_LEVEL_HIGH } gpio_level_t;
bool hal_gpio_init(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode);
bool hal_gpio_set_level(gpio_port_t port, gpio_pin_t pin, gpio_level_t level);
bool hal_gpio_get_level(gpio_port_t port, gpio_pin_t pin, gpio_level_t *level);
#endif
|
hal_gpio.c: (以 ESP32 为例,需要根据具体的 ESP 芯片和硬件平台进行修改)
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
|
#include "hal_gpio.h" #include "driver/gpio.h"
bool hal_gpio_init(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode) { gpio_config_t io_conf; io_conf.intr_type = GPIO_INTR_DISABLE; if (mode == GPIO_MODE_OUTPUT) { io_conf.mode = GPIO_MODE_OUTPUT; } else if (mode == GPIO_MODE_INPUT || mode == GPIO_MODE_INPUT_PULLUP || mode == GPIO_MODE_INPUT_PULLDOWN) { io_conf.mode = GPIO_MODE_INPUT; } else { return false; } io_conf.pin_bit_mask = (1ULL << pin); io_conf.pull_down_en = (mode == GPIO_MODE_INPUT_PULLDOWN) ? 1 : 0; io_conf.pull_up_en = (mode == GPIO_MODE_INPUT_PULLUP) ? 1 : 0; gpio_config(&io_conf); return true; }
bool hal_gpio_set_level(gpio_port_t port, gpio_pin_t pin, gpio_level_t level) { gpio_set_level(pin, (level == GPIO_LEVEL_HIGH) ? 1 : 0); return true; }
bool hal_gpio_get_level(gpio_port_t port, gpio_pin_t pin, gpio_level_t *level) { int gpio_level = gpio_get_level(pin); if (gpio_level == 0) { *level = GPIO_LEVEL_LOW; } else { *level = GPIO_LEVEL_HIGH; } return true; }
|
hal_spi.h, hal_spi.c, hal_uart.h, hal_uart.c, hal_usb.h, hal_usb.c, hal_wifi.h, hal_wifi.c, hal_timer.h, hal_timer.c: (类似 HAL_GPIO 的实现,此处省略,但实际项目中需要根据硬件平台和使用的驱动库进行实现,例如 ESP-IDF 提供了 SPI, UART, USB, WiFi 的驱动。)
2. 板级支持包 (BSP)
bsp.h:
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 48 49 50 51 52 53 54 55 56 57 58 59 60
|
#ifndef BSP_H #define BSP_H
#include <stdint.h> #include <stdbool.h> #include "hal_gpio.h"
bool bsp_init();
bool bsp_led_init();
bool bsp_led_set_state(int led_id, bool state);
bool bsp_button_init();
bool bsp_button_get_state(int button_id, bool *pressed);
#endif
|
bsp.c: (以 ESP32 开发板为例)
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
#include "bsp.h" #include "esp_system.h" #include "esp_log.h"
#define LED_WIFI_PIN GPIO_NUM_2 #define LED_USB_PIN GPIO_NUM_4 #define BUTTON_MODE_PIN GPIO_NUM_0
static const char *TAG = "BSP";
bool bsp_init() { ESP_LOGI(TAG, "Initializing BSP..."); esp_err_t ret = esp_base_mac_addr_set((const uint8_t[]){0x00, 0x11, 0x22, 0x33, 0x44, 0x55}); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set base MAC address: %d", ret); return false; }
if (!bsp_led_init()) { ESP_LOGE(TAG, "Failed to initialize LEDs"); return false; }
if (!bsp_button_init()) { ESP_LOGE(TAG, "Failed to initialize button"); return false; }
ESP_LOGI(TAG, "BSP Initialization complete."); return true; }
bool bsp_led_init() { if (!hal_gpio_init(GPIO_PORT_0, LED_WIFI_PIN, GPIO_MODE_OUTPUT)) return false; if (!hal_gpio_init(GPIO_PORT_0, LED_USB_PIN, GPIO_MODE_OUTPUT)) return false; bsp_led_set_state(0, false); bsp_led_set_state(1, false); ESP_LOGI(TAG, "LEDs initialized."); return true; }
bool bsp_led_set_state(int led_id, bool state) { gpio_pin_t pin = (led_id == 0) ? LED_WIFI_PIN : LED_USB_PIN; gpio_level_t level = state ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW; return hal_gpio_set_level(GPIO_PORT_0, pin, level); }
bool bsp_button_init() { if (!hal_gpio_init(GPIO_PORT_0, BUTTON_MODE_PIN, GPIO_MODE_INPUT_PULLUP)) return false; ESP_LOGI(TAG, "Button initialized."); return true; }
bool bsp_button_get_state(int button_id, bool *pressed) { gpio_level_t level; if (!hal_gpio_get_level(GPIO_PORT_0, BUTTON_MODE_PIN, &level)) return false; *pressed = (level == GPIO_LEVEL_LOW); return true; }
|
3. 操作系统层 (OS - FreeRTOS)
(FreeRTOS 的配置和使用通常在 ESP-IDF 工程的 sdkconfig.h
和 main/main.c
中进行,此处不单独展示 OS 层代码,但会在后续应用层代码中体现 FreeRTOS 的使用,例如任务创建、队列使用等。)
4. 中间件层 (Middleware)
middleware_wifi.h:
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 48 49 50 51 52 53 54 55 56 57 58
|
#ifndef MIDDLEWARE_WIFI_H #define MIDDLEWARE_WIFI_H
#include <stdint.h> #include <stdbool.h>
bool middleware_wifi_init();
bool middleware_wifi_connect(const char *ssid, const char *password);
bool middleware_wifi_disconnect();
bool middleware_wifi_is_connected();
bool middleware_wifi_get_ip_address(char *ip_str, size_t ip_str_len);
#endif
|
middleware_wifi.c: (使用 ESP-IDF WiFi 驱动和 lwIP 协议栈)
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
#include "middleware_wifi.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" #include "lwip/ip4_addr.h" #include <string.h>
#define WIFI_MAX_RETRY 3
static const char *TAG = "MW_WIFI"; static int s_retry_num = 0; static EventGroupHandle_t s_wifi_event_group; const int WIFI_CONNECTED_BIT = BIT0; const int WIFI_FAIL_BIT = BIT1;
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
bool middleware_wifi_init() { s_wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id; esp_event_handler_instance_t instance_got_ip; ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "WiFi initialization finished."); return true; }
bool middleware_wifi_connect(const char *ssid, const char *password) { wifi_config_t wifi_config = { .sta = { .ssid = "", .password = "", .threshold.authmode = WIFI_AUTH_WPA2_PSK, .pmf_cfg = { .capable = true, .required = false }, }, }; strncpy((char *)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid) - 1); strncpy((char *)wifi_config.sta.password, password, sizeof(wifi_config.sta.password) - 1);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_connect());
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) { ESP_LOGI(TAG, "Connected to AP SSID:%s password:%s", ssid, password); s_retry_num = 0; return true; } else if (bits & WIFI_FAIL_BIT) { ESP_LOGE(TAG, "Failed to connect to SSID:%s, password:%s", ssid, password); } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } return false; }
bool middleware_wifi_disconnect() { ESP_ERROR_CHECK(esp_wifi_disconnect()); ESP_ERROR_CHECK(esp_wifi_stop()); ESP_LOGI(TAG, "WiFi disconnected."); return true; }
bool middleware_wifi_is_connected() { return (xEventGroupGetBits(s_wifi_event_group) & WIFI_CONNECTED_BIT) != 0; }
bool middleware_wifi_get_ip_address(char *ip_str, size_t ip_str_len) { if (!middleware_wifi_is_connected()) { return false; } esp_netif_ip_info_t ip_info; esp_netif_t *sta_netif = esp_netif_get_example_netif(); if (esp_netif_get_ip_info(sta_netif, &ip_info) != ESP_OK) { ESP_LOGE(TAG, "Failed to get IP address"); return false; } ip4addr_ntoa_r(&ip_info.ip, ip_str, ip_str_len); ESP_LOGI(TAG, "Got IP Address: %s", ip_str); return true; }
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { if (s_retry_num < WIFI_MAX_RETRY) { esp_wifi_connect(); s_retry_num++; ESP_LOGI(TAG, "retry to connect to the AP"); } else { xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); } ESP_LOGI(TAG,"connect to the AP fail"); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } }
|
middleware_usb.h, middleware_usb.c, middleware_filesystem.h, middleware_filesystem.c, middleware_config.h, middleware_config.c: (类似 middleware_wifi 的实现,需要根据使用的 USB 设备栈 (TinyUSB), 文件系统 (FatFS) 和配置管理方案进行实现, 此处省略,但实际项目中需要完成这些中间件模块的开发。)
5. 应用层 (Application Layer)
app_mode_manager.h:
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
|
#ifndef APP_MODE_MANAGER_H #define APP_MODE_MANAGER_H
#include <stdint.h> #include <stdbool.h>
typedef enum { MODE_WIFI_CARD, MODE_USB_DISK, MODE_MAX } system_mode_t;
bool app_mode_manager_init();
system_mode_t app_mode_manager_get_mode();
bool app_mode_manager_set_mode(system_mode_t mode);
#endif
|
app_mode_manager.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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
#include "app_mode_manager.h" #include "bsp.h" #include "middleware_wifi.h" #include "middleware_usb.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h"
static const char *TAG = "APP_MODE_MGR"; static system_mode_t current_mode = MODE_WIFI_CARD;
bool app_mode_manager_init() { ESP_LOGI(TAG, "Initializing Mode Manager...");
if (xTaskCreate(mode_switch_task, "ModeSwitchTask", 2048, NULL, 5, NULL) != pdPASS) { ESP_LOGE(TAG, "Failed to create mode switch task"); return false; }
if (!app_mode_manager_set_mode(MODE_WIFI_CARD)) { ESP_LOGE(TAG, "Failed to set initial mode to WiFi Card"); return false; }
ESP_LOGI(TAG, "Mode Manager Initialization complete."); return true; }
system_mode_t app_mode_manager_get_mode() { return current_mode; }
bool app_mode_manager_set_mode(system_mode_t mode) { if (mode >= MODE_MAX) { ESP_LOGE(TAG, "Invalid mode: %d", mode); return false; }
ESP_LOGI(TAG, "Switching to mode: %d", mode); current_mode = mode;
switch (mode) { case MODE_WIFI_CARD: bsp_led_set_state(0, true); bsp_led_set_state(1, false); middleware_usb_deinit(); middleware_wifi_init(); ESP_LOGI(TAG, "Mode switched to WiFi Card."); break; case MODE_USB_DISK: bsp_led_set_state(0, false); bsp_led_set_state(1, true); middleware_wifi_deinit(); middleware_usb_init(); ESP_LOGI(TAG, "Mode switched to USB Disk."); break; default: ESP_LOGE(TAG, "Unknown mode: %d", mode); return false; }
return true; }
static void mode_switch_task(void *pvParameters) { bool button_pressed = false; system_mode_t next_mode;
while (1) { if (bsp_button_get_state(0, &button_pressed)) { if (button_pressed) { vTaskDelay(pdMS_TO_TICKS(50));
if (bsp_button_get_state(0, &button_pressed) && button_pressed) { next_mode = (current_mode == MODE_WIFI_CARD) ? MODE_USB_DISK : MODE_WIFI_CARD; app_mode_manager_set_mode(next_mode); } } } vTaskDelay(pdMS_TO_TICKS(100)); } }
|
app_wifi_card.h, app_wifi_card.c, app_usb_disk.h, app_usb_disk.c, app_ui.h, app_ui.c, main.c: (类似 app_mode_manager 的应用层模块实现,需要分别实现无线网卡模式和 U 盘模式的具体功能,以及用户界面逻辑。main.c
文件作为程序入口,负责系统初始化和任务创建。此处省略,但实际项目中需要完成这些应用层模块的开发,并确保代码量达到要求。)
6. 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
|
#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "bsp.h" #include "app_mode_manager.h" #include "esp_log.h"
static const char *TAG = "MAIN";
void app_main(void) { ESP_LOGI(TAG, "ESP-Dongle Application Start...");
if (!bsp_init()) { ESP_LOGE(TAG, "BSP initialization failed!"); while (1); }
if (!app_mode_manager_init()) { ESP_LOGE(TAG, "Mode Manager initialization failed!"); while (1); }
ESP_LOGI(TAG, "System initialization complete.");
while (1) { vTaskDelay(pdMS_TO_TICKS(1000)); } }
|
代码扩展和完善方向
上述代码只是一个基本的框架和核心模块的示例,需要进一步扩展和完善各个模块的功能,并添加更多的细节和注释:
- HAL 层: 完善 SPI, UART, USB, WiFi, Timer 等 HAL 驱动的实现,包括 DMA 支持、中断处理、错误处理等。
- BSP 层: 添加更完善的 Flash 存储器管理 (例如分区管理、 wear leveling 等),电源管理 (低功耗模式切换、电压监控等),以及更细致的硬件初始化和配置。
- 中间件层:
- TCP/IP 协议栈 (lwIP): 配置和优化 lwIP 协议栈,实现更完善的网络功能,例如 DHCP 客户端、 DNS 客户端、 TCP/UDP 服务器/客户端 等。
- WiFi 驱动适配层: 实现更高级的 WiFi 功能,例如 AP 扫描结果解析、 WiFi 参数配置界面 (如果需要)、 WiFi 安全加密等。
- USB 设备栈 (TinyUSB): 实现 USB CDC-ECM (以太网卡模式) 和 USB MSC (大容量存储设备模式) 的功能,包括 USB 描述符配置、端点处理、数据传输逻辑、错误处理等。
- 文件系统 (FatFS): 实现完整的文件系统操作接口,例如文件/目录创建、删除、读写、查找、格式化等,并考虑文件系统的性能优化和错误处理。
- 配置管理: 实现更灵活的配置管理机制,例如使用配置文件存储配置参数,提供配置参数的读取、修改、保存等功能。
- 应用层:
- 无线网卡模式应用: 实现 USB CDC-ECM 功能,将 ESP-Dongle 模拟成 USB 网卡,实现网络数据转发,并进行性能优化。
- U 盘模式应用: 实现 USB MSC 功能,将 Flash 存储器映射为 USB 磁盘,实现文件读写操作,并考虑数据安全和文件系统稳定性。
- 用户界面 (UI): 完善 LED 指示灯的状态显示,添加更丰富的用户交互方式 (例如串口命令、 Web 界面 等,如果硬件条件允许)。
- 错误处理和日志: 在各个模块中添加完善的错误处理机制,并使用日志系统记录系统运行状态和错误信息,方便调试和维护。
- 代码注释: 为所有代码添加详细的注释,解释代码的功能、实现原理、接口参数、返回值等,提高代码的可读性和可维护性。
- 单元测试: 为各个模块编写单元测试用例,验证模块功能的正确性和稳定性 (虽然在示例代码中没有体现,但实际项目中单元测试非常重要)。
- 代码风格规范: 统一代码风格,例如缩进、命名规范、注释风格等,提高代码的整洁性和可读性.
通过以上扩展和完善,并构建一个功能完善、可靠高效、可扩展易维护的 ESP-Dongle 嵌入式软件系统。
总结
本文详细介绍了 ESP-Dongle 双重功能嵌入式系统的软件设计架构和 C 代码实现。采用分层架构,将系统划分为硬件抽象层 (HAL)、板级支持包 (BSP)、操作系统层 (OS - FreeRTOS)、中间件层 (Middleware) 和应用层 (Application Layer),实现了代码的模块化和可维护性。代码示例涵盖了 GPIO HAL 驱动、 BSP 初始化、 WiFi 中间件、模式管理应用层等核心模块。
要构建一个完整的、高质量的嵌入式系统,还需要在上述代码基础上进行大量的扩展和完善,包括各个模块的详细实现、错误处理、性能优化、单元测试、文档编写等工作。通过实践验证和不断迭代,最终才能开发出一个可靠、高效、可扩展的 ESP-Dongle 产品。