如何利用STM32G4的DAC与DMA生成三角波叠加正弦波
问题描述
我拥有一块STM32G4 nucleo开发板,希望利用STM32G4的DAC和DMA生成由~1Hz三角波与500Hz正弦波叠加而成的波形。请问能否从单个DAC通道输出该叠加波形?我已计算出正弦波单周期查找表,并将其叠加到斜线上,但发现仅能生成上升沿和下降沿各带一个正弦周期的三角波。相关代码如下:
#define dac_buf_len 200 HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t *) dac, dac_buf_len,DAC_ALIGN_12B_R); //generate sine wave for (uint32_t i=0; i < dac_buf_len; i++) { float s = (float) i/(float)(dac_buf_len-1); dac_sin[i] = sine_amplitude * sin(2*M_PI*s); //one cycle of sine wave } //generate triangular wave (ramp up) for (uint32_t i=0; i<dac_buf_len/2; i++) { dac_triangular[i] = 0.006*i - 0.5; } //generate triangular wave (ramp down) for (uint32_t i=0; i<dac_buf_len/2; i++) { dac_triangular[100+i] = -0.006*i + 0.1; } //sum two waves together for (uint32_t i=0; i< dac_buf_len; i++) { dac[i] = dac_sin[i] + dac_triangular[i]; }
解决方案
完全可以从单个DAC通道输出这两种波形的叠加,问题出在当前的波形生成逻辑没有匹配两个信号的频率关系:
1Hz三角波的周期是1秒,500Hz正弦波的周期是2ms,意味着在三角波的1秒周期内,需要包含500个正弦波周期。而你的代码中,仅在200点的buffer里生成了1个正弦周期,导致三角波半周期(0.5秒)内只有1个正弦周期,这就是你看到的现象。
修正步骤
1. 确定DAC输出速率
通过定时器触发DAC的DMA请求,设定触发频率(即每个DAC采样点的输出速率)。例如,设置触发频率为100kHz,每个点的输出时间是10μs,1秒需要100000个采样点,刚好匹配1Hz三角波的周期。
2. 匹配波形的采样点数量
- 三角波:1秒周期,分成上升沿(0.5秒)和下降沿(0.5秒),各需要50000个点
- 正弦波:500Hz,每个周期需要200个点(100kHz / 200 = 500Hz),1秒内刚好是500个周期(500×200=100000点)
3. 修正代码逻辑
以下是调整后的代码示例(假设12位DAC输出范围为0~4095,可根据实际幅度需求调整):
// 总采样点:100kHz触发下,1秒输出完,对应1Hz三角波 #define DAC_BUF_LEN 100000 // 正弦波每个周期的采样点:100kHz/200=500Hz #define SINE_CYCLE_POINTS 200 // 定义buffer(建议用全局变量,避免栈溢出) float dac_sin[DAC_BUF_LEN]; float dac_triangular[DAC_BUF_LEN]; uint32_t dac[DAC_BUF_LEN]; // 生成正弦波:1秒内500个周期 for (uint32_t i = 0; i < DAC_BUF_LEN; i++) { // 计算当前点在正弦周期内的相位 float phase = (2 * M_PI * (i % SINE_CYCLE_POINTS)) / SINE_CYCLE_POINTS; // 正弦幅度设为DAC量程的1/4(可调整) dac_sin[i] = (4095.0 / 4) * sin(phase); } // 生成三角波:上升沿(0~4095,0.5秒) for (uint32_t i = 0; i < DAC_BUF_LEN / 2; i++) { // 线性从0上升到4095 dac_triangular[i] = (4095.0 / (DAC_BUF_LEN / 2 - 1)) * i; } // 生成三角波:下降沿(4095~0,0.5秒) for (uint32_t i = 0; i < DAC_BUF_LEN / 2; i++) { uint32_t idx = DAC_BUF_LEN / 2 + i; // 线性从4095下降到0 dac_triangular[idx] = 4095.0 - (4095.0 / (DAC_BUF_LEN / 2 - 1)) * i; } // 叠加波形并转换为12位DAC格式(确保值在0~4095范围内,避免削波) for (uint32_t i = 0; i < DAC_BUF_LEN; i++) { float sum = dac_sin[i] + dac_triangular[i]; // 限制范围,防止超出DAC输出能力 sum = (sum < 0) ? 0 : sum; sum = (sum > 4095) ? 4095 : sum; // 转换为12位右对齐格式 dac[i] = (uint32_t)sum; } // 启动DAC DMA循环输出(需确保DMA设置为循环模式) HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, dac, DAC_BUF_LEN, DAC_ALIGN_12B_R);
额外注意事项
- DMA循环模式:需在CubeMX中设置DAC的DMA为循环模式,确保buffer重复输出,得到连续波形。
- 定时器配置:配置定时器触发DAC的频率为100kHz(可根据实际需求调整,只要满足三角波周期1秒、正弦波500Hz的比例即可)。
- 幅度调整:根据实际需求修改正弦波和三角波的幅度,叠加后不要超出DAC的输出范围(0~4095),否则会出现削波失真。
内容的提问来源于stack exchange,提问作者jlim14
相关产品推荐
相关产品推荐

