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

如何编写可灵活修改中间值的For循环实现DAC信号输出程序?

灵活调整DAC输出信号的循环实现示例

核心思路

用动态计算采样值替代固定数组存储,将所有可调参数集中在一处,仅修改单个(或少量)参数即可切换波形、调整频率/幅值,无需手动修改数组内容、循环范围或DMA长度。


实时计算式实现(定时器中断触发,无需预生成数组)

适合低内存占用、灵活调整的场景,通过定时器中断实时计算每个采样点的DAC输出值:

#include "stm32f4xx_hal.h"

// 仅需修改此处的参数即可调整波形/频率/幅值
#define WAVE_TYPE 1          // 1=方波, 2=三角波, 3=锯齿波
#define DAC_MAX_VALUE 4095   // 12位DAC最大值(幅值调整)
#define SIGNAL_FREQ 100      // 目标信号频率(Hz)
#define TIMER_TRIGGER_FREQ 100000  // 定时器中断频率(Hz),控制采样精度

uint32_t current_sample = 0;
uint32_t samples_per_cycle = TIMER_TRIGGER_FREQ / SIGNAL_FREQ;

// 定时器周期中断回调(需对应你使用的定时器实例)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance != TIM2) return;

    uint32_t dac_out = 0;
    // 根据选定波形动态计算输出值
    switch(WAVE_TYPE)
    {
        case 1: // 方波
            dac_out = (current_sample < samples_per_cycle/2) ? DAC_MAX_VALUE : 0;
            break;
        case 2: // 三角波
            if (current_sample < samples_per_cycle/2)
            {
                dac_out = (DAC_MAX_VALUE * 2 * current_sample) / samples_per_cycle;
            }
            else
            {
                dac_out = DAC_MAX_VALUE - ((DAC_MAX_VALUE * 2 * (current_sample - samples_per_cycle/2)) / samples_per_cycle);
            }
            break;
        case 3: // 锯齿波
            dac_out = (DAC_MAX_VALUE * current_sample) / samples_per_cycle;
            break;
        default: // 默认输出低电平
            dac_out = 0;
            break;
    }

    // 更新DAC输出
    HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_out);

    // 循环计数,实现周期重复
    current_sample++;
    if (current_sample >= samples_per_cycle)
    {
        current_sample = 0;
    }
}

// 初始化函数(主函数中调用)
void DAC_Wave_Init(void)
{
    HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
    HAL_TIM_Base_Start_IT(&htim2);
}

DMA批量输出实现(自动生成波形缓冲区)

适合连续稳定输出的场景,通过For循环自动生成对应波形的缓冲区,无需手动编辑数组内容:

#include "stm32f4xx_hal.h"

// 仅需修改此处的参数即可调整波形/频率/幅值
#define WAVE_TYPE 2          // 1=方波, 2=三角波, 3=锯齿波
#define DAC_MAX_VALUE 4095   // 12位DAC最大值(幅值调整)
#define SIGNAL_FREQ 100      // 目标信号频率(Hz)
#define TIMER_TRIGGER_FREQ 100000  // DMA触发频率(Hz)
#define BUFFER_LEN TIMER_TRIGGER_FREQ / SIGNAL_FREQ  // 自动计算缓冲区长度

uint16_t dac_buffer[BUFFER_LEN];

// 自动生成波形缓冲区
void Generate_Wave_Buffer(void)
{
    for (uint32_t i = 0; i < BUFFER_LEN; i++)
    {
        switch(WAVE_TYPE)
        {
            case 1: // 方波
                dac_buffer[i] = (i < BUFFER_LEN/2) ? DAC_MAX_VALUE : 0;
                break;
            case 2: // 三角波
                if (i < BUFFER_LEN/2)
                {
                    dac_buffer[i] = (DAC_MAX_VALUE * 2 * i) / BUFFER_LEN;
                }
                else
                {
                    dac_buffer[i] = DAC_MAX_VALUE - ((DAC_MAX_VALUE * 2 * (i - BUFFER_LEN/2)) / BUFFER_LEN);
                }
                break;
            case 3: // 锯齿波
                dac_buffer[i] = (DAC_MAX_VALUE * i) / BUFFER_LEN;
                break;
            default:
                dac_buffer[i] = 0;
                break;
        }
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DAC_Init();
    MX_TIM2_Init();

    Generate_Wave_Buffer();
    // 启动DMA输出,长度参数直接使用自动计算的BUFFER_LEN
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)dac_buffer, BUFFER_LEN, DAC_ALIGN_12B_R);
    HAL_TIM_Base_Start(&htim2);

    while (1)
    {
        // 主循环无额外操作
    }
}

使用说明

  • 切换波形:仅修改WAVE_TYPE的数值即可,无需改动其他代码
  • 调整频率:修改SIGNAL_FREQ,程序会自动计算采样点数/缓冲区长度
  • 调整幅值:修改DAC_MAX_VALUE(比如输出半幅信号改为2047)
  • 两种方案均避免了手动修改数组内容、循环范围或DMA参数的繁琐操作,所有配置集中在顶部的宏定义中。

内容的提问来源于stack exchange,提问作者Meria Rajagukguk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:08:10