STM32F103系列微控制器内置的数字模拟转换器(DAC)模块有个非常实用的功能——硬件三角波发生器。这个功能对于需要生成周期性模拟信号的场景特别有用,比如音频合成、电机控制或者传感器测试。我第一次用这个功能时,发现它比用软件逐点计算波形要高效得多,CPU占用率几乎为零。
DAC模块包含两个独立的12位转换通道,每个通道都有自己的数据寄存器和控制逻辑。三角波发生器的工作原理其实很简单:内部有一个计数器,在每次触发事件到来时自动递增或递减。这个计数器的值会和DAC数据寄存器的基值相加,然后输出到DAC的模拟引脚上。当计数器达到设定的峰值(由MAMP位控制)时,就会自动反转计数方向。
这里有个关键点需要注意:三角波发生器必须配合触发源才能工作。常见的触发源可以是定时器、外部引脚或者软件触发。我在项目中通常使用定时器触发,因为这样可以精确控制波形频率。比如设置TIM2每100us触发一次DAC更新,这样生成的三角波周期就是(峰值*2)*100us。
要让DAC输出三角波,需要配置几个关键寄存器。首先是DAC控制寄存器(DAC_CR),这个寄存器控制着DAC通道的所有功能。我们需要设置WAVEx位为10b来选择三角波模式,然后通过MAMPx位设置波形幅度。幅度设置有个坑我踩过:必须在使能DAC之前设置好MAMP值,否则修改是无效的。
具体寄存器配置流程是这样的:
这里有个实用的技巧:如果你需要双通道同步输出,记得使用DAC_DHR12RD寄存器。这个寄存器可以同时写入两个通道的数据,保证输出同步。我做过测试,用这个寄存器比分别写入两个通道的寄存器,同步性要好得多。
在实际项目中,经常需要两个通道输出同步的波形,但幅度可能不同。比如我之前做的一个项目,需要通道1输出0-3.3V的三角波,通道2输出0-1.65V的同步波形。STM32F103的DAC支持这种场景,关键是要用好双通道同步更新功能。
实现步骤可以分为这几步:
这里有个实测有效的代码片段:
c复制// 初始化双通道
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Triangle;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_4095;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_2047;
DAC_Init(DAC_Channel_2, &DAC_InitStructure);
// 使能双通道
DAC_Cmd(DAC_Channel_1, ENABLE);
DAC_Cmd(DAC_Channel_2, ENABLE);
// 设置同步触发
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
TIM_Cmd(TIM2, ENABLE);
波形频率的精确控制离不开定时器的正确配置。STM32F103的定时器触发DAC有几个需要注意的地方:
首先,定时器的时钟要配置正确。APB1定时器时钟通常是36MHz(取决于系统时钟设置)。然后通过预分频器(PSC)和自动重装载值(ARR)来计算触发频率。比如要生成1kHz的三角波(假设幅度为4095),可以这样计算:
周期 = (4096 * 2) / 频率 = 8192 / 1000 = 8.192ms
定时器触发间隔 = 周期 / (4096 * 2) = 1us
所以可以设置PSC=35,ARR=0,这样定时器频率就是36MHz/(35+1)=1MHz,即每1us触发一次。
我在调试时发现,有时候波形会有毛刺,这通常是定时器配置不当导致的。建议:
当所有配置完成后,用示波器观察波形时可能会遇到几个典型问题:
首先是波形幅度不对。这可能是因为:
其次是波形失真。常见原因包括:
我常用的调试方法是:
对于要求严格同步的应用,建议使用硬件触发而不是软件触发。我在一个电机控制项目中发现,使用TIM2硬件触发,两个通道的延迟差可以控制在10ns以内,完全满足大多数应用需求。
在实际应用中,经常需要动态调整波形参数。比如根据传感器反馈实时改变三角波幅度。STM32F103的DAC支持运行时修改大多数参数,但要注意操作顺序。
修改幅度(MAMP)的正确步骤:
动态改变频率的方法:
这里有个实用技巧:如果需要非常平滑地改变频率,可以使用定时器的PWM模式,通过改变占空比来间接控制DAC触发频率。我在音频合成项目中用这个方法实现了无级变频,效果很好。
在电池供电的应用中,DAC的功耗需要特别注意。STM32F103的DAC有几个省电技巧:
关于噪声控制,实测发现:
我在一个便携设备上的实测数据:
在实际项目中,我遇到过不少DAC相关的问题,这里分享几个典型案例:
问题1:波形出现台阶现象
原因:数据寄存器更新速度跟不上触发频率
解决:降低触发频率或使用DMA传输
问题2:双通道不同步
原因:寄存器写入顺序不当
解决:使用DAC_DHR12RD寄存器同时写入双通道数据
问题3:波形幅度不稳定
原因:参考电压波动
解决:增加参考电压滤波电容,或使用外部精密参考源
问题4:高频波形失真
原因:输出缓冲带宽不足
解决:降低输出负载电容,或外接运放
最后提醒一点:调试DAC时,一定要用示波器观察实际波形,不要完全依赖寄存器值。我遇到过几次寄存器配置正确但波形不对的情况,最后发现是PCB布线问题导致的。