编程技术分享

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

0%

简介:一块板子,集成了示波器,信号发生器,USB存储,方便使用。都是开源方案,我不过是站在巨人的肩膀上。

好的,作为一名高级嵌入式软件开发工程师,我很乐意为您详细阐述针对您展示的集成示波器、信号发生器和USB存储的嵌入式产品的代码设计架构,并提供相应的C代码示例。
关注微信公众号,提前获取相关推文

系统架构设计

针对这款集成了示波器、信号发生器和USB存储功能的多功能嵌入式设备,我推荐采用分层架构的设计模式。这种架构能够有效地组织代码,提高模块化程度,增强系统的可维护性和可扩展性。以下是具体的分层架构设计:

1. 硬件抽象层 (HAL - Hardware Abstraction Layer)

  • 目的: HAL层是系统架构的最底层,直接与硬件交互。它将具体的硬件操作抽象成统一的软件接口,使得上层软件无需关心底层硬件的具体实现细节,从而实现硬件的独立性和可移植性。
  • 模块:
    • GPIO 驱动: 控制通用输入/输出端口,例如按键、LED、旋钮编码器等。
    • ADC 驱动: 模数转换器驱动,用于采集示波器的模拟信号输入。
    • DAC 驱动: 数模转换器驱动,用于输出信号发生器的模拟信号。
    • SPI/I2C 驱动: 串行外设接口驱动,用于与LCD显示屏、存储器或其他外设通信。
    • 定时器驱动: 用于生成精确的定时,例如示波器采样定时、信号发生器波形生成定时。
    • USB 驱动: USB控制器驱动,实现USB存储功能。
    • 中断控制器驱动: 管理和处理各种硬件中断。
    • 时钟系统驱动: 配置和管理系统时钟。
  • 实现要点:
    • 为每个硬件模块定义清晰的接口函数,例如 GPIO_Init(), ADC_Read(), DAC_Write(), SPI_Transmit(), Timer_Start(), USB_ReceiveData() 等。
    • HAL层代码应尽可能简洁,专注于硬件操作,避免包含业务逻辑。
    • 采用条件编译 (#ifdef, #endif) 或函数指针等技术,方便适配不同的硬件平台。

2. 板级支持包 (BSP - Board Support Package)

  • 目的: BSP层构建在HAL层之上,它提供了针对特定硬件平台的初始化和配置功能。BSP层连接了硬件抽象层和操作系统/应用层,为上层软件提供统一的硬件平台接口。
  • 模块:
    • 系统初始化: 完成系统时钟配置、中断向量表设置、堆栈初始化等系统级初始化工作。
    • 外设初始化: 调用HAL层驱动,初始化系统中使用的所有硬件外设 (GPIO, ADC, DAC, SPI, I2C, Timer, USB)。
    • 内存管理: 如果使用RTOS,BSP层可能需要集成内存管理模块,例如动态内存分配和释放。
    • 时钟管理: 提供系统时钟频率查询接口,方便上层软件进行时间相关的计算。
  • 实现要点:
    • BSP层代码与具体的硬件平台紧密相关,需要根据实际使用的微控制器和开发板进行定制。
    • BSP层应提供易于使用的API,方便上层软件进行硬件资源的配置和管理。
    • 可以包含一些针对特定板级的硬件测试和诊断代码。

3. 操作系统层 (OS Layer) 或 裸机系统 (Bare-metal System)

  • 目的: 操作系统层负责系统资源的管理和调度,例如任务调度、内存管理、进程间通信等。如果系统资源需求不高,或者对实时性要求极高,也可以选择裸机系统,直接在硬件上运行应用程序。
  • 选择:
    • 实时操作系统 (RTOS): 例如 FreeRTOS, RT-Thread, uC/OS 等。RTOS能够提供多任务处理能力,提高系统的并发性和实时性,更适合于功能复杂的嵌入式系统。
    • 裸机系统 (Bare-metal): 不使用操作系统,直接在硬件上运行应用程序。裸机系统代码结构相对简单,资源占用少,启动速度快,但开发和维护复杂性较高,不适合复杂应用。
  • RTOS 的优势 (如果选择 RTOS):
    • 多任务处理: 可以将示波器、信号发生器、USB存储等功能划分为独立的任务,并发执行,提高系统效率。
    • 任务调度: RTOS负责任务的调度和优先级管理,保证实时性要求高的任务能够及时响应。
    • 资源管理: RTOS提供内存管理、任务同步和通信机制,方便管理系统资源。
    • 模块化: RTOS本身就是一个模块化的系统,方便代码的组织和维护。
  • 实现要点 (如果选择 RTOS):
    • 根据项目需求选择合适的RTOS内核。
    • 配置RTOS内核,例如任务栈大小、优先级、时间片等。
    • 创建和管理任务,例如示波器任务、信号发生器任务、USB存储任务、UI任务等。
    • 使用RTOS提供的同步和通信机制 (信号量、互斥锁、消息队列等) 实现任务间的协作。

4. 服务层 (Service Layer)

  • 目的: 服务层构建在操作系统层之上,封装了各种业务逻辑功能模块,为应用层提供高层次的服务接口。
  • 模块:
    • 示波器服务: 实现示波器的核心功能,包括数据采集、触发、时基控制、电压刻度控制、波形显示等。
    • 信号发生器服务: 实现信号发生器的核心功能,包括波形生成、频率控制、幅度控制、波形输出等。
    • USB存储服务: 实现USB存储功能,包括USB设备枚举、文件系统访问、数据读写等。
    • 显示服务: 封装LCD显示屏的控制逻辑,提供图形界面绘制、文本显示等功能。
    • 输入服务: 处理用户输入,例如按键、旋钮编码器等,并将输入事件传递给应用层。
  • 实现要点:
    • 服务层模块应高内聚、低耦合,每个模块负责特定的业务功能。
    • 服务层模块对外提供清晰的API,方便应用层调用。
    • 服务层模块内部可以使用状态机、事件驱动等设计模式,提高代码的可读性和可维护性。
    • 考虑错误处理和异常情况,保证服务的健壮性。

5. 应用层 (Application Layer)

  • 目的: 应用层是系统架构的最上层,直接面向用户。它负责实现用户界面、应用程序逻辑,并调用服务层提供的功能。
  • 模块:
    • 用户界面 (UI): 实现用户交互界面,例如菜单、对话框、图形显示等。可以使用简单的文本界面或者图形界面库 (如 LittlevGL, emWin 等)。
    • 应用逻辑: 处理用户的操作请求,调用服务层提供的API,实现具体的功能,例如设置示波器参数、生成信号波形、保存数据到USB存储等。
    • 配置管理: 管理系统的配置参数,例如示波器采样率、信号发生器波形类型、显示屏亮度等。
  • 实现要点:
    • 应用层代码应关注用户体验,提供友好、易用的界面。
    • 应用层代码应简洁明了,专注于应用逻辑,避免包含底层硬件操作。
    • 可以使用状态机、事件驱动等设计模式,管理应用程序的状态和流程。
    • 考虑用户操作的容错性,提供友好的错误提示。

代码实现示例 (C语言)

为了演示上述架构,并满足3000行代码的需求,我将提供一个相对详细的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
project/
├── hal/ # 硬件抽象层 (HAL)
│ ├── inc/ # HAL 头文件
│ │ ├── hal_gpio.h
│ │ ├── hal_adc.h
│ │ ├── hal_dac.h
│ │ ├── hal_spi.h
│ │ ├── hal_timer.h
│ │ ├── hal_usb.h
│ │ └── hal.h
│ └── src/ # HAL 源文件
│ ├── hal_gpio.c
│ ├── hal_adc.c
│ ├── hal_dac.c
│ ├── hal_spi.c
│ ├── hal_timer.c
│ ├── hal_usb.c
│ └── hal.c
├── bsp/ # 板级支持包 (BSP)
│ ├── inc/ # BSP 头文件
│ │ └── bsp.h
│ └── src/ # BSP 源文件
│ └── bsp.c
├── rtos/ # 实时操作系统 (这里假设使用简化的 RTOS 概念)
│ ├── inc/ # RTOS 头文件
│ │ ├── rtos_task.h
│ │ ├── rtos_queue.h
│ │ ├── rtos_semaphore.h
│ │ └── rtos.h
│ └── src/ # RTOS 源文件 (简化实现)
│ ├── rtos_task.c
│ ├── rtos_queue.c
│ ├── rtos_semaphore.c
│ └── rtos.c
├── services/ # 服务层
│ ├── inc/ # 服务层头文件
│ │ ├── oscilloscope_service.h
│ │ ├── signal_generator_service.h
│ │ ├── usb_storage_service.h
│ │ ├── display_service.h
│ │ ├── input_service.h
│ │ └── services.h
│ └── src/ # 服务层源文件
│ ├── oscilloscope_service.c
│ ├── signal_generator_service.c
│ ├── usb_storage_service.c
│ ├── display_service.c
│ ├── input_service.c
│ └── services.c
├── app/ # 应用层
│ ├── inc/ # 应用层头文件
│ │ ├── ui.h
│ │ └── app.h
│ └── src/ # 应用层源文件
│ ├── ui.c
│ ├── app.c
│ └── main.c # 主程序入口
├── drivers/ # 设备驱动 (例如 LCD 驱动)
│ ├── inc/
│ │ └── lcd_driver.h
│ └── src/
│ └── lcd_driver.c
├── libs/ # 第三方库 (例如文件系统库)
│ ├── inc/
│ └── src/
├── include/ # 项目公共头文件
├── build/ # 编译输出目录
├── doc/ # 文档目录
└── tools/ # 工具脚本目录

代码示例 (部分关键模块 - 完整代码超过3000行)

1. HAL 层 (hal/)

hal/inc/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
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

typedef enum {
GPIO_PIN_0 = 0,
GPIO_PIN_1,
GPIO_PIN_2,
// ...
GPIO_PIN_MAX
} GPIO_PinTypeDef;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_AF // Alternate Function
} GPIO_ModeTypeDef;

typedef enum {
GPIO_SPEED_LOW,
GPIO_SPEED_MEDIUM,
GPIO_SPEED_HIGH
} GPIO_SpeedTypeDef;

typedef enum {
GPIO_PUPD_NONE,
GPIO_PUPD_PULLUP,
GPIO_PUPD_PULLDOWN
} GPIO_PuPdTypeDef;

typedef struct {
GPIO_PinTypeDef Pin;
GPIO_ModeTypeDef Mode;
GPIO_SpeedTypeDef Speed;
GPIO_PuPdTypeDef Pull;
} GPIO_InitTypeDef;

void HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct);
void HAL_GPIO_WritePin(GPIO_PinTypeDef Pin, uint8_t PinState); // 0 or 1
uint8_t HAL_GPIO_ReadPin(GPIO_PinTypeDef Pin);

#endif // HAL_GPIO_H

hal/src/hal_gpio.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
#include "hal_gpio.h"
#include "bsp.h" // 假设 bsp.h 中定义了硬件寄存器地址

void HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct) {
// ... (根据 GPIO_InitStruct 配置硬件寄存器,例如设置方向、速度、上下拉电阻等)
// 这里是硬件相关的具体实现,例如操作 MCU 的 GPIO 寄存器
// 例如:
// if (GPIO_InitStruct->Pin == GPIO_PIN_0) {
// if (GPIO_InitStruct->Mode == GPIO_MODE_OUTPUT) {
// // 设置 GPIO_PIN_0 为输出模式,操作硬件寄存器
// // ...
// }
// }
// ...
(void)GPIO_InitStruct; // 避免编译警告,实际需要根据 GPIO_InitStruct 配置硬件
}

void HAL_GPIO_WritePin(GPIO_PinTypeDef Pin, uint8_t PinState) {
// ... (根据 Pin 设置 GPIO 输出电平,操作硬件寄存器)
// 例如:
// if (Pin == GPIO_PIN_0) {
// if (PinState == 1) {
// // 设置 GPIO_PIN_0 输出高电平,操作硬件寄存器
// // ...
// } else {
// // 设置 GPIO_PIN_0 输出低电平,操作硬件寄存器
// // ...
// }
// }
// ...
(void)Pin; (void)PinState; // 避免编译警告,实际需要根据 Pin 和 PinState 操作硬件
}

uint8_t HAL_GPIO_ReadPin(GPIO_PinTypeDef Pin) {
// ... (读取 GPIO 输入电平,操作硬件寄存器)
// 例如:
// if (Pin == GPIO_PIN_0) {
// // 读取 GPIO_PIN_0 的输入状态,操作硬件寄存器并返回
// // ...
// }
// ...
(void)Pin; // 避免编译警告,实际需要根据 Pin 操作硬件
return 0; // 默认返回 0,实际需要读取硬件状态
}

类似地,可以实现 hal_adc.h, hal_adc.c, hal_dac.h, hal_dac.c, hal_spi.h, hal_spi.c, hal_timer.h, hal_timer.c, hal_usb.h, hal_usb.c 等 HAL 驱动。 这些驱动会根据具体的硬件平台进行实现,操作 MCU 的相关寄存器。

2. BSP 层 (bsp/)

bsp/inc/bsp.h

1
2
3
4
5
6
7
8
9
10
11
#ifndef BSP_H
#define BSP_H

#include "hal.h" // 包含 HAL 层头文件

void BSP_SystemInit(void);
void BSP_LED_Init(void);
void BSP_LED_On(void);
void BSP_LED_Off(void);

#endif // BSP_H

bsp/src/bsp.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
#include "bsp.h"
#include "hal_gpio.h" // 使用 GPIO 驱动控制 LED

void BSP_SystemInit(void) {
// ... (系统时钟初始化,例如配置 PLL, 设置系统时钟频率)
// ... (中断向量表初始化)
// ... (堆栈初始化)
// ... (其他系统级初始化)
BSP_LED_Init(); // 初始化 LED
// ... (初始化其他板级硬件,例如晶振、外部存储器等)
}

void BSP_LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_0; // 假设 LED 连接到 GPIO_PIN_0
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Pull = GPIO_PUPD_NONE;
HAL_GPIO_Init(&GPIO_InitStruct);
BSP_LED_Off(); // 默认关闭 LED
}

void BSP_LED_On(void) {
HAL_GPIO_WritePin(GPIO_PIN_0, 1); // LED 亮
}

void BSP_LED_Off(void) {
HAL_GPIO_WritePin(GPIO_PIN_0, 0); // LED 灭
}

3. RTOS 层 (rtos/) - 简化 RTOS 概念

rtos/inc/rtos_task.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef RTOS_TASK_H
#define RTOS_TASK_H

typedef void (*TaskFunction_t)(void *pvParameters);

typedef struct {
TaskFunction_t pvTaskCode;
const char *pcName;
void *pvParameters;
unsigned int usStackDepth; // Stack size in words
unsigned portBASE_TYPE uxPriority;
void *pxTaskHandle; // Task handle (optional, for future use)
} TaskInitTypeDef_t;

void RTOS_TaskCreate(TaskInitTypeDef_t *pxTaskDefinition);
void RTOS_TaskStartScheduler(void); // 启动调度器 (简化的裸机轮询调度)

#endif // RTOS_TASK_H

rtos/src/rtos_task.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
#include "rtos_task.h"

#define MAX_TASKS 10
static TaskInitTypeDef_t Tasks[MAX_TASKS];
static int TaskCount = 0;

void RTOS_TaskCreate(TaskInitTypeDef_t *pxTaskDefinition) {
if (TaskCount < MAX_TASKS) {
Tasks[TaskCount] = *pxTaskDefinition;
TaskCount++;
} else {
// Error: Too many tasks
}
}

void RTOS_TaskStartScheduler(void) {
while (1) {
for (int i = 0; i < TaskCount; i++) {
if (Tasks[i].pvTaskCode != NULL) {
Tasks[i].pvTaskCode(Tasks[i].pvParameters); // 执行任务函数
}
}
// ... (可以添加延时,模拟 RTOS 的时间片轮转)
}
}

这只是一个非常简化的 RTOS 概念示例,实际的 RTOS 会更复杂,例如 FreeRTOS, RT-Thread 等,需要包含更完善的调度算法、任务管理、同步机制等。 如果项目需要更专业的 RTOS 功能,建议直接集成成熟的 RTOS 库。

4. 服务层 (services/)

services/inc/oscilloscope_service.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
#ifndef OSCILLOSCOPE_SERVICE_H
#define OSCILLOSCOPE_SERVICE_H

#include "hal_adc.h"
#include "hal_timer.h"
#include "display_service.h"

#define OSCILLOSCOPE_SAMPLE_BUFFER_SIZE 1024

typedef struct {
uint16_t sample_buffer[OSCILLOSCOPE_SAMPLE_BUFFER_SIZE];
uint16_t sample_count;
uint32_t sample_rate_hz;
// ... (其他示波器状态参数,例如触发模式、时基、电压刻度等)
} OscilloscopeData_t;

void OscilloscopeService_Init(void);
void OscilloscopeService_StartSampling(uint32_t sample_rate_hz);
void OscilloscopeService_StopSampling(void);
OscilloscopeData_t* OscilloscopeService_GetData(void); // 获取采样数据
void OscilloscopeService_SetTimebase(uint32_t timebase_ms);
void OscilloscopeService_SetVoltageScale(float voltage_scale_v_div);

#endif // OSCILLOSCOPE_SERVICE_H

services/src/oscilloscope_service.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
#include "oscilloscope_service.h"
#include "hal_adc.h"
#include "hal_timer.h"
#include "display_service.h"
#include "rtos.h" // 假设使用 RTOS

static OscilloscopeData_t oscilloscope_data;
static volatile uint8_t sampling_enabled = 0;

void OscilloscopeService_Init(void) {
// ... (初始化 ADC 模块)
// ... (初始化 Timer 模块,用于采样定时)
oscilloscope_data.sample_count = 0;
oscilloscope_data.sample_rate_hz = 1000; // 默认采样率 1kHz
// ... (初始化其他示波器参数)
}

void OscilloscopeService_StartSampling(uint32_t sample_rate_hz) {
oscilloscope_data.sample_rate_hz = sample_rate_hz;
oscilloscope_data.sample_count = 0;
sampling_enabled = 1;
// ... (启动 ADC 采样定时器,触发 ADC 转换)
// ... (可以启动一个 RTOS 任务专门处理 ADC 采样数据)
}

void OscilloscopeService_StopSampling(void) {
sampling_enabled = 0;
// ... (停止 ADC 采样定时器)
}

OscilloscopeData_t* OscilloscopeService_GetData(void) {
return &oscilloscope_data;
}

void OscilloscopeService_SetTimebase(uint32_t timebase_ms) {
// ... (根据 timebase_ms 设置示波器时基)
}

void OscilloscopeService_SetVoltageScale(float voltage_scale_v_div) {
// ... (根据 voltage_scale_v_div 设置示波器电压刻度)
}

// ADC 采样完成中断回调函数 (假设在 HAL 层或 BSP 层配置)
void ADC_ConversionComplete_Callback(uint16_t adc_value) {
if (sampling_enabled) {
if (oscilloscope_data.sample_count < OSCILLOSCOPE_SAMPLE_BUFFER_SIZE) {
oscilloscope_data.sample_buffer[oscilloscope_data.sample_count++] = adc_value;
} else {
OscilloscopeService_StopSampling(); // 缓冲区满,停止采样
// ... (可以发送消息给显示任务,更新波形显示)
}
}
}

// 示波器服务任务 (如果使用 RTOS)
void OscilloscopeService_Task(void *pvParameters) {
(void)pvParameters;
while (1) {
if (sampling_enabled) {
// ... (处理采样数据,例如触发检测、数据滤波、计算参数等)
// ... (更新显示数据,例如将波形数据发送给显示服务)
}
// RTOS_TaskDelay(10); // 延时一段时间,降低 CPU 占用率
}
}

类似地,可以实现 signal_generator_service.h, signal_generator_service.c, usb_storage_service.h, usb_storage_service.c, display_service.h, display_service.c, input_service.h, input_service.c 等服务模块。 这些服务模块封装了各自的功能逻辑,并提供 API 供应用层调用。

5. 应用层 (app/)

app/inc/ui.h

1
2
3
4
5
6
7
8
9
#ifndef UI_H
#define UI_H

void UI_Init(void);
void UI_DisplayMenu(void);
void UI_UpdateOscilloscopeDisplay(OscilloscopeData_t *data);
void UI_UpdateSignalGeneratorDisplay(void); // ... 其他显示更新函数

#endif // UI_H

app/src/ui.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
95
96
97
98
99
100
101
#include "ui.h"
#include "display_service.h"
#include "input_service.h"
#include "oscilloscope_service.h"
#include "signal_generator_service.h"
#include <stdio.h> // For sprintf

void UI_Init(void) {
DisplayService_Init(); // 初始化显示服务
InputService_Init(); // 初始化输入服务
DisplayService_ClearScreen();
UI_DisplayMenu();
}

void UI_DisplayMenu(void) {
DisplayService_ClearScreen();
DisplayService_WriteString(0, 0, "Main Menu:");
DisplayService_WriteString(1, 0, "1. Oscilloscope");
DisplayService_WriteString(2, 0, "2. Signal Gen");
DisplayService_WriteString(3, 0, "3. USB Storage");
// ...
}

void UI_UpdateOscilloscopeDisplay(OscilloscopeData_t *data) {
DisplayService_ClearScreen();
DisplayService_WriteString(0, 0, "Oscilloscope:");
// ... (显示示波器状态信息,例如采样率、时基、电压刻度等)
// ... (绘制波形,可以使用简单的文本字符模拟波形)
char buffer[32];
sprintf(buffer, "Sample Count: %d", data->sample_count);
DisplayService_WriteString(1, 0, buffer);

// 简单文本波形绘制示例 (假设 LCD 是 16x2 字符 LCD)
DisplayService_WriteString(2, 0, "Waveform:");
char waveform_line[17] = {0}; // 16 characters + null terminator
for (int i = 0; i < 16; i++) {
if (i < data->sample_count && i < OSCILLOSCOPE_SAMPLE_BUFFER_SIZE / 64) { // 简化显示,每 64 个采样点显示一个字符
uint16_t sample_value = data->sample_buffer[i * 64];
if (sample_value > 500) { // 假设 ADC 值范围 0-1023
waveform_line[i] = '*'; // 高电平用 * 表示
} else {
waveform_line[i] = ' '; // 低电平用空格表示
}
} else {
waveform_line[i] = ' ';
}
}
DisplayService_WriteString(3, 0, waveform_line);
}

void UI_UpdateSignalGeneratorDisplay(void) {
DisplayService_ClearScreen();
DisplayService_WriteString(0, 0, "Signal Generator:");
// ... (显示信号发生器状态信息,例如波形类型、频率、幅度等)
}

// UI 任务 (如果使用 RTOS)
void UITask(void *pvParameters) {
(void)pvParameters;
UI_Init();
uint8_t current_menu = 0; // 0: Main Menu, 1: Oscilloscope, 2: Signal Generator, ...

while (1) {
InputEvent_t event;
if (InputService_GetEvent(&event)) { // 获取输入事件
if (event.type == INPUT_TYPE_BUTTON_PRESS) {
if (event.id == BUTTON_UP) {
// ... (处理按键事件,例如菜单切换、参数调整)
if (current_menu == 0) {
if (event.value == 1) { // 按下按钮 1
current_menu = 1;
OscilloscopeService_StartSampling(1000); // 开始示波器采样
} else if (event.value == 2) { // 按下按钮 2
current_menu = 2;
// ... (切换到信号发生器菜单)
}
} else if (current_menu == 1) {
if (event.id == BUTTON_BACK) { // 返回按钮
current_menu = 0;
OscilloscopeService_StopSampling(); // 停止示波器采样
UI_DisplayMenu();
}
}
// ... (根据当前菜单和按键事件执行相应的操作)
}
// ... (处理其他按键事件)
} else if (event.type == INPUT_TYPE_ENCODER_ROTATE) {
// ... (处理旋钮编码器事件,例如参数调节)
}
}

if (current_menu == 1) {
OscilloscopeData_t *oscilloscope_data = OscilloscopeService_GetData();
UI_UpdateOscilloscopeDisplay(oscilloscope_data); // 更新示波器显示
} else if (current_menu == 2) {
UI_UpdateSignalGeneratorDisplay(); // 更新信号发生器显示
}

// RTOS_TaskDelay(50); // 延时一段时间,降低 UI 刷新率
}
}

app/src/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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "bsp.h"
#include "rtos.h"
#include "app.h"
#include "ui.h"
#include "oscilloscope_service.h"
#include "signal_generator_service.h"
#include "usb_storage_service.h"
#include "input_service.h"
#include "display_service.h"

void OscilloscopeTask(void *pvParameters);
void SignalGeneratorTask(void *pvParameters);
void USBStorageTask(void *pvParameters);
void UITask(void *pvParameters);

int main() {
BSP_SystemInit(); // 初始化 BSP

// 初始化服务层模块
OscilloscopeService_Init();
SignalGeneratorService_Init();
USBStorageService_Init();
DisplayService_Init();
InputService_Init();

// 创建 RTOS 任务 (如果使用 RTOS)
TaskInitTypeDef_t task_ui = {UITask, "UI Task", NULL, 128, 1, NULL};
RTOS_TaskCreate(&task_ui);

TaskInitTypeDef_t task_oscilloscope = {OscilloscopeTask, "Oscilloscope Task", NULL, 256, 2, NULL};
RTOS_TaskCreate(&task_oscilloscope);

TaskInitTypeDef_t task_signal_generator = {SignalGeneratorTask, "Signal Gen Task", NULL, 256, 2, NULL};
RTOS_TaskCreate(&task_signal_generator);

TaskInitTypeDef_t task_usb_storage = {USBStorageTask, "USB Storage Task", NULL, 512, 3, NULL};
RTOS_TaskCreate(&task_usb_storage);


RTOS_TaskStartScheduler(); // 启动 RTOS 调度器 (如果使用 RTOS)
// 如果是裸机系统,则直接进入主循环,例如调用 UITask()
// UITask(NULL); // 裸机系统直接运行 UI 任务

return 0; // 理论上 RTOS 启动后不会返回到 main 函数
}

// 各个功能任务的实现 (例如示波器任务、信号发生器任务、USB存储任务)
// 这些任务的具体实现逻辑可以放在 app/src/ 或 services/src/ 目录下

// 示波器任务示例
void OscilloscopeTask(void *pvParameters) {
(void)pvParameters;
while (1) {
// ... (示波器任务的具体逻辑,例如数据采集、触发、数据处理)
// ... (可以通过消息队列或共享内存与 UI 任务通信,传递数据)
// RTOS_TaskDelay(10); // 延时
}
}

// 信号发生器任务示例
void SignalGeneratorTask(void *pvParameters) {
(void)pvParameters;
while (1) {
// ... (信号发生器任务的具体逻辑,例如波形生成、频率控制、幅度控制)
// ... (控制 DAC 输出信号)
// RTOS_TaskDelay(10); // 延时
}
}

// USB 存储任务示例
void USBStorageTask(void *pvParameters) {
(void)pvParameters;
while (1) {
// ... (USB 存储任务的具体逻辑,例如 USB 设备枚举、文件系统处理)
// ... (处理 USB Host 或 USB Device 相关操作)
// RTOS_TaskDelay(100); // 延时
}
}

drivers/ 目录 (设备驱动)

drivers/inc/lcd_driver.h

1
2
3
4
5
6
7
8
9
#ifndef LCD_DRIVER_H
#define LCD_DRIVER_H

void LCD_Init(void);
void LCD_Clear(void);
void LCD_SetCursor(uint8_t row, uint8_t col);
void LCD_WriteString(const char *str);

#endif // LCD_DRIVER_H

drivers/src/lcd_driver.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
#include "lcd_driver.h"
#include "hal_gpio.h" // 假设 LCD 控制线使用 GPIO
#include "hal_spi.h" // 假设 LCD 数据线使用 SPI

void LCD_Init(void) {
// ... (初始化 LCD 控制器,例如配置 GPIO 或 SPI 引脚)
// ... (发送 LCD 初始化命令序列)
// ... (例如设置显示模式、光标、清屏等)
}

void LCD_Clear(void) {
// ... (发送 LCD 清屏命令)
}

void LCD_SetCursor(uint8_t row, uint8_t col) {
// ... (设置 LCD 光标位置)
}

void LCD_WriteString(const char *str) {
// ... (循环发送字符串中的每个字符到 LCD 数据端口)
while (*str) {
// ... (发送 *str 字符到 LCD 数据端口)
str++;
}
}

libs/ 目录 (第三方库)

这个目录可以存放例如 FAT 文件系统库 (例如 FatFs) 的头文件和源文件,用于实现 USB 存储功能中的文件系统操作。 由于篇幅限制,这里不再详细展开。

include/ 目录 (公共头文件)

这个目录可以存放项目中通用的头文件,例如类型定义、宏定义、全局变量声明等。

总结

以上代码示例展示了一个基于分层架构的嵌入式系统软件框架,用于构建集成示波器、信号发生器和USB存储功能的嵌入式产品。 代码涵盖了 HAL 层、BSP 层、简化 RTOS 层、服务层和应用层的基本结构和关键模块的实现思路。 由于代码量庞大,我只提供了部分核心模块的示例代码,完整的 3000 行代码需要更加详细地填充各个模块的具体实现逻辑,并根据实际硬件平台和功能需求进行扩展和完善。

关键技术和方法总结:

  • 分层架构: 将系统划分为 HAL, BSP, OS, Service, Application 等层次,提高模块化和可维护性。
  • 硬件抽象层 (HAL): 隔离硬件差异,提高代码的可移植性。
  • 板级支持包 (BSP): 提供特定硬件平台的初始化和配置。
  • 实时操作系统 (RTOS) (可选): 提供多任务处理、任务调度和资源管理能力,提高系统效率和实时性。
  • 服务层: 封装业务逻辑功能模块,提供高层次服务接口。
  • 应用层: 实现用户界面和应用程序逻辑。
  • 模块化设计: 将系统分解为独立的模块,方便开发、测试和维护。
  • 接口设计: 定义清晰的模块接口,实现模块间的解耦。
  • 事件驱动编程: 例如 UI 任务和输入服务之间的交互,提高系统响应性。
  • 状态机: 可以用于管理服务模块和应用层模块的状态和流程。
  • 开源方案: 充分利用开源 RTOS, 文件系统库, USB 协议栈等,缩短开发周期,降低开发成本。

希望以上详细的架构设计和代码示例能够帮助您理解嵌入式系统开发流程和代码组织方式。 实际项目中,代码的细节实现还需要根据具体的硬件平台、功能需求和性能指标进行调整和优化。

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