
刚从51转过来,不想投入太多的资金,选择某宝的小蓝板(bluePill),这个板可能是最便宜的了(7.6元包邮)。初步测试一下时钟,定时器,中断,DMA什么的。到ADC还比较满意,DAC就晕了(这个芯片没有DAC)。于是采用PWM出模拟值。先初始化; 9 [ M; h- E4 V0 y5 @ void TIM1_PWM_Init(u16 arr,u16 psc)2 ?2 z. [' I9 J4 O { / {% t/ o! e* s" c8 l( y! T0 ] GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;4 c2 o2 d9 ~. e" g/ h3 x3 j3 T) X4 M TIM_OCInitTypeDef TIM_OCInitStructure;% m' M- a r5 i3 R* Y ; c6 r: L9 y/ @, x5 J/ ? RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能GPIO外设时钟使能 8 j# z7 o# ?" {9 I& p9 b5 H6 h" k% V1 p //设置该引脚为复用输出功能,输出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); //定时器初始化 9 @: g! K9 X2 p! x5 l1 b/ ^; n L- O TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值6 L0 P- w* s5 ^1 H TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 ' C' p* J* w" `8 P6 t TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式2 g& [; o3 h3 |- B( Y TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位1 L, v) `0 y( C; E( f //初始化输出比较参数2 Y, B6 f* [8 _' N0 U. t. f TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能5 S; }# [/ H4 q$ b TIM_OCInitStructure.TIM_Pulse = 1350; //设置待装入捕获比较寄存器的脉冲值 1350--Low 200--High! E J3 e3 c2 ?5 M+ Z. } TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx3 a! z2 C! }6 O4 D //使能预装载寄存器, O$ P. L4 _' Q) U TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能。该函数操作的是TIM1 刹车和死区寄存器该函数并不是适合所有定时器的, //只有部分定时器可以使用,例如,在stm32f0中,可用于TIM1, TIM15, TIM16以及TIM17,; m$ Q8 X7 M5 K: H8 W: i! Q) F- D //在stm32f1中可用于TIM1, TIM8,TIM15, TIM16以及TIM17,如果在其它定时器中使用, //可能会使STM32停留在某一处而无法继续执行下面的任务8 ]0 S( r& P, D+ G: b TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //CH1预装载使能 , K2 h7 i' X( x$ | TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器# ?) ~6 H* E# f { TIM_Cmd(TIM1,ENABLE); //使能TIM15 ?3 @$ T& ` t; t 1 n$ b; s1 P8 B( w6 G& O } 5 M3 D# v# G! D) \6 i8 Z 然后在MAIN()中:4 @3 ?4 k t) Q( j" }# P3 H, x; g a int main()' q% ~0 M% u9 J& B: h G8 `( \' n {0 V4 L3 q5 c/ H3 I) a" y TIM_SetCompare1(TIM1,1500); //占空比=1000 / (2999+1)*100% = 50%7 T! R1 V0 H& ]( n0 _& P! x$ O1 x while(1) { ; } } 可以在PA8看到PWM波形。一顿操作: ![]() 发现DAC输出精度,线性都不好。也不知道是运放的问题还是其他。网上一顿搂,改进PWM输出模拟量。 ![]() 效果好了不少。线性还是不好。 于是将DAC又返回ADC采集加数字闭环。 dac_d是期望输出的值,dac_out是送去PWM转换的值,vi是从DACOUT那里取出的电压ADC值。下面程序是数字反馈% I; y' i3 _. u" S void dac_auto(void) { u16 tmp;4 S3 R3 W" u. h8 f/ l4 V if((short int)vi>(dac_d+1))- X$ L/ y6 L8 E2 l+ L( v& O {. ~! k4 Z2 J' J" E+ ] tmp=(short int)vi-dac_d;: J$ G, x7 J9 i1 f if(tmp>=220)dac_out-=170;# H: p; P! C$ Q/ e else if(tmp>=100)dac_out-=80; else if(tmp>=50)dac_out-=45;9 C7 p0 r( g( i+ y else if(tmp>=10)dac_out-=6; else if(tmp>=5)dac_out-=2;; R5 N% R' q( m) {0 j* R else dac_out-=1;' N! Z! d8 D1 B }5 D A; p6 l/ C* \# m6 u else if((short int)vi<(dac_d-1))' Y* W8 Q, o: M% `7 _1 c {6 `3 y3 L9 n5 t$ ~+ ^7 j tmp=dac_d-(short int)vi; if(tmp>=220)dac_out+=110;, P" I$ p- Q2 s4 a5 C, F else if(tmp>=100)dac_out+=55;) `+ Q! o* p. B else if(tmp>=50)dac_out+=35;$ T; ~" }0 x0 u- T- H 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);" S+ N" j, r5 c* a# G8 f0 l, Z# O4 t filter(); } 经过处理,PWM输出的最终电压值波动小于1毫伏。1 s @4 j! {! b4 ]5 X% m+ `! j" K0 H |