搜索
查看: 1098|回复: 0

[原创] 提高stm32f103c8t6的PWM精度

[复制链接]

该用户从未签到

1

主题

2

帖子

0

蝴蝶豆

中级会员

最后登录
2023-3-28
发表于 2020-8-16 19:05:40 | 显示全部楼层 |阅读模式
刚从51转过来,不想投入太多的资金,选择某宝的小蓝板(bluePill),这个板可能是最便宜的了(7.6元包邮)。初步测试一下时钟,定时器,中断,DMA什么的。到ADC还比较满意,DAC就晕了(这个芯片没有DAC)。于是采用PWM出模拟值。先初始化;

void TIM1_PWM_Init(u16 arr,u16 psc)
{  
        GPIO_InitTypeDef GPIO_InitStructure;                              
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);     //
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外设时钟使能

   //设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1         //PA8是PWM输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;            //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
   //定时器初始化       
        TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
        TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
   //初始化输出比较参数
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
        TIM_OCInitStructure.TIM_Pulse = 1350; //设置待装入捕获比较寄存器的脉冲值 1350--Low  200--High
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高
        TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
          //使能预装载寄存器
  TIM_CtrlPWMOutputs(TIM1,ENABLE);            //MOE 主输出使能。该函数操作的是TIM1 刹车和死区寄存器该函数并不是适合所有定时器的,
                                        //只有部分定时器可以使用,例如,在stm32f0中,可用于TIM1, TIM15, TIM16以及TIM17,
                                        //在stm32f1中可用于TIM1, TIM8,TIM15, TIM16以及TIM17,如果在其它定时器中使用,
                                        //可能会使STM32停留在某一处而无法继续执行下面的任务
        TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);  //CH1预装载使能         
  TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器
        TIM_Cmd(TIM1,ENABLE);  //使能TIM1

}



然后在MAIN()中:
int main()
{
TIM_SetCompare1(TIM1,1500);  //占空比=1000 / (2999+1)*100% = 50%
while(1)
{
   ;
}
}
可以在PA8看到PWM波形。一顿操作:
1.jpg
发现DAC输出精度,线性都不好。也不知道是运放的问题还是其他。网上一顿搂,改进PWM输出模拟量。
2.jpg
效果好了不少。线性还是不好。
于是将DAC又返回ADC采集加数字闭环。
dac_d是期望输出的值,dac_out是送去PWM转换的值,vi是从DACOUT那里取出的电压ADC值。下面程序是数字反馈
void dac_auto(void)
{
        u16 tmp;
       if((short int)vi>(dac_d+1))
            {
                tmp=(short int)vi-dac_d;
                if(tmp>=220)dac_out-=170;
                else if(tmp>=100)dac_out-=80;
                else if(tmp>=50)dac_out-=45;
                else if(tmp>=10)dac_out-=6;
                else if(tmp>=5)dac_out-=2;
                else dac_out-=1;
             }
        else if((short int)vi<(dac_d-1))
            {
                tmp=dac_d-(short int)vi;
                if(tmp>=220)dac_out+=110;
                else if(tmp>=100)dac_out+=55;
                else if(tmp>=50)dac_out+=35;
                else if(tmp>=10)dac_out+=7;
                else if(tmp>=5)dac_out+=3;
                else dac_out+=1;
            }
                if(dac_out>=2999)dac_out=2999;
                if(dac_out<=1)dac_out=1;
                TIM_SetCompare1(TIM1,dac_out);
        filter();
}

经过处理,PWM输出的最终电压值波动小于1毫伏。
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

GMT+8, 2024-4-29 04:46 , Processed in 0.160149 second(s), 32 queries .

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表