PWM DAC原理
PWM本质上其实就是一种周期一旦确定高低电平占空比就可调的方博。
PWM波形可以用分段函数表示:
其中:T是单片机中计数脉冲的基本周期,也就是STM32定时器的计数频率的倒数。N是PWM波一个周期的计数脉冲个数,也就是STM32的ARR-1的值。n是PWM波一个周期中高电平的计数脉冲个数,也就是STM32中CCRx的值。VH和VL分别是PWM波的高低电平电压值,k为谐波次数,t为时间。我们将1式展开成傅里叶级数,得到公式2:
从2式可以看出,式1中第一个中括号为直流分量,第二项为1次谐波分量,第三项为大于1次的高次谐波分量。式2中的直流分量与n成线性关系,并随着n从0到N,直流分量从VL到VL+VH之间变化。这正是电压输出的DAC所需要的。因此,如果能把式2中除直流分量外的谐波过滤掉,则可以得到从PWM波到电压输出DAC的转换,即:PWM波可以通过一个低通滤波器进行解调。式2中的第二项的幅度和相角与n有关,频率为1/(NT),其实就是PWM的输出频率。该频率是设计低通滤波器的依据。如果能把1次谐波很好过滤掉,则高次谐波就基本不存在了。
通过上面的了解,我们可以得到PWM DAC的分辨率,计算公式为:分辨率=log2(N)
这里假设n的最小变化为1,当N=256时,分辨率就是8位(N=4096时,分辨率就是12位).而STM32的定时器都是16位的,因此可以得到很高的分辨率,分辨率越高,速度就越慢。
在8位分辨率条件下,我们一般要求1次谐波对输出电压的影响不要超过1个位的精度,也就是3.3/256=0.01289V。假设VH为3.3V,VL为0V,那么一次谐波的最大值是2*3.3/Π=2.1V,这就是要求我们的RC滤波电路提供至少-20lg(2.1/0.01289)=-44dB的衰减。
STM32的定时器最快的计数频率是168Mhz,部分定时器只有84MHz,以84为例,8为分辨率的时候,PWM频率为84M/256=328.125Khz。如果是1阶RC滤波,则要求截止频率为2.07Khz,如果为2阶RC滤波,则要求截止频率为26.14Khz。
PWM DAC硬件:
二阶RC滤波截止频率计算公式为:f=1/2ΠRC
以上公式要求R20*C34=R32*C35=RC。根据这个公式,我们计算出截止频率为:33.8Khz超过了26.144Khz,这个和我们前面提到的不符,原因是该电路还需要用作PWM DAC音频输出,而音频信号带宽是22.05Khz,为了让音频信号能够通过该低通滤波器,同时为了标准化参数选取,所以确定了这样的参数。实测精度在0.5LSB以内。
相关实验代码:
void TIM9_CH2_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitABC;
TIM_TimeBaseInitTypeDef TIM_TimeBaseABC;
TIM_OCInitTypeDef TIMOCInitABC;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE);//TIM9时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能PORTA时钟
GPIO_InitABC.GPIO_Pin=GPIO_Pin_3;//GPIOA3
GPIO_InitABC.GPIO_Mode=GPIO_Mode_AF;//复用功能
GPIO_InitABC.GPIO_Speed=GPIO_Speed_100MHz;//速度100MHz
GPIO_InitABC.GPIO_OType=GPIO_OType_PP;//推挽复用输出
GPIO_InitABC.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA,&GPIO_InitABC);//初始化PA3
GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_TIM9);//GPIOA3复用定时器9 AF3
TIM_TimeBaseABC.TIM_Prescaler=psc;//定时器分频
TIM_TimeBaseABC.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseABC.TIM_Period=arr;//自动重装载值
TIM_TimeBaseABC.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM9,&TIM_TimeBaseABC);//初始化定时器9
TIM_OCInitABC.TIM_OCMode=TIM_OCMode_PWM1;//选择定时器模式:TIM脉冲宽度调到模式2
TIM_OCInitABC.TIM_OutputState=TIM_OutputState_Enable;//比较输出使能
TIM_OCInitABC.TIM_OCPolarity=TIM_OCPolarity_High;//输出极性:TIM输出比较极性较高
TIM_OCInitABC.TIM_Pulse=0;
TIM_OC2Init(TIM9,&TIM_OCInitABC);//根据T指定的参数初始化外设TIM9 OC2
TIM_OC2PreloadConfig(TIM9,TIM_OCPreload_Enable);//使能TIM9在CCR2上的预装载寄存器
TIM_ARRPreloadConfig(TIM9,ENABLE);//ARPE使能
TIM_Cmd(TIM9,ENABLE);//使能TIM9
}