ESP32 DAC连续DMA模式下双通道输出不同信号的实现问题
解决ESP32 DAC连续模式双通道输出不同信号(正弦/余弦90°相位差)的问题
问题根源分析
你当前的问题出在波形生成的索引逻辑错误:在DAC_CHANNEL_MODE_ALTER模式下,通道0会读取缓冲区的偶数索引(0、2、4...),通道1读取奇数索引(1、3、5...),但你直接用循环变量i作为相位计算参数,导致两个通道的采样点相位并非连续的90°偏移,反而因采样间隔问题导致输出信号重叠,最终看起来完全相同。
同时需要确认freq_hz的计算逻辑是否匹配期望的输出频率。
修正步骤
1. 修正波形生成函数
重新设计缓冲区填充逻辑:将正弦波的连续采样点依次放在缓冲区偶数位置,余弦波(与正弦波相位差90°)的连续采样点放在奇数位置。这样通道0会完整输出正弦波,通道1完整输出余弦波。
修改后的generate_waves函数:
void generate_waves(void) { // 每个通道的有效采样点数是总长度的一半 int half_len = EXAMPLE_ARRAY_LEN / 2; for (int k = 0; k < half_len; k++) { // 计算当前采样点的相位(0~2π) float phase = 2 * M_PI * k / half_len; // 通道0(偶数索引):正弦波 signal_wave[2 * k] = (uint8_t)(amplitude / 2.0 * (1 + sin(phase))); // 通道1(奇数索引):余弦波(相位偏移π/2) signal_wave[2 * k + 1] = (uint8_t)(amplitude / 2.0 * (1 + cos(phase))); } }
2. 确认DAC连续模式配置正确性
确保chan_mode设置为DAC_CHANNEL_MODE_ALTER,同时修正freq_hz计算逻辑:
cont_cfg = { .chan_mask = DAC_CHANNEL_MASK_ALL, .desc_num = 2, .buf_size = 2048, // 采样率 = 目标信号频率 × 每个周期的采样点数(half_len) .freq_hz = frequency_Hz * (EXAMPLE_ARRAY_LEN / 2), .offset = 0, .clk_src = DAC_DIGI_CLK_SRC_DEFAULT, .chan_mode = DAC_CHANNEL_MODE_ALTER, // 必须确保模式正确 };
这里freq_hz是DAC的采样率,每个通道的信号频率 = 采样率 / 每个通道的采样点数(即EXAMPLE_ARRAY_LEN/2),计算后可得到你传入的frequency_Hz目标频率。
3. 添加调试验证
在配置完成后打印关键参数,确认配置生效:
Serial.printf("DAC配置完成:信号频率=%dHz,采样率=%dHz,通道模式=ALTER\n", frequency_Hz, cont_cfg.freq_hz);
完整修正后的DAC_Continuous_DMA.h
#pragma once #ifndef DAC_Continuous_DMA_h #define DAC_Continuous_DMA_h #include "Arduino.h" #include <math.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "soc/dac_channel.h" #include "driver/dac_continuous.h" #include "soc/sens_reg.h" #define EXAMPLE_ARRAY_LEN 512 // 总缓冲区长度(必须为偶数,保证双通道采样点数相等) #define EXAMPLE_DAC_AMPLITUDE 255 // DAC最大幅值(8位精度,0~255) _Static_assert(EXAMPLE_DAC_AMPLITUDE < 256, "DAC为8位精度,幅值不能超过255"); _Static_assert(EXAMPLE_ARRAY_LEN % 2 == 0, "缓冲区长度必须为偶数,保证两个通道采样点数一致"); dac_continuous_config_t cont_cfg; uint8_t signal_wave[EXAMPLE_ARRAY_LEN]; uint8_t amplitude = EXAMPLE_DAC_AMPLITUDE; dac_continuous_handle_t cont_handle = NULL; void generate_waves(void) { int half_len = EXAMPLE_ARRAY_LEN / 2; for (int k = 0; k < half_len; k++) { float phase = 2 * M_PI * k / half_len; // 通道0:正弦波 signal_wave[2 * k] = (uint8_t)(amplitude / 2.0 * (1 + sin(phase))); // 通道1:余弦波(相位差90°) signal_wave[2 * k + 1] = (uint8_t)(amplitude / 2.0 * (1 + cos(phase))); } } void dac_continuous_dma_config(uint32_t frequency_Hz = 1000) { generate_waves(); int half_len = EXAMPLE_ARRAY_LEN / 2; cont_cfg = { .chan_mask = DAC_CHANNEL_MASK_ALL, .desc_num = 2, .buf_size = 2048, .freq_hz = frequency_Hz * half_len, .offset = 0, .clk_src = DAC_DIGI_CLK_SRC_DEFAULT, .chan_mode = DAC_CHANNEL_MODE_ALTER, }; ESP_ERROR_CHECK(dac_continuous_new_channels(&cont_cfg, &cont_handle)); ESP_ERROR_CHECK(dac_continuous_enable(cont_handle)); ESP_ERROR_CHECK(dac_continuous_write_cyclically(cont_handle, signal_wave, EXAMPLE_ARRAY_LEN, NULL)); // 调试打印 Serial.printf("DAC配置完成:信号频率=%dHz,采样率=%dHz,通道模式=ALTER\n", frequency_Hz, cont_cfg.freq_hz); } #endif // DAC_Continuous_DMA_h
关键注意事项
EXAMPLE_ARRAY_LEN必须设置为偶数,保证两个通道的采样点数完全一致,避免波形错位。- 使用
amplitude / 2.0而非整数除法,避免精度丢失导致波形幅值不正确。 - 如果目标频率超出
DAC_DIGI_CLK_SRC_DEFAULT范围,可切换为DAC_DIGI_CLK_SRC_APLL以支持更高采样率。
内容的提问来源于stack exchange,提问作者Andrei Krivoshei
相关产品推荐
相关产品推荐

