2025-09-25 18:50:48 +08:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#include "esp32_s3_szp.h"
|
|
|
|
|
|
#include "app_ui.h"
|
|
|
|
|
|
#include <esp_system.h>
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
#include "ecg_generator.h"
|
2025-09-26 14:16:44 +08:00
|
|
|
|
#include "sine_generator.h"
|
2025-09-25 18:50:48 +08:00
|
|
|
|
#include "esp_timer.h"
|
|
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
|
|
#include "freertos/task.h"
|
2025-09-26 14:16:44 +08:00
|
|
|
|
#include "driver/gpio.h"
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
EventGroupHandle_t my_event_group;
|
|
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 按键定义
|
|
|
|
|
|
#define BUTTON_PIN GPIO_NUM_0 // 使用GPIO0作为按键输入
|
|
|
|
|
|
#define BUTTON_DEBOUNCE_MS 200 // 防抖时间
|
|
|
|
|
|
|
2025-09-25 18:50:48 +08:00
|
|
|
|
static const char *TAG = "MAIN";
|
|
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 信号生成器相关
|
2025-09-25 18:50:48 +08:00
|
|
|
|
static ecg_generator_t g_ecg_gen;
|
2025-09-26 14:16:44 +08:00
|
|
|
|
static sine_generator_t g_sine_gen;
|
|
|
|
|
|
static esp_timer_handle_t signal_timer = NULL;
|
|
|
|
|
|
static uint32_t signal_sample_count = 0;
|
|
|
|
|
|
static uint32_t signal_last_log_time = 0;
|
|
|
|
|
|
static bool use_sine_wave = true; // true=正弦波, false=ECG
|
|
|
|
|
|
|
|
|
|
|
|
// 信号生成器定时器回调函数
|
|
|
|
|
|
static void signal_timer_callback(void* arg) {
|
|
|
|
|
|
float signal_voltage = 0.0f;
|
|
|
|
|
|
|
|
|
|
|
|
if (use_sine_wave) {
|
|
|
|
|
|
// 生成正弦波样本
|
|
|
|
|
|
signal_voltage = sine_generator_get_next_sample(&g_sine_gen);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 生成ECG样本
|
|
|
|
|
|
signal_voltage = ecg_generator_get_next_sample(&g_ecg_gen);
|
|
|
|
|
|
}
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 输出到DAC通道2
|
2025-09-26 14:16:44 +08:00
|
|
|
|
set_channel_voltage(2, signal_voltage);
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
signal_sample_count++;
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 减少日志输出频率,避免影响高频中断性能
|
|
|
|
|
|
// 每20000个样本输出一次统计信息(约1秒)
|
|
|
|
|
|
if (signal_sample_count >= 20000) {
|
|
|
|
|
|
ESP_LOGI(TAG, "Generated %u samples at 20kHz (%s)",
|
|
|
|
|
|
signal_sample_count, use_sine_wave ? "Sine Wave" : "ECG");
|
|
|
|
|
|
signal_sample_count = 0;
|
|
|
|
|
|
signal_last_log_time = esp_timer_get_time() / 1000;
|
2025-09-25 18:50:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 函数声明
|
|
|
|
|
|
void displayMemoryUsage(void);
|
2025-09-26 14:16:44 +08:00
|
|
|
|
void test_signal_generation(void);
|
|
|
|
|
|
void switch_to_ecg_mode(void);
|
|
|
|
|
|
void switch_to_sine_mode(void);
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 信号生成器测试函数
|
|
|
|
|
|
void test_signal_generation(void) {
|
|
|
|
|
|
ESP_LOGI(TAG, "=== Signal Generation Test ===");
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化ECG生成器
|
2025-09-26 14:16:44 +08:00
|
|
|
|
ecg_generator_init(&g_ecg_gen, 20000.0f); // 20kHz生成率
|
|
|
|
|
|
ecg_param_set(&g_ecg_gen, 5.0f, 75.0f);
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 初始化正弦波生成器
|
|
|
|
|
|
sine_generator_init(&g_sine_gen, 20000.0f); // 20kHz生成率
|
|
|
|
|
|
sine_generator_set_frequency(&g_sine_gen, 10.0f); // 100Hz正弦波
|
|
|
|
|
|
sine_generator_set_amplitude(&g_sine_gen, 5.0f); // 5mV
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 创建定时器配置
|
|
|
|
|
|
const esp_timer_create_args_t timer_args = {
|
2025-09-26 14:16:44 +08:00
|
|
|
|
.callback = &signal_timer_callback,
|
|
|
|
|
|
.name = "signal_timer"
|
2025-09-25 18:50:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 创建定时器
|
2025-09-26 14:16:44 +08:00
|
|
|
|
esp_err_t ret = esp_timer_create(&timer_args, &signal_timer);
|
2025-09-25 18:50:48 +08:00
|
|
|
|
if (ret != ESP_OK) {
|
2025-09-26 14:16:44 +08:00
|
|
|
|
ESP_LOGE(TAG, "Failed to create signal timer: %s", esp_err_to_name(ret));
|
2025-09-25 18:50:48 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 启动信号生成器
|
|
|
|
|
|
if (use_sine_wave) {
|
|
|
|
|
|
sine_generator_start(&g_sine_gen);
|
|
|
|
|
|
ESP_LOGI(TAG, "Started sine wave generator: 100Hz, 5mV");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ecg_generator_start(&g_ecg_gen);
|
|
|
|
|
|
ESP_LOGI(TAG, "Started ECG generator: 75 BPM, 5mV");
|
|
|
|
|
|
}
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 启动定时器 (50us = 20kHz)
|
|
|
|
|
|
ret = esp_timer_start_periodic(signal_timer, 50); // 50微秒 = 20kHz
|
2025-09-25 18:50:48 +08:00
|
|
|
|
if (ret != ESP_OK) {
|
2025-09-26 14:16:44 +08:00
|
|
|
|
ESP_LOGE(TAG, "Failed to start signal timer: %s", esp_err_to_name(ret));
|
|
|
|
|
|
esp_timer_delete(signal_timer);
|
2025-09-25 18:50:48 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
ESP_LOGI(TAG, "Signal timer started at 20kHz (50us period)");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换到ECG模式
|
|
|
|
|
|
void switch_to_ecg_mode(void) {
|
|
|
|
|
|
if (use_sine_wave) {
|
|
|
|
|
|
sine_generator_stop(&g_sine_gen);
|
|
|
|
|
|
ecg_generator_start(&g_ecg_gen);
|
|
|
|
|
|
use_sine_wave = false;
|
|
|
|
|
|
ESP_LOGI(TAG, "Switched to ECG mode");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换到正弦波模式
|
|
|
|
|
|
void switch_to_sine_mode(void) {
|
|
|
|
|
|
if (!use_sine_wave) {
|
|
|
|
|
|
ecg_generator_stop(&g_ecg_gen);
|
|
|
|
|
|
sine_generator_start(&g_sine_gen);
|
|
|
|
|
|
use_sine_wave = true;
|
|
|
|
|
|
ESP_LOGI(TAG, "Switched to sine wave mode");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 按键初始化
|
|
|
|
|
|
void button_init(void) {
|
|
|
|
|
|
gpio_config_t io_conf = {};
|
|
|
|
|
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
|
|
|
|
|
io_conf.mode = GPIO_MODE_INPUT;
|
|
|
|
|
|
io_conf.pin_bit_mask = (1ULL << BUTTON_PIN);
|
|
|
|
|
|
io_conf.pull_down_en = 0;
|
|
|
|
|
|
io_conf.pull_up_en = 1; // 启用上拉电阻
|
|
|
|
|
|
gpio_config(&io_conf);
|
|
|
|
|
|
ESP_LOGI(TAG, "Button initialized on GPIO %d", BUTTON_PIN);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检测按键按下
|
|
|
|
|
|
bool button_pressed(void) {
|
|
|
|
|
|
static uint32_t last_press_time = 0;
|
|
|
|
|
|
uint32_t current_time = esp_timer_get_time() / 1000; // 转换为毫秒
|
|
|
|
|
|
|
|
|
|
|
|
// 检测按键按下(低电平)
|
|
|
|
|
|
if (gpio_get_level(BUTTON_PIN) == 0) {
|
|
|
|
|
|
// 防抖处理
|
|
|
|
|
|
if (current_time - last_press_time > BUTTON_DEBOUNCE_MS) {
|
|
|
|
|
|
last_press_time = current_time;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
2025-09-25 18:50:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打印内存使用情况
|
|
|
|
|
|
void displayMemoryUsage() {
|
|
|
|
|
|
size_t totalDRAM = heap_caps_get_total_size(MALLOC_CAP_INTERNAL);
|
|
|
|
|
|
size_t freeDRAM = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
|
|
|
|
|
size_t usedDRAM = totalDRAM - freeDRAM;
|
|
|
|
|
|
|
|
|
|
|
|
size_t totalPSRAM = heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
|
|
|
|
|
|
size_t freePSRAM = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
|
|
|
|
|
size_t usedPSRAM = totalPSRAM - freePSRAM;
|
|
|
|
|
|
|
|
|
|
|
|
size_t DRAM_largest_block = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
|
|
|
|
|
|
size_t PSRAM_largest_block = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
|
|
|
|
|
|
|
|
|
|
|
|
float dramUsagePercentage = (float)usedDRAM / totalDRAM * 100;
|
|
|
|
|
|
float psramUsagePercentage = (float)usedPSRAM / totalPSRAM * 100;
|
|
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "DRAM Total: %zu bytes, Used: %zu bytes, Free: %zu bytes, DRAM_Largest_block: %zu bytes", totalDRAM, usedDRAM, freeDRAM, DRAM_largest_block);
|
|
|
|
|
|
ESP_LOGI(TAG, "DRAM Used: %.2f%%", dramUsagePercentage);
|
|
|
|
|
|
ESP_LOGI(TAG, "PSRAM Total: %zu bytes, Used: %zu bytes, Free: %zu bytes, PSRAM_Largest_block: %zu bytes", totalPSRAM, usedPSRAM, freePSRAM, PSRAM_largest_block);
|
|
|
|
|
|
ESP_LOGI(TAG, "PSRAM Used: %.2f%%", psramUsagePercentage);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 主函数
|
|
|
|
|
|
void app_main(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
ESP_LOGI(TAG, "Starting ECG application...");
|
|
|
|
|
|
|
|
|
|
|
|
// 硬件初始化
|
|
|
|
|
|
bsp_i2c_init(); // I2C初始化
|
|
|
|
|
|
LED_init(); // LED初始化
|
|
|
|
|
|
init_ad5328(); // DAC初始化
|
2025-09-26 14:16:44 +08:00
|
|
|
|
button_init(); // 按键初始化
|
2025-09-25 18:50:48 +08:00
|
|
|
|
my_event_group = xEventGroupCreate();
|
|
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Hardware initialization completed.");
|
|
|
|
|
|
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 启动信号生成
|
|
|
|
|
|
test_signal_generation();
|
2025-09-25 18:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
// LED状态指示
|
|
|
|
|
|
ESP_LOGI(TAG, "Starting LED status indicator...");
|
|
|
|
|
|
int led_count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
while (true) {
|
2025-09-26 14:16:44 +08:00
|
|
|
|
// 检测按键按下
|
|
|
|
|
|
if (button_pressed()) {
|
|
|
|
|
|
if (use_sine_wave) {
|
|
|
|
|
|
switch_to_ecg_mode();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
switch_to_sine_mode();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-25 18:50:48 +08:00
|
|
|
|
// LED闪烁指示系统运行
|
|
|
|
|
|
gpio_set_level(LED_PIN, 1); // LED亮
|
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
|
|
|
|
|
|
|
|
|
|
gpio_set_level(LED_PIN, 0); // LED灭
|
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
|
|
|
|
|
|
|
|
|
|
// 每10次循环显示一次内存使用情况
|
|
|
|
|
|
if (++led_count % 10 == 0) {
|
|
|
|
|
|
displayMemoryUsage();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|