编程技术分享

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

0%

简介:立创·梁山派-示波器扩展板,由屏幕,按键,拨轮按键,模拟信号采集输出电路组成。一路模拟信号采集,一路波形发生输出,全金属BNC接头连接质感满满。独立三个静音按键,两个拨轮按键搭配,让功能得以灵活的配置

好的,作为一名高级嵌入式软件开发工程师,我将为您详细阐述立创·梁山派-示波器扩展板项目中最适合的代码设计架构,并提供相应的C代码实现。这个项目旨在构建一个可靠、高效、可扩展的嵌入式示波器系统,我们将从需求分析开始,逐步深入到系统实现、测试验证和维护升级的各个环节。
关注微信公众号,提前获取相关推文

1. 需求分析与系统架构设计

1.1 需求分析

基于产品简介和图片,我们可以提取出以下关键需求:

  • 核心功能:

    • 模拟信号采集: 单通道模拟信号输入,需要高精度、高采样率的ADC模块。
    • 波形发生输出: 单通道波形输出,需要DAC模块或者PWM模拟输出,能够生成多种波形(正弦波、方波、三角波等)。
    • 波形显示: 在屏幕上实时显示采集到的波形,并提供必要的参数显示(电压幅度、时间刻度等)。
    • 用户交互: 通过按键和拨轮按键进行功能配置和参数调整,例如:
      • 调整垂直刻度(电压/格)。
      • 调整水平刻度(时间/格)。
      • 切换触发模式。
      • 选择波形发生器输出波形类型。
      • 调整波形发生器频率和幅度。
      • 菜单导航和参数设置。
  • 硬件资源:

    • 屏幕: 用于波形和UI显示。
    • 按键: 独立静音按键,用于功能选择和操作。
    • 拨轮按键: 用于参数调节和菜单导航。
    • 模拟信号采集电路: 包含BNC接口和ADC模块。
    • 波形发生输出电路: 包含BNC接口和DAC/PWM模块。
  • 系统特性:

    • 可靠性: 系统需要稳定可靠地运行,避免崩溃和数据错误。
    • 高效性: 系统需要快速响应用户操作,实时采集和显示波形。
    • 可扩展性: 系统架构应易于扩展新功能,例如更高级的触发模式、频谱分析、数据存储等。
    • 易维护性: 代码结构清晰,模块化,方便后续维护和升级。

1.2 系统架构设计

为了满足上述需求,我们选择分层架构作为系统的主要架构模式。分层架构能够将系统划分为不同的功能层,每一层只关注特定的职责,层与层之间通过清晰的接口进行通信,从而提高代码的可维护性和可扩展性。

我们的系统架构可以分为以下几层:

  • 硬件抽象层 (HAL - Hardware Abstraction Layer): 直接与硬件交互,封装底层硬件操作,向上层提供统一的硬件接口。例如,ADC驱动、DAC驱动、GPIO驱动、SPI/I2C驱动(如果屏幕使用SPI/I2C接口)、定时器驱动等。HAL层的目标是屏蔽硬件差异,使得上层应用代码可以在不同的硬件平台上移植。

  • 板级支持包 (BSP - Board Support Package): 基于HAL层,提供更高级的硬件服务和系统初始化功能。例如,时钟配置、中断管理、存储器管理、外设初始化等。BSP层负责为应用层提供一个可用的硬件平台环境。

  • 核心服务层 (Core Services Layer): 提供系统核心服务,例如任务调度、数据管理、算法实现等。对于示波器系统,核心服务层可以包含:

    • ADC采样服务: 负责控制ADC模块进行采样,并将采样数据存储到缓冲区。
    • 波形生成服务: 负责生成各种波形数据,并控制DAC/PWM模块输出。
    • 显示驱动服务: 负责将波形数据和UI元素绘制到屏幕上。
    • 输入处理服务: 负责处理按键和拨轮按键的输入,并将输入事件传递给应用层。
  • 应用层 (Application Layer): 实现示波器的具体功能逻辑,例如:

    • 示波器模式: 采集和显示模拟信号波形,提供参数调整功能。
    • 波形发生器模式: 生成并输出指定波形,提供参数调整功能。
    • 菜单管理: 实现用户界面菜单,用于功能选择和参数设置。
  • 用户界面层 (UI Layer): 负责用户界面的呈现和用户交互逻辑。UI层可以基于图形库(例如,简单的帧缓冲绘图或者更高级的GUI库)实现,处理用户输入事件,并更新屏幕显示。

系统架构图示:

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
+---------------------+
| 应用层 (Application Layer) |
| - 示波器模式 |
| - 波形发生器模式 |
| - 菜单管理 |
+---------------------+
^
|
+---------------------+
| 核心服务层 (Core Services Layer) |
| - ADC采样服务 |
| - 波形生成服务 |
| - 显示驱动服务 |
| - 输入处理服务 |
+---------------------+
^
|
+---------------------+
| 板级支持包 (BSP - Board Support Package) |
| - 时钟配置 |
| - 中断管理 |
| - 外设初始化 |
+---------------------+
^
|
+---------------------+
| 硬件抽象层 (HAL - Hardware Abstraction Layer) |
| - ADC驱动 |
| - DAC驱动 |
| - GPIO驱动 |
| - SPI/I2C驱动 |
| - 定时器驱动 |
+---------------------+
^
|
+---------------------+
| 硬件 (Hardware) |
| - MCU |
| - ADC芯片 |
| - DAC芯片/PWM输出 |
| - 屏幕 |
| - 按键 |
| - 拨轮按键 |
+---------------------+

2. 代码实现 (C语言)

下面我将逐步提供各个层次的代码实现,并进行详细的解释。为了代码的完整性和可运行性,我会假设使用一个常见的嵌入式开发平台,例如基于ARM Cortex-M系列的单片机,并使用一些常用的外设接口。

2.1 硬件抽象层 (HAL)

hal_adc.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
#ifndef HAL_ADC_H
#define HAL_ADC_H

#include <stdint.h>

// ADC 初始化结构体
typedef struct {
uint32_t resolution; // ADC 分辨率 (例如 12位)
uint32_t sampling_rate; // 采样率 (Hz)
uint32_t channel; // ADC 通道
} HAL_ADC_ConfigTypeDef;

// 初始化 ADC
HAL_StatusTypeDef HAL_ADC_Init(HAL_ADC_ConfigTypeDef *config);

// 开始 ADC 采样
HAL_StatusTypeDef HAL_ADC_Start();

// 停止 ADC 采样
HAL_StatusTypeDef HAL_ADC_Stop();

// 获取 ADC 采样数据
HAL_StatusTypeDef HAL_ADC_GetData(uint16_t *data);

// 设置 ADC 采样完成回调函数 (可选,用于中断模式)
typedef void (*HAL_ADC_CallbackTypeDef)(uint16_t data);
HAL_StatusTypeDef HAL_ADC_SetCallback(HAL_ADC_CallbackTypeDef callback);

#endif // HAL_ADC_H

hal_adc.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 "hal_adc.h"
#include "stm32_adc.h" // 假设使用 STM32 的 ADC 驱动

HAL_StatusTypeDef HAL_ADC_Init(HAL_ADC_ConfigTypeDef *config) {
// 将 HAL 层配置转换为 STM32 ADC 驱动配置
STM32_ADC_ConfigTypeDef stm32_config;
stm32_config.resolution = config->resolution;
stm32_config.sampling_rate = config->sampling_rate;
stm32_config.channel = config->channel;

// 调用 STM32 ADC 驱动初始化函数
return STM32_ADC_Init(&stm32_config);
}

HAL_StatusTypeDef HAL_ADC_Start() {
return STM32_ADC_Start();
}

HAL_StatusTypeDef HAL_ADC_Stop() {
return STM32_ADC_Stop();
}

HAL_StatusTypeDef HAL_ADC_GetData(uint16_t *data) {
return STM32_ADC_GetData(data);
}

HAL_StatusTypeDef HAL_ADC_SetCallback(HAL_ADC_CallbackTypeDef callback) {
return STM32_ADC_SetCallback(callback);
}

hal_dac.h:

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

#include <stdint.h>

// DAC 初始化结构体
typedef struct {
uint32_t resolution; // DAC 分辨率 (例如 12位)
uint32_t channel; // DAC 通道
} HAL_DAC_ConfigTypeDef;

// 初始化 DAC
HAL_StatusTypeDef HAL_DAC_Init(HAL_DAC_ConfigTypeDef *config);

// 设置 DAC 输出电压值 (0 - MaxValue)
HAL_StatusTypeDef HAL_DAC_SetValue(uint16_t value);

#endif // HAL_DAC_H

hal_dac.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "hal_dac.h"
#include "stm32_dac.h" // 假设使用 STM32 的 DAC 驱动

HAL_StatusTypeDef HAL_DAC_Init(HAL_DAC_ConfigTypeDef *config) {
// 将 HAL 层配置转换为 STM32 DAC 驱动配置
STM32_DAC_ConfigTypeDef stm32_config;
stm32_config.resolution = config->resolution;
stm32_config.channel = config->channel;

// 调用 STM32 DAC 驱动初始化函数
return STM32_DAC_Init(&stm32_config);
}

HAL_StatusTypeDef HAL_DAC_SetValue(uint16_t value) {
return STM32_DAC_SetValue(value);
}

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

#include <stdint.h>

// GPIO 初始化结构体
typedef struct {
uint32_t pin; // GPIO 引脚
uint32_t mode; // GPIO 模式 (输入/输出/复用功能)
uint32_t pull; // 上拉/下拉/浮空
uint32_t speed; // GPIO 速度
} HAL_GPIO_ConfigTypeDef;

// GPIO 模式定义
#define HAL_GPIO_MODE_INPUT 0x00
#define HAL_GPIO_MODE_OUTPUT 0x01
#define HAL_GPIO_MODE_AF 0x02 // 复用功能

// GPIO 上拉/下拉定义
#define HAL_GPIO_PULL_NONE 0x00
#define HAL_GPIO_PULL_UP 0x01
#define HAL_GPIO_PULL_DOWN 0x02

// GPIO 速度定义 (根据具体MCU定义)
#define HAL_GPIO_SPEED_LOW 0x00
#define HAL_GPIO_SPEED_MEDIUM 0x01
#define HAL_GPIO_SPEED_HIGH 0x02

// 初始化 GPIO
HAL_StatusTypeDef HAL_GPIO_Init(HAL_GPIO_ConfigTypeDef *config);

// 设置 GPIO 输出电平
HAL_StatusTypeDef HAL_GPIO_WritePin(uint32_t pin, uint8_t state);

// 读取 GPIO 输入电平
uint8_t HAL_GPIO_ReadPin(uint32_t pin);

#endif // HAL_GPIO_H

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
#include "hal_gpio.h"
#include "stm32_gpio.h" // 假设使用 STM32 的 GPIO 驱动

HAL_StatusTypeDef HAL_GPIO_Init(HAL_GPIO_ConfigTypeDef *config) {
// 将 HAL 层配置转换为 STM32 GPIO 驱动配置
STM32_GPIO_ConfigTypeDef stm32_config;
stm32_config.pin = config->pin;
stm32_config.mode = config->mode;
stm32_config.pull = config->pull;
stm32_config.speed = config->speed;

// 调用 STM32 GPIO 驱动初始化函数
return STM32_GPIO_Init(&stm32_config);
}

HAL_StatusTypeDef HAL_GPIO_WritePin(uint32_t pin, uint8_t state) {
return STM32_GPIO_WritePin(pin, state);
}

uint8_t HAL_GPIO_ReadPin(uint32_t pin) {
return STM32_GPIO_ReadPin(pin);
}

hal_spi.h (如果屏幕使用SPI):

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
#ifndef HAL_SPI_H
#define HAL_SPI_H

#include <stdint.h>

// SPI 初始化结构体
typedef struct {
uint32_t mode; // SPI 模式 (主/从)
uint32_t baudrate; // SPI 波特率
uint32_t data_size; // 数据位大小 (8位/16位)
uint32_t clock_polarity; // 时钟极性
uint32_t clock_phase; // 时钟相位
} HAL_SPI_ConfigTypeDef;

// SPI 模式定义
#define HAL_SPI_MODE_MASTER 0x00
#define HAL_SPI_MODE_SLAVE 0x01

// SPI 时钟极性/相位定义
#define HAL_SPI_POLARITY_LOW 0x00
#define HAL_SPI_POLARITY_HIGH 0x01
#define HAL_SPI_PHASE_1EDGE 0x00
#define HAL_SPI_PHASE_2EDGE 0x01

// 初始化 SPI
HAL_StatusTypeDef HAL_SPI_Init(HAL_SPI_ConfigTypeDef *config);

// SPI 发送数据
HAL_StatusTypeDef HAL_SPI_Transmit(uint8_t *data, uint32_t size);

// SPI 接收数据
HAL_StatusTypeDef HAL_SPI_Receive(uint8_t *data, uint32_t size);

// SPI 收发数据
HAL_StatusTypeDef HAL_SPI_TransmitReceive(uint8_t *tx_data, uint8_t *rx_data, uint32_t size);

#endif // HAL_SPI_H

hal_spi.c (如果屏幕使用SPI):

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
#include "hal_spi.h"
#include "stm32_spi.h" // 假设使用 STM32 的 SPI 驱动

HAL_StatusTypeDef HAL_SPI_Init(HAL_SPI_ConfigTypeDef *config) {
// 将 HAL 层配置转换为 STM32 SPI 驱动配置
STM32_SPI_ConfigTypeDef stm32_config;
stm32_config.mode = config->mode;
stm32_config.baudrate = config->baudrate;
stm32_config.data_size = config->data_size;
stm32_config.clock_polarity = config->clock_polarity;
stm32_config.clock_phase = config->clock_phase;

// 调用 STM32 SPI 驱动初始化函数
return STM32_SPI_Init(&stm32_config);
}

HAL_StatusTypeDef HAL_SPI_Transmit(uint8_t *data, uint32_t size) {
return STM32_SPI_Transmit(data, size);
}

HAL_StatusTypeDef HAL_SPI_Receive(uint8_t *data, uint32_t size) {
return STM32_SPI_Receive(data, size);
}

HAL_StatusTypeDef HAL_SPI_TransmitReceive(uint8_t *tx_data, uint8_t *rx_data, uint32_t size) {
return STM32_SPI_TransmitReceive(tx_data, rx_data, size);
}

hal_timer.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
#ifndef HAL_TIMER_H
#define HAL_TIMER_H

#include <stdint.h>

// 定时器初始化结构体
typedef struct {
uint32_t prescaler; // 预分频器
uint32_t period; // 周期
uint32_t mode; // 定时器模式 (例如,普通定时器,PWM)
} HAL_TIMER_ConfigTypeDef;

// 定时器模式定义 (根据具体MCU定义)
#define HAL_TIMER_MODE_BASIC 0x00
#define HAL_TIMER_MODE_PWM 0x01

// 初始化定时器
HAL_StatusTypeDef HAL_TIMER_Init(HAL_TIMER_ConfigTypeDef *config);

// 启动定时器
HAL_StatusTypeDef HAL_TIMER_Start();

// 停止定时器
HAL_StatusTypeDef HAL_TIMER_Stop();

// 设置定时器中断回调函数
typedef void (*HAL_TIMER_CallbackTypeDef)(void);
HAL_StatusTypeDef HAL_TIMER_SetCallback(HAL_TIMER_CallbackTypeDef callback);

// 设置 PWM 占空比 (0-100%)
HAL_StatusTypeDef HAL_TIMER_SetPWMDutyCycle(uint32_t channel, uint32_t duty_cycle);

#endif // HAL_TIMER_H

hal_timer.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 "hal_timer.h"
#include "stm32_timer.h" // 假设使用 STM32 的 定时器驱动

HAL_StatusTypeDef HAL_TIMER_Init(HAL_TIMER_ConfigTypeDef *config) {
// 将 HAL 层配置转换为 STM32 定时器驱动配置
STM32_TIMER_ConfigTypeDef stm32_config;
stm32_config.prescaler = config->prescaler;
stm32_config.period = config->period;
stm32_config.mode = config->mode;

// 调用 STM32 定时器驱动初始化函数
return STM32_TIMER_Init(&stm32_config);
}

HAL_StatusTypeDef HAL_TIMER_Start() {
return STM32_TIMER_Start();
}

HAL_StatusTypeDef HAL_TIMER_Stop() {
return STM32_TIMER_Stop();
}

HAL_StatusTypeDef HAL_TIMER_SetCallback(HAL_TIMER_CallbackTypeDef callback) {
return STM32_TIMER_SetCallback(callback);
}

HAL_StatusTypeDef HAL_TIMER_SetPWMDutyCycle(uint32_t channel, uint32_t duty_cycle) {
return STM32_TIMER_SetPWMDutyCycle(channel, duty_cycle);
}

注意: stm32_adc.h, stm32_dac.h, stm32_gpio.h, stm32_spi.h, stm32_timer.h 这些头文件和对应的源文件是假设的 STM32 平台的底层驱动,需要根据实际使用的 MCU 平台进行替换或编写。HAL 层的目的是提供一个通用的接口,方便上层代码调用,而不需要关心底层的硬件细节。

2.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
#ifndef BSP_H
#define BSP_H

#include "hal_adc.h"
#include "hal_dac.h"
#include "hal_gpio.h"
#include "hal_spi.h"
#include "hal_timer.h"

// 系统时钟频率 (假设为 72MHz)
#define SYS_CLK_FREQ 72000000UL

// ADC 相关定义
#define BSP_ADC_CHANNEL 0 // ADC 通道
#define BSP_ADC_RESOLUTION 12 // ADC 分辨率 (位)
#define BSP_ADC_SAMPLING_RATE 100000 // 采样率 (Hz)

// DAC 相关定义
#define BSP_DAC_CHANNEL 0 // DAC 通道
#define BSP_DAC_RESOLUTION 12 // DAC 分辨率 (位)

// GPIO 定义 (根据实际硬件连接定义)
#define BSP_BUTTON_MENU_PIN GPIO_PIN_0 // 菜单按键
#define BSP_BUTTON_OK_PIN GPIO_PIN_1 // OK 按键
#define BSP_BUTTON_CANCEL_PIN GPIO_PIN_2 // 取消按键
#define BSP_ENCODER_A_PIN GPIO_PIN_3 // 编码器 A 相
#define BSP_ENCODER_B_PIN GPIO_PIN_4 // 编码器 B 相
#define BSP_ENCODER_SW_PIN GPIO_PIN_5 // 编码器开关

// SPI 定义 (如果屏幕使用 SPI)
#define BSP_SPI_BAUDRATE 10000000 // SPI 波特率
#define BSP_SPI_CS_PIN GPIO_PIN_6 // SPI 片选引脚
#define BSP_SPI_DC_PIN GPIO_PIN_7 // SPI 数据/命令选择引脚
#define BSP_SPI_RESET_PIN GPIO_PIN_8 // SPI 复位引脚

// 定时器定义 (用于 ADC 采样和波形生成)
#define BSP_TIMER_ADC_SAMPLE TIM1 // 用于 ADC 采样的定时器
#define BSP_TIMER_WAVE_GEN TIM2 // 用于波形生成的定时器

// 初始化 BSP
HAL_StatusTypeDef BSP_Init();

// 读取按键状态
uint8_t BSP_Button_GetState(uint32_t button_pin);

// 读取编码器增量
int16_t BSP_Encoder_GetIncrement();

#endif // BSP_H

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
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
#include "bsp.h"

HAL_StatusTypeDef BSP_Init() {
HAL_StatusTypeDef status = HAL_OK;

// 初始化 GPIO
HAL_GPIO_ConfigTypeDef gpio_config;

// 按键 GPIO 初始化 (输入,上拉)
gpio_config.mode = HAL_GPIO_MODE_INPUT;
gpio_config.pull = HAL_GPIO_PULL_UP;
gpio_config.speed = HAL_GPIO_SPEED_LOW;
gpio_config.pin = BSP_BUTTON_MENU_PIN | BSP_BUTTON_OK_PIN | BSP_BUTTON_CANCEL_PIN |
BSP_ENCODER_A_PIN | BSP_ENCODER_B_PIN | BSP_ENCODER_SW_PIN;
status |= HAL_GPIO_Init(&gpio_config);
if (status != HAL_OK) return status;

// SPI GPIO 初始化 (如果屏幕使用SPI)
// ... (根据实际屏幕 SPI 连接配置 GPIO)

// 初始化 ADC
HAL_ADC_ConfigTypeDef adc_config;
adc_config.channel = BSP_ADC_CHANNEL;
adc_config.resolution = BSP_ADC_RESOLUTION;
adc_config.sampling_rate = BSP_ADC_SAMPLING_RATE;
status |= HAL_ADC_Init(&adc_config);
if (status != HAL_OK) return status;

// 初始化 DAC
HAL_DAC_ConfigTypeDef dac_config;
dac_config.channel = BSP_DAC_CHANNEL;
dac_config.resolution = BSP_DAC_RESOLUTION;
status |= HAL_DAC_Init(&dac_config);
if (status != HAL_OK) return status;

// 初始化 SPI (如果屏幕使用SPI)
// ... (根据实际屏幕 SPI 配置初始化 SPI)

// 初始化定时器 (用于 ADC 采样)
HAL_TIMER_ConfigTypeDef timer_adc_config;
timer_adc_config.prescaler = SYS_CLK_FREQ / BSP_ADC_SAMPLING_RATE - 1; // 计算预分频值
timer_adc_config.period = 1; // 周期为 1,产生频率为 采样率
timer_adc_config.mode = HAL_TIMER_MODE_BASIC;
status |= HAL_TIMER_Init(&timer_adc_config);
if (status != HAL_OK) return status;

// 初始化定时器 (用于波形生成)
// ... (根据波形生成需求配置定时器)

return HAL_OK;
}

uint8_t BSP_Button_GetState(uint32_t button_pin) {
return HAL_GPIO_ReadPin(button_pin);
}

int16_t BSP_Encoder_GetIncrement() {
static int16_t encoder_count = 0;
static uint8_t last_state = 0;

uint8_t current_state = (HAL_GPIO_ReadPin(BSP_ENCODER_A_PIN) << 1) | HAL_GPIO_ReadPin(BSP_ENCODER_B_PIN);

if (current_state != last_state) {
if (current_state == 0b00 && last_state == 0b01) {
encoder_count++; // 顺时针
} else if (current_state == 0b00 && last_state == 0b10) {
encoder_count--; // 逆时针
}
last_state = current_state;
}
return encoder_count;
}

2.3 核心服务层 (Core Services Layer)

adc_service.h:

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

#include <stdint.h>
#include "bsp.h"

#define ADC_BUFFER_SIZE 1024 // ADC 数据缓冲区大小

extern uint16_t adc_buffer[ADC_BUFFER_SIZE];
extern volatile uint32_t adc_buffer_index;

// 初始化 ADC 服务
HAL_StatusTypeDef ADC_Service_Init();

// 获取最新的 ADC 数据缓冲区
uint16_t* ADC_Service_GetBuffer();

// 获取 ADC 数据缓冲区索引
uint32_t ADC_Service_GetBufferIndex();

#endif // ADC_SERVICE_H

adc_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
#include "adc_service.h"
#include "hal_timer.h"

uint16_t adc_buffer[ADC_BUFFER_SIZE];
volatile uint32_t adc_buffer_index = 0;

// ADC 采样完成回调函数
static void ADC_Sample_Callback(uint16_t data) {
adc_buffer[adc_buffer_index++] = data;
if (adc_buffer_index >= ADC_BUFFER_SIZE) {
adc_buffer_index = 0; // 循环缓冲区
}
}

HAL_StatusTypeDef ADC_Service_Init() {
HAL_StatusTypeDef status = HAL_OK;

// 初始化 ADC
status |= HAL_ADC_Start();
if (status != HAL_OK) return status;

// 设置 ADC 采样完成回调函数
status |= HAL_ADC_SetCallback(ADC_Sample_Callback);
if (status != HAL_OK) return status;

// 启动 ADC 采样定时器
status |= HAL_TIMER_Start();
if (status != HAL_OK) return status;

return HAL_OK;
}

uint16_t* ADC_Service_GetBuffer() {
return adc_buffer;
}

uint32_t ADC_Service_GetBufferIndex() {
return adc_buffer_index;
}

wave_gen_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
25
26
27
28
29
30
31
32
33
34
#ifndef WAVE_GEN_SERVICE_H
#define WAVE_GEN_SERVICE_H

#include <stdint.h>
#include "bsp.h"

// 波形类型定义
typedef enum {
WAVE_SINE,
WAVE_SQUARE,
WAVE_TRIANGLE,
WAVE_SAWTOOTH
} WaveTypeTypeDef;

// 波形参数结构体
typedef struct {
WaveTypeTypeDef type; // 波形类型
uint32_t frequency; // 频率 (Hz)
uint16_t amplitude; // 幅度 (0 - MaxValue)
} WaveGen_ParamsTypeDef;

// 初始化波形发生器服务
HAL_StatusTypeDef WaveGen_Service_Init();

// 设置波形参数
HAL_StatusTypeDef WaveGen_Service_SetParams(WaveGen_ParamsTypeDef *params);

// 启动波形发生器
HAL_StatusTypeDef WaveGen_Service_Start();

// 停止波形发生器
HAL_StatusTypeDef WaveGen_Service_Stop();

#endif // WAVE_GEN_SERVICE_H

wave_gen_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
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
122
123
#include "wave_gen_service.h"
#include "math.h" // 用于 sin 函数

#define WAVE_GEN_BUFFER_SIZE 1024 // 波形数据缓冲区大小
uint16_t wave_gen_buffer[WAVE_GEN_BUFFER_SIZE];
WaveGen_ParamsTypeDef current_wave_params;

// 生成正弦波数据
static void GenerateSineWave(WaveGen_ParamsTypeDef *params) {
float frequency = params->frequency;
float amplitude = params->amplitude;
float step = 2 * M_PI * frequency / BSP_ADC_SAMPLING_RATE; // 角度步进值
float angle = 0;

for (uint32_t i = 0; i < WAVE_GEN_BUFFER_SIZE; i++) {
wave_gen_buffer[i] = (uint16_t)((sin(angle) * amplitude) + amplitude); // 偏移到正值范围
angle += step;
if (angle > 2 * M_PI) angle -= 2 * M_PI; // 角度溢出处理
}
}

// 生成方波数据
static void GenerateSquareWave(WaveGen_ParamsTypeDef *params) {
uint16_t high_level = params->amplitude * 2; // 高电平值
uint16_t low_level = 0; // 低电平值
uint32_t half_period_samples = BSP_ADC_SAMPLING_RATE / (2 * params->frequency); // 半周期采样点数

for (uint32_t i = 0; i < WAVE_GEN_BUFFER_SIZE; i++) {
if ((i / half_period_samples) % 2 == 0) {
wave_gen_buffer[i] = high_level;
} else {
wave_gen_buffer[i] = low_level;
}
}
}

// 生成三角波数据
static void GenerateTriangleWave(WaveGen_ParamsTypeDef *params) {
uint16_t amplitude = params->amplitude * 2; // 最大值
uint32_t period_samples = BSP_ADC_SAMPLING_RATE / params->frequency; // 周期采样点数
float step = (float)amplitude / (period_samples / 2.0f); // 上升/下降步进值

for (uint32_t i = 0; i < WAVE_GEN_BUFFER_SIZE; i++) {
uint32_t phase = i % period_samples;
if (phase < period_samples / 2) {
wave_gen_buffer[i] = (uint16_t)(phase * step); // 上升阶段
} else {
wave_gen_buffer[i] = (uint16_t)(amplitude - (phase - period_samples / 2) * step); // 下降阶段
}
}
}

// 生成锯齿波数据
static void GenerateSawtoothWave(WaveGen_ParamsTypeDef *params) {
uint16_t amplitude = params->amplitude * 2; // 最大值
uint32_t period_samples = BSP_ADC_SAMPLING_RATE / params->frequency; // 周期采样点数
float step = (float)amplitude / period_samples; // 上升步进值

for (uint32_t i = 0; i < WAVE_GEN_BUFFER_SIZE; i++) {
wave_gen_buffer[i] = (uint16_t)((i % period_samples) * step); // 上升阶段
}
}


// 波形发生器定时器回调函数 (PWM 模式模拟 DAC 输出)
static void WaveGen_Timer_Callback() {
static uint32_t wave_index = 0;
uint16_t pwm_duty_cycle = wave_gen_buffer[wave_index];

HAL_TIMER_SetPWMDutyCycle(0, pwm_duty_cycle * 100 / ((1 << BSP_DAC_RESOLUTION) - 1)); // 假设 PWM 精度为 100
wave_index++;
if (wave_index >= WAVE_GEN_BUFFER_SIZE) {
wave_index = 0; // 循环缓冲区
}
}


HAL_StatusTypeDef WaveGen_Service_Init() {
HAL_StatusTypeDef status = HAL_OK;

// 初始化波形生成定时器 (PWM 模式)
HAL_TIMER_ConfigTypeDef timer_wave_config;
timer_wave_config.prescaler = SYS_CLK_FREQ / BSP_ADC_SAMPLING_RATE / WAVE_GEN_BUFFER_SIZE - 1; // 计算预分频值, 保证输出频率
timer_wave_config.period = 100; // PWM 周期 (假设 PWM 精度为 100)
timer_wave_config.mode = HAL_TIMER_MODE_PWM;
status |= HAL_TIMER_Init(&timer_wave_config);
if (status != HAL_OK) return status;

// 设置波形生成定时器回调函数
status |= HAL_TIMER_SetCallback(WaveGen_Timer_Callback);
if (status != HAL_OK) return status;

return HAL_OK;
}

HAL_StatusTypeDef WaveGen_Service_SetParams(WaveGen_ParamsTypeDef *params) {
current_wave_params = *params;
switch (params->type) {
case WAVE_SINE:
GenerateSineWave(params);
break;
case WAVE_SQUARE:
GenerateSquareWave(params);
break;
case WAVE_TRIANGLE:
GenerateTriangleWave(params);
break;
case WAVE_SAWTOOTH:
GenerateSawtoothWave(params);
break;
default:
return HAL_ERROR;
}
return HAL_OK;
}

HAL_StatusTypeDef WaveGen_Service_Start() {
return HAL_TIMER_Start();
}

HAL_StatusTypeDef WaveGen_Service_Stop() {
return HAL_TIMER_Stop();
}

display_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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#ifndef DISPLAY_SERVICE_H
#define DISPLAY_SERVICE_H

#include <stdint.h>
#include "bsp.h"

// 显示颜色定义
#define COLOR_BLACK 0x0000
#define COLOR_WHITE 0xFFFF
#define COLOR_RED 0xF800
#define COLOR_GREEN 0x07E0
#define COLOR_BLUE 0x001F
#define COLOR_YELLOW 0xFFE0

// 初始化显示服务
HAL_StatusTypeDef Display_Service_Init();

// 清屏
HAL_StatusTypeDef Display_Service_ClearScreen(uint16_t color);

// 画点
HAL_StatusTypeDef Display_Service_DrawPixel(uint16_t x, uint16_t y, uint16_t color);

// 画线
HAL_StatusTypeDef Display_Service_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

// 画矩形
HAL_StatusTypeDef Display_Service_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

// 填充矩形
HAL_StatusTypeDef Display_Service_FillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

// 显示字符
HAL_StatusTypeDef Display_Service_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bgcolor);

// 显示字符串
HAL_StatusTypeDef Display_Service_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bgcolor);

// 绘制波形
HAL_StatusTypeDef Display_Service_DrawWaveform(uint16_t *data, uint32_t data_len, uint16_t x_offset, uint16_t y_offset, uint16_t color);

#endif // DISPLAY_SERVICE_H

display_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
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
#include "display_service.h"
#include "font.h" // 假设包含字体数据
#include "string.h" // 用于 strlen

// 屏幕尺寸 (假设为 240x320)
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320

HAL_StatusTypeDef Display_Service_Init() {
// 初始化屏幕驱动 (例如,SPI 初始化,屏幕复位等)
// ... (根据实际屏幕驱动初始化代码)
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_ClearScreen(uint16_t color) {
// 填充整个屏幕为指定颜色
Display_Service_FillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, color);
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_DrawPixel(uint16_t x, uint16_t y, uint16_t color) {
// 设置指定坐标像素颜色
// ... (根据实际屏幕驱动写像素代码)
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
// Bresenham's line algorithm (或其他画线算法)
int16_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
int16_t dy = abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
int16_t err = (dx > dy ? dx : -dy) / 2, e2;

for (;;) {
Display_Service_DrawPixel(x1, y1, color);
if (x1 == x2 && y1 == y2) break;
e2 = err;
if (e2 > -dx) { err -= dy; x1 += sx; }
if (e2 < dy) { err += dx; y1 += sy; }
}
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
// 画矩形边框
Display_Service_DrawLine(x1, y1, x2, y1, color); // 上边
Display_Service_DrawLine(x2, y1, x2, y2, color); // 右边
Display_Service_DrawLine(x2, y2, x1, y2, color); // 下边
Display_Service_DrawLine(x1, y2, x1, y1, color); // 左边
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_FillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
// 填充矩形
for (uint16_t x = x1; x <= x2; x++) {
for (uint16_t y = y1; y <= y2; y++) {
Display_Service_DrawPixel(x, y, color);
}
}
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bgcolor) {
// 基于字体数据绘制字符
if (ch < ' ' || ch > '~') ch = '?'; // 限制字符范围
const uint8_t *font_data = &font8x16_ascii[(ch - ' ') * 16]; // 假设字体是 8x16

for (uint8_t row = 0; row < 16; row++) {
for (uint8_t col = 0; col < 8; col++) {
if ((font_data[row] >> col) & 0x01) {
Display_Service_DrawPixel(x + (7 - col), y + row, color);
} else {
Display_Service_DrawPixel(x + (7 - col), y + row, bgcolor); // 背景色
}
}
}
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bgcolor) {
// 绘制字符串
uint16_t current_x = x;
while (*str) {
Display_Service_DrawChar(current_x, y, *str, color, bgcolor);
current_x += 8; // 字符宽度 (假设 8 像素)
str++;
}
return HAL_OK;
}

HAL_StatusTypeDef Display_Service_DrawWaveform(uint16_t *data, uint32_t data_len, uint16_t x_offset, uint16_t y_offset, uint16_t color) {
// 绘制波形
if (data == NULL || data_len == 0) return HAL_ERROR;

uint16_t prev_y = y_offset + SCREEN_HEIGHT / 2 - data[0] * (SCREEN_HEIGHT / 2) / ((1 << BSP_ADC_RESOLUTION) - 1); // 缩放和偏移
for (uint32_t i = 1; i < data_len; i++) {
uint16_t current_x = x_offset + i;
uint16_t current_y = y_offset + SCREEN_HEIGHT / 2 - data[i] * (SCREEN_HEIGHT / 2) / ((1 << BSP_ADC_RESOLUTION) - 1); // 缩放和偏移
Display_Service_DrawLine(current_x - 1 + x_offset, prev_y, current_x + x_offset, current_y, color);
prev_y = current_y;
if (current_x + x_offset >= SCREEN_WIDTH) break; // 超出屏幕宽度停止绘制
}
return HAL_OK;
}

input_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
25
26
#ifndef INPUT_SERVICE_H
#define INPUT_SERVICE_H

#include <stdint.h>
#include "bsp.h"

// 按键事件类型
typedef enum {
BUTTON_MENU_PRESS,
BUTTON_OK_PRESS,
BUTTON_CANCEL_PRESS,
ENCODER_CW, // 编码器顺时针旋转
ENCODER_CCW, // 编码器逆时针旋转
ENCODER_SW_PRESS
} InputEventTypeTypeDef;

// 输入事件回调函数类型
typedef void (*InputEventCallbackTypeDef)(InputEventTypeTypeDef event);

// 初始化输入服务
HAL_StatusTypeDef Input_Service_Init(InputEventCallbackTypeDef callback);

// 输入服务轮询 (在主循环中调用)
void Input_Service_Poll();

#endif // INPUT_SERVICE_H

input_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
#include "input_service.h"

InputEventCallbackTypeDef input_callback;

HAL_StatusTypeDef Input_Service_Init(InputEventCallbackTypeDef callback) {
input_callback = callback;
return HAL_OK;
}

void Input_Service_Poll() {
static uint8_t last_menu_state = 1; // 假设按键默认高电平
static uint8_t last_ok_state = 1;
static uint8_t last_cancel_state = 1;
static int16_t last_encoder_count = 0;
static uint8_t last_encoder_sw_state = 1;

// 按键检测
uint8_t menu_state = BSP_Button_GetState(BSP_BUTTON_MENU_PIN);
uint8_t ok_state = BSP_Button_GetState(BSP_BUTTON_OK_PIN);
uint8_t cancel_state = BSP_Button_GetState(BSP_BUTTON_CANCEL_PIN);
uint8_t encoder_sw_state = BSP_Button_GetState(BSP_ENCODER_SW_PIN);

if (menu_state == 0 && last_menu_state == 1) { // 按键按下 (低电平有效)
if (input_callback) input_callback(BUTTON_MENU_PRESS);
}
last_menu_state = menu_state;

if (ok_state == 0 && last_ok_state == 1) {
if (input_callback) input_callback(BUTTON_OK_PRESS);
}
last_ok_state = ok_state;

if (cancel_state == 0 && last_cancel_state == 1) {
if (input_callback) input_callback(BUTTON_CANCEL_PRESS);
}
last_cancel_state = cancel_state;

if (encoder_sw_state == 0 && last_encoder_sw_state == 1) {
if (input_callback) input_callback(ENCODER_SW_PRESS);
}
last_encoder_sw_state = encoder_sw_state;

// 编码器检测
int16_t current_encoder_count = BSP_Encoder_GetIncrement();
int16_t increment = current_encoder_count - last_encoder_count;
if (increment > 0) {
if (input_callback) {
for (int i = 0; i < increment; i++) { // 处理多次增量
input_callback(ENCODER_CW);
}
}
} else if (increment < 0) {
if (input_callback) {
for (int i = 0; i < -increment; i++) { // 处理多次减量
input_callback(ENCODER_CCW);
}
}
}
last_encoder_count = current_encoder_count;
}

2.4 应用层 (Application Layer)

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
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include "bsp.h"
#include "adc_service.h"
#include "wave_gen_service.h"
#include "display_service.h"
#include "input_service.h"
#include "stdio.h" // 用于 sprintf

// 系统状态定义
typedef enum {
STATE_OSCILLOSCOPE,
STATE_WAVE_GENERATOR,
STATE_MENU
} SystemStateTypeTypeDef;

SystemStateTypeTypeDef current_state = STATE_OSCILLOSCOPE; // 初始状态为示波器模式

// 示波器参数
typedef struct {
float vertical_scale; // 垂直刻度 (V/div)
float horizontal_scale; // 水平刻度 (us/div)
uint32_t trigger_level; // 触发电平
} OscilloscopeParamsTypeDef;

OscilloscopeParamsTypeDef oscilloscope_params = {
.vertical_scale = 1.0f,
.horizontal_scale = 100.0f,
.trigger_level = 1024
};

// 波形发生器参数
WaveGen_ParamsTypeDef wave_generator_params = {
.type = WAVE_SINE,
.frequency = 1000,
.amplitude = 2048 // 满量程一半
};

// UI 菜单项
typedef struct {
const char *name;
// ... (可以添加菜单项对应的操作函数指针)
} MenuItemTypeDef;

MenuItemTypeDef main_menu[] = {
{"Oscilloscope"},
{"Wave Generator"},
{"Settings"},
{"About"},
{NULL} // 菜单结束标志
};

uint32_t menu_index = 0; // 当前菜单项索引

// 输入事件处理回调函数
void HandleInputEvent(InputEventTypeTypeDef event) {
switch (current_state) {
case STATE_OSCILLOSCOPE:
HandleOscilloscopeInput(event);
break;
case STATE_WAVE_GENERATOR:
HandleWaveGeneratorInput(event);
break;
case STATE_MENU:
HandleMenuInput(event);
break;
default:
break;
}
}

// 示波器模式输入处理
void HandleOscilloscopeInput(InputEventTypeTypeDef event) {
switch (event) {
case BUTTON_MENU_PRESS:
current_state = STATE_MENU; // 进入菜单
menu_index = 0; // 菜单索引复位
break;
case ENCODER_CW:
oscilloscope_params.vertical_scale *= 1.1f; // 增大垂直刻度
if (oscilloscope_params.vertical_scale > 10.0f) oscilloscope_params.vertical_scale = 10.0f;
break;
case ENCODER_CCW:
oscilloscope_params.vertical_scale /= 1.1f; // 减小垂直刻度
if (oscilloscope_params.vertical_scale < 0.1f) oscilloscope_params.vertical_scale = 0.1f;
break;
case BUTTON_OK_PRESS:
// ... (触发模式切换或其他操作)
break;
case BUTTON_CANCEL_PRESS:
// ... (复位参数或其他操作)
break;
default:
break;
}
}

// 波形发生器模式输入处理
void HandleWaveGeneratorInput(InputEventTypeTypeDef event) {
switch (event) {
case BUTTON_MENU_PRESS:
current_state = STATE_MENU; // 进入菜单
menu_index = 1; // 菜单索引复位到波形发生器菜单项
break;
case ENCODER_CW:
wave_generator_params.frequency += 100; // 增大频率
if (wave_generator_params.frequency > 10000) wave_generator_params.frequency = 10000;
WaveGen_Service_SetParams(&wave_generator_params); // 更新波形
break;
case ENCODER_CCW:
wave_generator_params.frequency -= 100; // 减小频率
if (wave_generator_params.frequency < 100) wave_generator_params.frequency = 100;
WaveGen_Service_SetParams(&wave_generator_params); // 更新波形
break;
case BUTTON_OK_PRESS:
// ... (切换波形类型或其他操作)
break;
case BUTTON_CANCEL_PRESS:
// ... (停止/启动波形输出或其他操作)
break;
default:
break;
}
}

// 菜单模式输入处理
void HandleMenuInput(InputEventTypeTypeDef event) {
switch (event) {
case BUTTON_MENU_PRESS:
current_state = (menu_index == 0) ? STATE_OSCILLOSCOPE : STATE_WAVE_GENERATOR; // 返回上一个状态
break;
case ENCODER_CW:
menu_index++;
if (main_menu[menu_index].name == NULL) menu_index = 0; // 循环菜单
break;
case ENCODER_CCW:
if (menu_index == 0) {
// 找到最后一个菜单项的索引
uint32_t last_menu_index = 0;
while (main_menu[last_menu_index].name != NULL) last_menu_index++;
menu_index = last_menu_index - 1;
} else {
menu_index--;
}
break;
case BUTTON_OK_PRESS:
if (strcmp(main_menu[menu_index].name, "Oscilloscope") == 0) {
current_state = STATE_OSCILLOSCOPE;
} else if (strcmp(main_menu[menu_index].name, "Wave Generator") == 0) {
current_state = STATE_WAVE_GENERATOR;
} else if (strcmp(main_menu[menu_index].name, "Settings") == 0) {
// ... (进入设置菜单)
} else if (strcmp(main_menu[menu_index].name, "About") == 0) {
// ... (显示关于信息)
}
break;
case BUTTON_CANCEL_PRESS:
current_state = (menu_index == 0) ? STATE_OSCILLOSCOPE : STATE_WAVE_GENERATOR; // 返回上一个状态
break;
default:
break;
}
}


void System_Init() {
BSP_Init(); // 初始化 BSP
Display_Service_Init(); // 初始化显示服务
ADC_Service_Init(); // 初始化 ADC 服务
WaveGen_Service_Init(); // 初始化波形发生器服务
Input_Service_Init(HandleInputEvent); // 初始化输入服务,设置回调函数

WaveGen_Service_SetParams(&wave_generator_params); // 设置初始波形参数
}

void System_Run() {
uint16_t *adc_data;
char text_buffer[64];

while (1) {
Input_Service_Poll(); // 轮询输入事件

Display_Service_ClearScreen(COLOR_BLACK); // 清屏

switch (current_state) {
case STATE_OSCILLOSCOPE:
// 绘制示波器界面
Display_Service_DrawString(10, 10, "Oscilloscope Mode", COLOR_GREEN, COLOR_BLACK);

adc_data = ADC_Service_GetBuffer();
Display_Service_DrawWaveform(adc_data, ADC_BUFFER_SIZE, 10, 50, COLOR_GREEN); // 绘制波形

sprintf(text_buffer, "V/div: %.2fV", oscilloscope_params.vertical_scale);
Display_Service_DrawString(10, 200, text_buffer, COLOR_WHITE, COLOR_BLACK);
sprintf(text_buffer, "Time/div: %.2fus", oscilloscope_params.horizontal_scale);
Display_Service_DrawString(10, 220, text_buffer, COLOR_WHITE, COLOR_BLACK);

break;

case STATE_WAVE_GENERATOR:
// 绘制波形发生器界面
Display_Service_DrawString(10, 10, "Wave Generator Mode", COLOR_BLUE, COLOR_BLACK);
Display_Service_DrawString(10, 30, "Outputting Waveform:", COLOR_WHITE, COLOR_BLACK);

switch (wave_generator_params.type) {
case WAVE_SINE: Display_Service_DrawString(150, 30, "Sine", COLOR_YELLOW, COLOR_BLACK); break;
case WAVE_SQUARE: Display_Service_DrawString(150, 30, "Square", COLOR_YELLOW, COLOR_BLACK); break;
case WAVE_TRIANGLE: Display_Service_DrawString(150, 30, "Triangle", COLOR_YELLOW, COLOR_BLACK); break;
case WAVE_SAWTOOTH: Display_Service_DrawString(150, 30, "Sawtooth", COLOR_YELLOW, COLOR_BLACK); break;
}

sprintf(text_buffer, "Freq: %luHz", wave_generator_params.frequency);
Display_Service_DrawString(10, 50, text_buffer, COLOR_WHITE, COLOR_BLACK);
sprintf(text_buffer, "Ampl: %d", wave_generator_params.amplitude);
Display_Service_DrawString(10, 70, text_buffer, COLOR_WHITE, COLOR_BLACK);

break;

case STATE_MENU:
// 绘制菜单界面
Display_Service_DrawString(10, 10, "Main Menu", COLOR_WHITE, COLOR_BLACK);
for (uint32_t i = 0; main_menu[i].name != NULL; i++) {
uint16_t text_color = (i == menu_index) ? COLOR_YELLOW : COLOR_WHITE; // 选中项高亮
Display_Service_DrawString(20, 30 + i * 20, main_menu[i].name, text_color, COLOR_BLACK);
}
break;

default:
break;
}

// 延迟一段时间,控制帧率 (例如 20ms 刷新一次)
// HAL_Delay(20); // 需要实现 HAL_Delay 函数,例如基于 SysTick 定时器
}
}

int main() {
System_Init();
System_Run();

return 0;
}

2.5 状态机和事件驱动

在应用层代码中,我们使用了状态机来管理系统的不同模式(示波器模式、波形发生器模式、菜单模式)。通过 current_state 变量来记录当前系统所处的状态,并根据不同的状态执行不同的逻辑。

同时,我们采用了事件驱动的方式来处理用户输入。Input_Service_Poll() 函数定期轮询按键和编码器状态,当检测到输入事件时,通过回调函数 HandleInputEvent() 将事件传递给应用层进行处理。这种方式能够有效地响应用户操作,并保持系统的实时性。

3. 测试验证和维护升级

3.1 测试验证

为了保证系统的可靠性和功能正确性,我们需要进行全面的测试验证,包括:

  • 单元测试: 针对HAL层、BSP层、核心服务层中的各个模块进行单元测试,验证每个模块的功能是否正常,例如:

    • ADC驱动单元测试:验证ADC采样精度、采样率是否符合要求。
    • DAC驱动单元测试:验证DAC输出电压精度、波形生成是否正确。
    • 显示驱动单元测试:验证屏幕显示是否正常,画点、画线、显示字符等功能是否正确。
    • 输入处理单元测试:验证按键和编码器输入是否能够正确检测和处理。
  • 集成测试: 将各个模块组合起来进行集成测试,验证模块之间的协同工作是否正常,例如:

    • 示波器功能测试:验证示波器模式下,模拟信号采集、波形显示、参数调整等功能是否正常工作。
    • 波形发生器功能测试:验证波形发生器模式下,波形生成、波形输出、参数调整等功能是否正常工作。
    • 用户界面测试:验证菜单导航、参数设置、模式切换等用户界面功能是否易用和正确。
  • 系统测试: 进行长时间运行测试、稳定性测试、边界条件测试等系统级测试,验证系统的整体可靠性和稳定性。

3.2 维护升级

为了保证系统的长期可用性和适应新的需求,我们需要考虑系统的维护升级:

  • 模块化设计: 分层架构和模块化设计使得系统易于维护和升级。当需要修改或添加新功能时,只需要修改或添加相应的模块,而不需要修改整个系统。

  • 清晰的代码注释: 良好的代码注释能够提高代码的可读性和可维护性,方便后续开发人员理解和修改代码。

  • 版本控制: 使用版本控制系统(例如 Git)来管理代码,方便代码的版本管理、回溯和协作开发。

  • 固件升级机制: 预留固件升级接口和程序,方便用户或工程师进行固件升级,修复 bug 或添加新功能。常用的固件升级方式包括:

    • 串口升级: 通过串口接收新的固件程序并烧写到 Flash 存储器中。
    • USB升级: 通过 USB 接口连接到上位机,使用上位机软件进行固件升级。
    • OTA (Over-The-Air) 升级: 通过无线网络(例如 Wi-Fi 或蓝牙)接收新的固件程序并进行升级(对于支持无线功能的嵌入式系统)。

4. 总结

立创·梁山派-示波器扩展板项目采用分层架构和事件驱动的设计模式,构建了一个可靠、高效、可扩展的嵌入式示波器系统。代码实现从硬件抽象层 (HAL) 开始,逐步向上构建板级支持包 (BSP)、核心服务层和应用层,最终实现了示波器和波形发生器的核心功能。通过详细的代码注释和模块化设计,系统具有良好的可读性、可维护性和可扩展性。

为了保证系统的质量,我们还需要进行全面的测试验证,并建立完善的维护升级机制,以确保系统的长期稳定运行和持续改进。

这仅仅是一个基础的框架和示例代码,实际的项目开发还需要根据具体的硬件平台、功能需求和性能指标进行更详细的设计和实现。例如,可以考虑使用更高级的GUI库来构建更美观、更易用的用户界面,可以添加更高级的触发模式和测量功能,可以优化 ADC 采样和波形显示的性能等等。

希望这个详细的架构设计和代码示例能够帮助您理解嵌入式系统开发流程,并为您的项目提供参考。如果您有任何疑问或需要进一步的帮助,请随时提出。
Error executing command: Traceback (most recent call last):
File “/home/tong/bin/desc_img3.py”, line 73, in
for chunk in client.models.generate_content_stream(
File “/home/tong/.local/lib/python3.10/site-packages/google/genai/models.py”, line 3722, in generate_content_stream
for response_dict in self.api_client.request_streamed(
File “/home/tong/.local/lib/python3.10/site-packages/google/genai/_api_client.py”, line 344, in request_streamed
for chunk in session_response.segments():
File “/home/tong/.local/lib/python3.10/site-packages/google/genai/_api_client.py”, line 133, in segments
yield json.loads(str(chunk, ‘utf-8’))
File “/usr/lib/python3.10/json/init.py”, line 346, in loads
return _default_decoder.decode(s)
File “/usr/lib/python3.10/json/decoder.py”, line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File “/usr/lib/python3.10/json/decoder.py”, line 353, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

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