|
刚从51转过来,不想投入太多的资金,选择某宝的小蓝板(bluePill),这个板可能是最便宜的了(7.6元包邮)。初步测试一下时钟,定时器,中断,DMA什么的。到ADC还比较满意,DAC就晕了(这个芯片没有DAC)。于是采用PWM出模拟值。先初始化; D+ l7 a$ I7 j3 V: q void TIM1_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;- z$ z( @3 C4 [5 W% v1 U5 q9 Y TIM_OCInitTypeDef TIM_OCInitStructure;9 \+ M% x4 f2 m& S; w ( s" U* z# {9 c RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // , N; g$ V4 u8 @9 U9 ^; T RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能GPIO外设时钟使能 //设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形0 c3 j5 W3 ]: p7 j GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1 //PA8是PWM输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出% v9 l% \% C" o2 ] GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;8 C( K$ @% d1 }' Y8 c GPIO_Init(GPIOA, &GPIO_InitStructure);& k4 P+ w/ h- x //定时器初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 & R. K- F8 w* E. x ? TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式2 Z- L' l3 T7 i. k: D1 E _ TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 //初始化输出比较参数$ p: M0 f/ E1 r% y0 Q TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2: c; Q4 @8 b. P2 R6 v1 Q TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_Pulse = 1350; //设置待装入捕获比较寄存器的脉冲值 1350--Low 200--High( U# v& X7 j: {) |. s( O d TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高+ p/ M3 s6 o: M TIM_OC1Init(TIM1, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx, D: o( r: D# H% P' [' C. j& m: H //使能预装载寄存器; A: ]" N1 [% m TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能。该函数操作的是TIM1 刹车和死区寄存器该函数并不是适合所有定时器的, //只有部分定时器可以使用,例如,在stm32f0中,可用于TIM1, TIM15, TIM16以及TIM17,( V6 `1 Z( @7 h" \( R. J //在stm32f1中可用于TIM1, TIM8,TIM15, TIM16以及TIM17,如果在其它定时器中使用,$ _4 \* ]4 t1 K //可能会使STM32停留在某一处而无法继续执行下面的任务& {# l; ^$ `& |" a7 ^% y TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //CH1预装载使能 3 _: W) X5 R7 [7 ^5 \( ] TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器 TIM_Cmd(TIM1,ENABLE); //使能TIM1 - |4 `1 v2 M. }8 t0 @ }& D) t, q h4 }4 r1 ?9 E* @$ O ! ?. B( T! r- V* l) T3 B : [2 M- D2 }! J2 D! s v + D+ ~, {9 Q. N! U 然后在MAIN()中: int main()- k$ V0 d6 A. M. ^7 R { TIM_SetCompare1(TIM1,1500); //占空比=1000 / (2999+1)*100% = 50%# q% P' |. u# { while(1) { ; } }6 m' @# g3 X" N2 v; o& O. i5 A 可以在PA8看到PWM波形。一顿操作:' t C0 c+ M" x7 x9 |1 b; s
发现DAC输出精度,线性都不好。也不知道是运放的问题还是其他。网上一顿搂,改进PWM输出模拟量。1 q+ o2 m7 e5 r6 k0 o5 f% }
效果好了不少。线性还是不好。. R8 |- `/ {/ ~1 B* [$ v5 f 于是将DAC又返回ADC采集加数字闭环。 dac_d是期望输出的值,dac_out是送去PWM转换的值,vi是从DACOUT那里取出的电压ADC值。下面程序是数字反馈 void dac_auto(void)$ O$ |& i- S6 f- K" ?, c {5 U. ~' u; H1 d9 K u16 tmp;6 O3 a2 J* q7 |# p" u# w$ ^ if((short int)vi>(dac_d+1)) { tmp=(short int)vi-dac_d;. S; l" ^7 p, z% ~8 ~8 { 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;. x o, z& j2 ^; t" H7 L else dac_out-=1; } else if((short int)vi<(dac_d-1)) s4 G8 e Q; |3 s. R4 T$ u! N5 T {2 Q! t: B) P4 p2 D+ r' n tmp=dac_d-(short int)vi;; j2 W9 ]0 d0 J) L" g& g: `* S( c: K1 I if(tmp>=220)dac_out+=110; else if(tmp>=100)dac_out+=55;- h% E- d" m/ I0 s- J4 A4 O else if(tmp>=50)dac_out+=35; else if(tmp>=10)dac_out+=7;4 V* A% i4 f9 P else if(tmp>=5)dac_out+=3;9 Y9 n" D% O( o0 ]0 U; @ else dac_out+=1;. R' `" L8 h% F }' B& ^- n' k+ m2 K. d- h R+ P if(dac_out>=2999)dac_out=2999; if(dac_out<=1)dac_out=1; TIM_SetCompare1(TIM1,dac_out); filter();! |# C% r! q7 a. H4 K' W }6 N: c/ j4 y' ^, H 经过处理,PWM输出的最终电压值波动小于1毫伏。+ t9 j: l: U- A+ m. V |
微信公众号
手机版