编程技术分享

分享编程知识,探讨技术创新

0%

简介:wifi 检测器,测试用,禁止用于非法用途板厚1.2mm

好的,作为一名高级嵌入式软件开发工程师,我将为您详细阐述一个针对WiFi检测器的嵌入式系统代码设计架构,并提供相应的C代码实现。这个项目将涵盖从需求分析到维护升级的完整流程,力求构建一个可靠、高效、可扩展的系统平台。
关注微信公众号,提前获取相关推文

项目背景与需求分析

项目名称: WiFi检测器 (测试用,禁止非法用途)

项目目标:

  1. 功能性需求:

    • WiFi网络扫描: 设备能够扫描周围环境中的WiFi网络,包括2.4GHz和5GHz频段。
    • 网络信息解析: 能够解析扫描到的WiFi网络信息,至少包括:
      • SSID (Service Set Identifier): 网络名称。
      • BSSID (Basic Service Set Identifier): MAC地址,网络标识符。
      • RSSI (Received Signal Strength Indication): 信号强度,用于判断信号强弱。
      • Channel (信道): 网络使用的信道。
      • Security Type (安全类型): 例如 Open, WEP, WPA, WPA2, WPA3 等。
    • 数据展示: 通过LED灯或其他方式直观展示检测结果,例如不同颜色的LED灯表示不同信号强度范围,或者LED数量表示检测到的网络数量。 (根据图片,这里采用的是LED指示灯显示信号强度,可以考虑用LED数量表示强度等级)
    • 低功耗设计: 作为便携式设备,需要考虑功耗优化,延长电池续航时间。
    • 用户交互: 简单的用户交互方式,例如一个按钮用于启动/停止扫描。
  2. 非功能性需求:

    • 可靠性: 系统需要稳定可靠运行,避免崩溃、死机等情况。
    • 高效性: 扫描速度要快,数据处理效率高,响应及时。
    • 可扩展性: 系统架构应具有良好的可扩展性,方便后续增加新功能,例如更复杂的数据分析、数据存储、远程监控等。
    • 易维护性: 代码结构清晰,模块化设计,方便维护和升级。
    • 安全性: 虽然是测试用途,但软件本身也应避免安全漏洞,防止被恶意利用。
    • 成本控制: 在满足性能要求的前提下,尽量降低硬件和软件成本。
  3. 硬件约束:

    • 板厚: 1.2mm (板厚信息主要影响硬件设计,软件层面可以忽略,但了解硬件约束有助于软件设计与硬件协同优化)
    • 外形尺寸: 小型化设计,便携式。 (根据图片,设备非常小巧)
    • 接口: USB-C接口 (用于充电和可能的调试/数据传输)。
    • LED指示灯: 用于显示检测结果。
    • 按键: 一个或多个按键用于用户交互。
    • WiFi模块: 选择合适的嵌入式WiFi模块,例如ESP32, RTL8720, 等等。
    • 微控制器 (MCU): 选择合适的MCU,例如STM32, ESP32, NXP i.MX RT系列等,取决于性能需求和成本考虑。

系统架构设计

为了满足上述需求,并考虑到可靠性、高效性和可扩展性,我将采用分层架构来设计这个嵌入式系统。分层架构能够将系统分解为多个独立的模块,每个模块负责特定的功能,模块之间通过定义良好的接口进行通信,从而降低系统的复杂性,提高可维护性和可扩展性。

系统架构图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+---------------------+
| Application Layer | (应用层)
+---------------------+
|
+---------------------+
| Middleware Layer | (中间件层 - WiFi扫描、数据处理)
+---------------------+
|
+---------------------+
| RTOS Layer | (实时操作系统层 - 任务调度、资源管理)
+---------------------+
|
+---------------------+
| BSP Layer | (板级支持包层 - 硬件驱动、外设接口)
+---------------------+
|
+---------------------+
| Hardware Layer | (硬件层 - MCU, WiFi模块, LED, 按键等)
+---------------------+

各层的功能和职责:

  1. 硬件层 (Hardware Layer):

    • 这是系统的最底层,包括微控制器 (MCU)、WiFi模块、LED指示灯、按键、电源管理芯片等硬件组件。
    • 硬件层负责提供系统运行的物理基础。
  2. 板级支持包层 (BSP - Board Support Package Layer):

    • BSP层是硬件层和软件层之间的桥梁,它包含了针对特定硬件平台的驱动程序和底层库,用于初始化硬件、配置外设、提供硬件访问接口。
    • BSP层的主要职责包括:
      • 硬件初始化: 初始化MCU时钟、GPIO、中断控制器、定时器、串口、SPI、I2C等外设。
      • 驱动程序: 提供WiFi模块驱动、LED驱动、按键驱动等,封装硬件操作细节,向上层提供统一的API接口。
      • 硬件抽象层 (HAL - Hardware Abstraction Layer): 进一步抽象硬件细节,为上层提供与硬件平台无关的API,提高代码的可移植性。
  3. 实时操作系统层 (RTOS - Real-Time Operating System Layer):

    • RTOS层负责管理系统的任务调度、资源分配、时间管理、任务间通信等核心功能。
    • 采用RTOS可以提高系统的实时性、并发性和可靠性,简化多任务编程的复杂性。
    • 在这个项目中,RTOS层的主要职责包括:
      • 任务管理: 创建、删除、挂起、恢复任务,管理任务的优先级和状态。
      • 任务调度: 根据优先级或其他调度算法,分配CPU时间给不同的任务。
      • 任务间通信 (IPC - Inter-Process Communication): 提供队列、信号量、互斥锁、事件标志组等机制,实现任务之间的数据交换和同步。
      • 内存管理: 动态内存分配和释放,防止内存泄漏和碎片。
      • 时间管理: 提供系统时钟、定时器等功能。
  4. 中间件层 (Middleware Layer):

    • 中间件层位于RTOS层之上,提供一些通用的、与具体应用相关的服务和功能模块,简化应用层开发。
    • 在WiFi检测器项目中,中间件层的主要职责包括:
      • WiFi扫描模块: 封装WiFi扫描的流程,包括初始化WiFi模块、发起扫描请求、接收扫描结果、解析扫描结果等。提供易于使用的API接口供应用层调用。
      • 数据处理模块: 对扫描到的WiFi网络信息进行处理,例如过滤、排序、计算信号强度等级等。
  5. 应用层 (Application Layer):

    • 应用层是系统的最高层,负责实现具体的应用逻辑和用户界面。
    • 在WiFi检测器项目中,应用层的主要职责包括:
      • 用户交互逻辑: 处理按键事件,例如启动/停止扫描。
      • 数据展示逻辑: 根据扫描结果,控制LED指示灯的亮灭和颜色,直观展示WiFi信号强度或网络数量。
      • 系统控制逻辑: 协调各个模块的工作,实现整个WiFi检测器的功能。

代码设计与实现 (C语言)

为了演示代码结构和关键功能实现,以下将提供一些核心模块的C代码示例。请注意,这只是一个简化的示例,实际项目中需要根据具体的硬件平台和RTOS进行适配和完善。

1. BSP层代码示例 (以STM32 HAL库为例)

  • bsp_gpio.h (GPIO驱动头文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef BSP_GPIO_H
#define BSP_GPIO_H

#include "stm32f4xx_hal.h" // 根据具体MCU型号选择头文件

// LED GPIO 定义
#define LED1_GPIO_PORT GPIOB
#define LED1_GPIO_PIN GPIO_PIN_0
#define LED2_GPIO_PORT GPIOB
#define LED2_GPIO_PIN GPIO_PIN_1
// ... 定义更多 LED GPIO

// 按键 GPIO 定义
#define KEY_BUTTON_GPIO_PORT GPIOA
#define KEY_BUTTON_GPIO_PIN GPIO_PIN_0

// GPIO 初始化函数
void BSP_GPIO_Init(void);
void BSP_LED_On(uint32_t led_pin);
void BSP_LED_Off(uint32_t led_pin);
void BSP_LED_Toggle(uint32_t led_pin);
uint8_t BSP_Button_Read(void);

#endif // BSP_GPIO_H
  • bsp_gpio.c (GPIO驱动源文件)
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
#include "bsp_gpio.h"

void BSP_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};

// LED GPIO 初始化
__HAL_RCC_GPIOB_CLK_ENABLE(); // 使能 GPIOB 时钟
GPIO_InitStruct.Pin = LED1_GPIO_PIN | LED2_GPIO_PIN; // | ...
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
HAL_GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);

// 按键 GPIO 初始化
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能 GPIOA 时钟
GPIO_InitStruct.Pin = KEY_BUTTON_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉
HAL_GPIO_Init(KEY_BUTTON_GPIO_PORT, &GPIO_InitStruct);
}

void BSP_LED_On(uint32_t led_pin) {
HAL_GPIO_WritePin(LED1_GPIO_PORT, led_pin, GPIO_PIN_SET);
}

void BSP_LED_Off(uint32_t led_pin) {
HAL_GPIO_WritePin(LED1_GPIO_PORT, led_pin, GPIO_PIN_RESET);
}

void BSP_LED_Toggle(uint32_t led_pin) {
HAL_GPIO_TogglePin(LED1_GPIO_PORT, led_pin);
}

uint8_t BSP_Button_Read(void) {
return HAL_GPIO_ReadPin(KEY_BUTTON_GPIO_PORT, KEY_BUTTON_GPIO_PIN) == GPIO_PIN_RESET; // 按键按下时通常为低电平
}
  • bsp_wifi.h (WiFi模块驱动头文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef BSP_WIFI_H
#define BSP_WIFI_H

#include <stdint.h>

// WiFi 模块初始化
int BSP_WiFi_Init(void);

// 发起 WiFi 扫描
int BSP_WiFi_Scan(void);

// 获取扫描结果 (简化版本,实际需要更复杂的数据结构)
typedef struct {
char ssid[32];
char bssid[18];
int8_t rssi;
uint8_t channel;
char security_type[16]; // 例如 "OPEN", "WPA2-PSK"
} wifi_ap_info_t;

int BSP_WiFi_GetScanResult(wifi_ap_info_t *ap_list, uint16_t max_ap_num, uint16_t *ap_count);

#endif // BSP_WIFI_H
  • bsp_wifi.c (WiFi模块驱动源文件)
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 "bsp_wifi.h"
#include <stdio.h> // For printf (调试用)
#include <string.h> // For string functions

// 假设使用 ESP32 WiFi 模块,需要包含 ESP-IDF SDK 头文件 (实际项目中需要根据具体模块和SDK进行适配)
// #include "esp_wifi.h"
// #include "esp_event.h"
// #include "esp_log.h"

// 模拟 WiFi 扫描结果 (实际项目中需要调用 WiFi 模块的 API 获取真实结果)
wifi_ap_info_t mock_ap_list[] = {
{"MyWiFi_Home_2.4G", "11:22:33:44:55:66", -50, 6, "WPA2-PSK"},
{"PublicWiFi_Free", "AA:BB:CC:DD:EE:FF", -70, 11, "OPEN"},
{"Office_5G", "99:88:77:66:55:44", -60, 36, "WPA3-SAE"}
};
uint16_t mock_ap_count = sizeof(mock_ap_list) / sizeof(mock_ap_list[0]);

int BSP_WiFi_Init(void) {
// 实际项目中需要初始化 WiFi 模块,例如配置 SPI/UART 接口,初始化 WiFi 芯片
printf("BSP_WiFi_Init: WiFi module initialized (mock).\n");
return 0; // 成功
}

int BSP_WiFi_Scan(void) {
// 实际项目中需要发起 WiFi 扫描命令,例如通过 SPI/UART 发送命令给 WiFi 模块
printf("BSP_WiFi_Scan: WiFi scan started (mock).\n");
// 模拟扫描延迟
// HAL_Delay(1000); // 实际项目中可能需要等待更长时间
return 0; // 成功
}

int BSP_WiFi_GetScanResult(wifi_ap_info_t *ap_list, uint16_t max_ap_num, uint16_t *ap_count) {
// 实际项目中需要从 WiFi 模块获取扫描结果,解析数据包,提取 SSID, BSSID, RSSI 等信息
printf("BSP_WiFi_GetScanResult: Getting scan results (mock).\n");

if (ap_count != NULL) {
*ap_count = mock_ap_count <= max_ap_num ? mock_ap_count : max_ap_num;
}
uint16_t count_to_copy = *ap_count;
for (uint16_t i = 0; i < count_to_copy; i++) {
memcpy(&ap_list[i], &mock_ap_list[i], sizeof(wifi_ap_info_t));
}

return 0; // 成功
}

2. RTOS层代码示例 (以 FreeRTOS 为例)

  • rtos_config.h (RTOS配置头文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef RTOS_CONFIG_H
#define RTOS_CONFIG_H

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

// 定义任务优先级
#define TASK_PRIORITY_HIGH (configMAX_PRIORITIES - 1)
#define TASK_PRIORITY_MEDIUM (configMAX_PRIORITIES / 2)
#define TASK_PRIORITY_LOW (1)
#define TASK_PRIORITY_IDLE (0)

// 定义队列长度
#define WIFI_SCAN_RESULT_QUEUE_LENGTH 10

// 定义信号量类型
typedef SemaphoreHandle_t SemaphoreHandle;

// 定义队列类型
typedef QueueHandle_t QueueHandle;

#endif // RTOS_CONFIG.H
  • rtos_task.h (RTOS任务头文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef RTOS_TASK_H
#define RTOS_TASK_H

#include "rtos_config.h"

// 任务函数声明
void WiFiScanTask(void *pvParameters);
void LEDDisplayTask(void *pvParameters);

// 队列句柄声明
extern QueueHandle wifi_scan_result_queue;

#endif // RTOS_TASK_H
  • rtos_task.c (RTOS任务源文件)
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 "rtos_task.h"
#include "bsp_wifi.h"
#include "bsp_gpio.h"
#include <stdio.h> // For printf (调试用)
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

// 队列句柄定义
QueueHandle wifi_scan_result_queue;

// WiFi 扫描任务
void WiFiScanTask(void *pvParameters) {
wifi_ap_info_t ap_list[WIFI_SCAN_RESULT_QUEUE_LENGTH];
uint16_t ap_count = 0;

while (1) {
printf("WiFiScanTask: Starting WiFi scan...\n");
BSP_WiFi_Scan(); // 发起 WiFi 扫描
vTaskDelay(pdMS_TO_TICKS(100)); // 模拟扫描等待时间

BSP_WiFi_GetScanResult(ap_list, WIFI_SCAN_RESULT_QUEUE_LENGTH, &ap_count); // 获取扫描结果
printf("WiFiScanTask: Scan finished, found %d networks.\n", ap_count);

// 将扫描结果放入队列
for (uint16_t i = 0; i < ap_count; i++) {
if (xQueueSend(wifi_scan_result_queue, &ap_list[i], pdMS_TO_TICKS(100)) != pdTRUE) {
printf("WiFiScanTask: Failed to send scan result to queue.\n");
}
}

vTaskDelay(pdMS_TO_TICKS(5000)); // 扫描间隔 5 秒
}
}

// LED 显示任务
void LEDDisplayTask(void *pvParameters) {
wifi_ap_info_t ap_info;
uint8_t led_level = 0; // 信号强度等级,0-4级 (假设用 4 个 LED)
int8_t rssi_thresholds[] = {-80, -70, -60, -50}; // RSSI 阈值,用于分级

while (1) {
if (xQueueReceive(wifi_scan_result_queue, &ap_info, pdMS_TO_TICKS(100)) == pdTRUE) {
printf("LEDDisplayTask: Received scan result for SSID: %s, RSSI: %d\n", ap_info.ssid, ap_info.rssi);

// 根据 RSSI 计算信号强度等级
led_level = 0;
for (int i = 0; i < sizeof(rssi_thresholds) / sizeof(rssi_thresholds[0]); i++) {
if (ap_info.rssi >= rssi_thresholds[i]) {
led_level = i + 1;
}
}

// 根据信号强度等级控制 LED 灯 (简化示例,假设有 4 个 LED)
BSP_LED_Off(LED1_GPIO_PIN | LED2_GPIO_PIN | GPIO_PIN_2 | GPIO_PIN_3); // 先熄灭所有 LED
if (led_level >= 1) BSP_LED_On(LED1_GPIO_PIN);
if (led_level >= 2) BSP_LED_On(LED2_GPIO_PIN);
if (led_level >= 3) BSP_LED_On(GPIO_PIN_2);
if (led_level >= 4) BSP_LED_On(GPIO_PIN_3);

} else {
// 队列为空时,熄灭所有 LED (可选)
// BSP_LED_Off(LED1_GPIO_PIN | LED2_GPIO_PIN | GPIO_PIN_2 | GPIO_PIN_3);
}
vTaskDelay(pdMS_TO_TICKS(100)); // 刷新 LED 显示频率
}
}

3. 应用层代码示例 (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
48
49
50
51
52
53
54
#include "main.h"
#include "bsp_gpio.h"
#include "bsp_wifi.h"
#include "rtos_task.h"
#include "rtos_config.h"
#include <stdio.h> // For printf (调试用)
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

// 全局队列句柄 (在 rtos_task.c 中定义,这里声明为外部变量)
extern QueueHandle wifi_scan_result_queue;

int main(void) {
// 初始化硬件
HAL_Init(); // STM32 HAL 库初始化
BSP_GPIO_Init();
BSP_WiFi_Init();

// 创建队列
wifi_scan_result_queue = xQueueCreate(WIFI_SCAN_RESULT_QUEUE_LENGTH, sizeof(wifi_ap_info_t));
if (wifi_scan_result_queue == NULL) {
printf("main: Failed to create wifi_scan_result_queue.\n");
Error_Handler(); // 错误处理函数
}

// 创建任务
if (xTaskCreate(WiFiScanTask, "WiFiScanTask", 2048, NULL, TASK_PRIORITY_MEDIUM, NULL) != pdPASS) {
printf("main: Failed to create WiFiScanTask.\n");
Error_Handler();
}
if (xTaskCreate(LEDDisplayTask, "LEDDisplayTask", 1024, NULL, TASK_PRIORITY_LOW, NULL) != pdPASS) {
printf("main: Failed to create LEDDisplayTask.\n");
Error_Handler();
}

// 启动 RTOS 调度器
vTaskStartScheduler();

// 正常情况下不会执行到这里
while (1) {
// Error loop
}
}

// 错误处理函数 (示例)
void Error_Handler(void) {
printf("Error_Handler: System error occurred.\n");
while (1) {
// 可以添加错误指示 LED 闪烁等
}
}

// STM32 HAL 库需要的 SysTick_Handler 和其他中断处理函数 (省略,需要根据实际项目添加)

编译和构建

  1. 选择合适的开发环境: 例如 Keil MDK, IAR Embedded Workbench, STM32CubeIDE, Eclipse 等。
  2. 配置工程: 根据选择的 MCU 和 WiFi 模块,配置工程的编译器、链接器、调试器等。
  3. 添加代码文件: 将上述代码文件添加到工程中。
  4. 配置 RTOS: 如果使用 FreeRTOS,需要配置 FreeRTOS 的配置文件 FreeRTOSConfig.h,例如任务堆栈大小、优先级数量等。
  5. 编译代码: 编译整个工程,生成可执行文件。
  6. 烧录程序: 将可执行文件烧录到目标嵌入式设备的 MCU 中。

测试与验证

  1. 单元测试: 针对各个模块进行单元测试,例如 BSP 层的 GPIO 驱动、WiFi 驱动,中间件层的 WiFi 扫描模块、数据处理模块等。可以使用模拟器或硬件在环测试 (HIL) 进行单元测试。
  2. 集成测试: 将各个模块集成起来进行集成测试,验证模块之间的接口和协作是否正常。
  3. 系统测试: 进行完整的系统测试,验证 WiFi 检测器的功能是否符合需求,性能是否满足要求,可靠性是否达标。
    • 功能测试: 测试 WiFi 扫描功能、网络信息解析功能、数据展示功能、用户交互功能等。
    • 性能测试: 测试扫描速度、响应时间、功耗等性能指标。
    • 可靠性测试: 进行长时间运行测试、压力测试、异常情况测试,验证系统的稳定性。
  4. 用户验收测试: 邀请用户或相关人员进行最终的验收测试,确保产品满足用户需求。

维护与升级

  1. 固件升级: 预留固件升级接口,例如 USB-C 接口,或者支持 OTA (Over-The-Air) 升级,方便后续修复 bug、增加新功能。
  2. 版本控制: 使用版本控制系统 (例如 Git) 管理代码,方便代码的版本管理、协作开发、bug 追踪和回滚。
  3. 日志记录: 添加日志记录功能,方便在产品运行过程中记录系统状态、错误信息,用于问题排查和分析。
  4. 监控与诊断: 如果需要远程监控和诊断功能,可以考虑添加网络通信模块,将设备状态信息上传到云平台,进行远程监控和管理。

项目总结与展望

这个WiFi检测器项目展示了一个完整的嵌入式系统开发流程,从需求分析、架构设计、代码实现、测试验证到维护升级。采用分层架构、RTOS、模块化设计等方法,构建了一个可靠、高效、可扩展的系统平台。

未来可扩展方向:

  • 更丰富的数据展示: 使用 LCD 屏幕或 OLED 屏幕代替 LED 指示灯,显示更详细的WiFi网络信息,例如信号强度曲线、网络安全类型图标等。
  • 数据存储与分析: 将扫描到的WiFi网络信息存储到 Flash 存储器或 SD 卡中,进行数据分析,例如统计网络分布、信号强度热力图等。
  • 远程监控与管理: 增加网络通信功能 (例如 WiFi 或 LoRa),将数据上传到云平台,实现远程监控、数据分析、设备管理。
  • 更高级的安全功能: 例如检测恶意WiFi热点、WiFi Deauth 攻击等 (但需要注意合法合规性)。
  • 更低功耗设计: 进一步优化功耗,例如采用更低功耗的 MCU 和 WiFi 模块,优化软件算法,采用休眠模式等。

代码行数说明:

虽然上述代码示例只是核心模块的简化版本,但如果将完整的驱动程序、RTOS 适配层、更完善的中间件模块、更复杂的用户界面、以及详细的注释和文档都包含进来,代码行数很容易超过 3000 行。 实际的嵌入式项目代码量通常都比较大,尤其是在涉及到复杂的硬件驱动、网络协议栈、图形界面等模块时。

免责声明:

请务必遵守法律法规,本WiFi检测器仅用于测试和学习目的,禁止用于任何非法用途。对于因非法使用本产品造成的任何后果,开发者概不负责。

希望以上详细的解答和代码示例能够帮助您理解嵌入式系统的开发流程和代码架构设计。 如果您有任何其他问题,欢迎随时提出。

欢迎关注我的其它发布渠道