You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:23:13