如何编写可灵活修改中间值的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
相关产品推荐
相关产品推荐

