你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32通过PWM产生频率为20HZ占空比为50%方波,并通过单片机...

[复制链接]
STMCU-管管 发布时间:2020-9-22 10:40
  1. int main(void). t, V  ?% f0 H
  2. {                + [# ^. d8 o& X! ~7 A, g  o$ l
  3.         char str[10];
    & ^$ J9 [  ~0 |
  4.         delay_init();                     //延时函数初始化          
    , o6 V, I+ P, I7 M/ C: d7 r. ^
  5.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    + ~: d3 }: ^! Z3 ?; r
  6.         uart_init(115200);         //串口初始化为115200( r9 w8 W+ i& K  s7 L1 k; c9 M
  7.         LED_Init();                                  //初始化与LED连接的硬件接口
    ( }8 F( ]# |- {( @
  8.         EXTIX_Init();                 //初始化外部中断输入
    ( X# |- ?, k  a) ^; H" V
  9.         LCD_Init();) m) t6 z$ |& o
  10.         TIM3_PWM_Init(499,7199);7 M5 M* R. ]+ b) M- F3 j9 h
  11.         TIM2_Init(4999,7199);
      Z6 T; [0 b+ c4 Y: e: s
  12.         LED0=0;                                        //先点亮红灯- t, _; X  \( z) t7 f* ?
  13.         TIM_SetCompare2(TIM3,250);//设置CCR2的寄存器值为250占空比为50%
    # j* p( R- F; C
  14.         LCD_ShowString(45,125,200,30,16,"-----freqency-----");6 M* k/ v2 I4 {2 z6 @# i$ f+ u
  15.         LCD_ShowString(130,165,32,30,16,"HZ");
    0 W- ?4 s; w4 E6 ]0 ~6 i" `
  16.         while(1)
    4 j8 W: D8 e6 T% x3 {
  17.         {            6 d! [3 C4 S) x9 s/ n# k/ b8 W( \# q
  18.                 freq=10000.0 / (float)time_of_circle;
    ' C; f+ q' e  H8 g
  19.                 sprintf(str,"%.2f",freq);- ~# P4 @2 z) Z# y8 `
  20.                 LCD_ShowString(50,165,64,30,16,str);
    ( c2 \$ o( j4 U6 k
  21.                 LCD_ShowString(45,125,200,30,16,"-----freqency-----");4 {9 {; s6 G0 f( x* r8 l
  22.                 LCD_ShowString(130,165,32,30,16,"HZ");
    8 z' H( t0 X3 e4 J
  23.         }         
    $ X# X0 g, e0 s% \4 d1 M
  24. }
复制代码

% }' i6 Z) b" A6 a& J
1_meitu_1.jpg

3 |# ^$ l( y# Q0 A
2_meitu_2.jpg

" V( J( e  L& L% e3 N1 j: d2 y6 U+ m+ ^4 q  @+ ~& Z
8 h1 b/ p" |" [3 c$ S
/ H# [; U3 K0 |6 n$ e' ?) d! P' w) Y

) [8 I  Z1 g& y/ |单片机产生频率为20HZ的占空比为50%方波

       通过单片机产生方波很容易,设置寄存器ARR的值就能确定周期。设置CCRx的值就能设置设置占空比。 当CNT寄存值小于CCRx的值时输出低电平,大于CCRx的值时输出高电平,到达ARR的值时溢出。知道基本的原理后通过寄存器初始化和使能相关的寄存器就可以了。

       这次实验采用TIM3 CH2不重映像,同时设置PWM模式为向上计数模式。配置步骤如下:

% ]/ I9 Z; A6 {0 Y0 n4 Y

3_meitu_3.jpg

; Z3 h8 P7 x, h0 F& _" K, Y& u
, R1 I1 S* @  Q; n; P

5 r. S1 i; X3 M$ M
2 t6 k0 {/ }  c0 {
  • 开启TIM3时钟,并设置PA7为复用输出
  • 初始化TIM3,设置TIM3的ARR和PSC值
  • 设置TIM3_CH2的PWM模式,使能TIM3的CH2输出
  • 使能TIM3
  • 修改TIM3_CCR2来控制占空比
    + L+ F4 w- f- F( r/ o! q& v
6 A7 {( k% Q! ~+ ]6 j% Y0 Z, r

3 S2 l0 Y) R2 g: v7 t3 |0 M
  1. //TIM3 PWM部分初始化
    ; l  S' |# J1 ?: o
  2. //PWM输出初始化$ a2 c4 s# W' ?# D
  3. //arr:自动重装值
    " B: }7 [1 r( N) D1 X
  4. //psc:时钟预分频数- T8 e0 M/ [) v
  5. void TIM3_PWM_Init(u16 arr,u16 psc)
    3 u5 e: Y* f6 p, u( v& F+ R6 A: j
  6. {  
    5 q, _) j, y" b8 n  x6 I/ X2 p) n
  7.         GPIO_InitTypeDef GPIO_InitStructure;
    - d: V4 a8 l% m+ Y1 e4 f+ d
  8.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;* \0 \! P# R! k% A. l
  9.         TIM_OCInitTypeDef  TIM_OCInitStructure;4 @* G9 h0 \) p
  10.         , {+ O( B- y( ]' z
  11. 9 a/ I9 i5 I# [5 C
  12.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);        //使能定时器3时钟! r0 e! H+ K, i1 e3 ^. o1 T
  13.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIO 和 AFIO 复用功能时钟
    % N2 s0 ~6 n9 A) H
  14. //        GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PC7   
    9 d2 ~% |5 Y5 B9 N/ b2 c/ [

  15. : X3 N5 k+ t# [. Z
  16.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2
    % o' g5 J0 S* g, a! k$ `
  17.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    + F& r; t) Q" W/ z8 p9 X
  18.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    & m# D, n2 x* n$ J! M" n2 T  N
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA
    9 U9 N, w7 e$ H! E( I' u
  20. % k2 z9 o# E3 o" l; N1 b
  21.    //初始化TIM3
    7 z0 u! m. v& w, [4 Q$ `, F
  22.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    - ]  b- h' s, v+ O
  23.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    5 R+ u" Q+ g9 R- t
  24.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim5 F# k9 X6 b* ?
  25.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式% n/ T$ i* s1 I" v
  26.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位" S7 o! ^* j9 a; W0 k
  27.        
    " s2 L( }0 o1 b
  28.         //初始化TIM3 Channel2 PWM模式         
    / M3 t. M9 Q4 _7 u5 U
  29.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式26 C% x- b& Q& E
  30.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    8 e8 {; d9 ]2 c. [; p$ q
  31.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    7 O' C/ b3 \; P5 o' o8 |# Q
  32.         TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2
    ' I- \( ], i/ C, Z. r$ Y
  33. 2 u2 T  a; M! A9 [% |& `
  34.         TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
    , l+ i! v' ]8 }, I

  35. ) E: K& a& m/ J3 t( R. J1 H, r3 M4 e
  36.         TIM_Cmd(TIM3, ENABLE);  //使能TIM31 {& A* b+ h2 P$ W2 ]% o# \
  37.         ) x. H& _1 M$ s' `2 ?; ^  G. u/ P* ]
  38. }
复制代码
# D8 J8 O3 A7 P+ Q

& M  R, g$ f4 |9 |

       以上代码就完成了PWM的初始化,如果要产生20HZ的波形,那么就相当于要没50ms要溢出一次,那么我们可以设置arr的值为499,psc的值为7199。Tout= ((arr+1)*(psc+1))/Tclk=(499+1)* ( 7199+1)/72=50ms 。说明计数到500次为50ms,那么设置CCR2的值为250就可以实现占空比为50%。

4 T6 R* i0 f  u! ^$ s: Y2 P

单片机测量频率并显示) x% O5 J6 p2 j9 g

测量频率的思路有很多种,网上有关于ADC测量电压,也有关于输入捕获的。但是上次电赛校赛,学长用的是外部中断结合定时器中断来实现的,思路也比较简单。就是下降沿触发外部中断,然后打开定时器计数。当再次进入外部中断时停止计数清楚相关的标志位。这样就得到了一个计数次数,通过计数次数就可以计算出电平经历变化用的时间,时间的倒数就是相关的频率。本次实验用的是外部中断三(EXTI3)对应PE3口。

1 w+ @% O* s7 K6 ?$ I( o
% H, {$ V: F/ v# h! P) N" V
  1. void EXTIX_Init(void)
    & w. O; x* v. c* F* }
  2. {
    2 S; g4 [3 c* f8 F* q* L( N

  3. ; m  b2 I5 u1 _! j' _& p- e$ N
  4.            EXTI_InitTypeDef EXTI_InitStructure;
    / W5 m6 K5 t, `' S" M
  5.         NVIC_InitTypeDef NVIC_InitStructure;
    $ T! M$ M6 g4 R4 H, V
  6. " i0 H  G* L0 {/ d; j% a3 ~
  7.     KEY_Init();         //        按键端口初始化
    $ s% U4 R4 D. e3 M* t
  8. 8 z/ ^; G: F- s2 D# C( |7 C
  9.           RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);        //使能复用功能时钟
    1 F' N- i6 _; x
  10.          
    - H& S$ O* @: c9 V# l. S
  11.    //GPIOE.3          中断线以及中断初始化配置 下降沿触发 //KEY1
    $ [& W( N+ W2 ?9 C* _6 O
  12.           GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
    5 V, j2 }1 j% B+ D3 M2 ?3 R: d
  13.           EXTI_InitStructure.EXTI_Line=EXTI_Line3;, h2 M) d9 [0 r5 c$ O" l
  14.           EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;       
    ) I! u, B$ y* m  }" Y: Y9 n
  15.           EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    2 r6 x* w( y- i
  16.           EXTI_Init(&EXTI_InitStructure);                  //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器+ O8 ?) S6 P9 L+ w; f7 q0 Q9 O4 i9 U

  17. 9 [* E+ {+ r) ~
  18.           NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;                        //使能按键KEY1所在的外部中断通道
    + P9 Z8 y& U4 w3 {
  19.           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;        //抢占优先级2 ; N2 I, j/ @' @( l
  20.           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;                                        //子优先级1 * Z0 i8 E3 _) b% N' w
  21.           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                                //使能外部中断通道
    8 y; D) s* m* y
  22.           NVIC_Init(&NVIC_InitStructure);            //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器4 x5 I; [, s9 m; Q, [* k
  23. 3 i7 K. `/ |5 l9 s1 r- d) w
  24. }
复制代码
  1. void EXTI3_IRQHandler(void)
    1 s1 {( S: V6 V- n8 y/ L; j3 H
  2. {) c6 i( l: l! y3 t
  3.         if(half_cricle == 0). \! b7 G& V4 z, M# m. u! ^
  4.         {# E- c; |1 q0 J1 r
  5.                 TIM2->CNT = 0;' H8 g- P, k' F. r
  6.                 TIM_Cmd(TIM2, ENABLE);  //使能TIMx       
    ( K$ C% B9 Q6 L& t2 @: {
  7.                 half_cricle = 1;: ^+ H7 ?" V: U! h
  8.         }
    # T5 ~; `& k, m# ~( B3 @
  9.         else if(half_cricle == 1)  A2 A& g% V& B0 z1 w
  10.         {& h: N3 N$ A3 N5 O+ c- k
  11.                 time_of_circle = TIM2->CNT;( w; S, O% K; b0 `6 n
  12.                 TIM2->CNT = 0;2 o3 w7 f4 y: ?# _7 m
  13.                 TIM_Cmd(TIM2, ENABLE);  //使能TIMx        . A/ i9 o' L) y; r* q
  14.         }% s! a8 L& e6 k
  15.         EXTI_ClearITPendingBit(EXTI_Line3);0 @7 ?4 E/ `, p
  16. }
复制代码
) x1 b# d3 N9 ?; l
0 u- w6 k2 N$ b4 V0 Z6 T0 A; Z

; W4 m( i+ g7 Y

8 O/ P( B" o% n. T
3 U+ G- Y( @% U* o, ~2 T

定时器2初始化:

  1. void TIM2_Init(u16 arr,u16 psc)
    + W$ g( H8 U! {
  2. {7 S7 b7 H- D9 }- Y" Q' T
  3.   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;( a* l0 s* Y( S! K, I! C7 t# n4 O  o
  4. //        NVIC_InitTypeDef NVIC_InitStructure;) v" @3 C9 ~/ H' H

  5. 3 q$ q0 K9 y* v; E1 ^- `- y/ @& O, y
  6.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能0 R8 T- k4 w  g/ r- ]

  7. " M1 ]. R+ S8 R/ n- d
  8.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         计数到5000为500ms4 w! |, i2 X3 k- P
  9.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
      y+ ?" n+ F$ g3 M- O) \" b" L
  10.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    ) i& y7 h  q) k3 c
  11.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    , r3 B% s1 ~8 Q5 g8 D: }
  12.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    / K7 ]2 e: y" M$ O* _

  13. 1 }: W0 X% C( w' d9 D6 j
  14. //        TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
    % A# C7 ]2 B/ e* ~+ V* z
  15. 1 T6 Y# E4 v& l
  16. //        NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断; S- S* n2 I# i* Y
  17. //        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级; E" o  }' }7 f& _- w
  18. //        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    $ D+ y6 t0 k* Y7 e
  19. //        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    ; |* G9 x0 O% D5 b) `0 r; `
  20. //        NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器                                                         
    / t" w& A, m( f  ^/ {0 o; J9 d
  21. }
复制代码
2 J8 a$ T8 q: Q' [8 `0 e4 _7 u
" I. K6 y7 @8 ^$ O" y3 ]

主函数:


3 u  x* q/ r& b& P2 E

  1. int main(void)
    , K5 x6 W: Z! D" D( D' i! Q
  2. {               
    5 B" ^7 K3 l, c8 q0 c. }
  3.         char str[10];& j3 C5 |+ U9 M! T
  4.         delay_init();                     //延时函数初始化          
    ( u3 \6 t  r0 o1 i# M/ I7 s
  5.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级& u8 e4 P' V7 Q$ z" a, P! H2 A% G
  6.         uart_init(115200);         //串口初始化为115200
    # K* N2 Y! q/ M0 o1 g9 M; S
  7.         LED_Init();                                  //初始化与LED连接的硬件接口 - m3 _/ J- R* [& ~% T& A
  8.         EXTIX_Init();                 //初始化外部中断输入) T0 S* m* s. `* K5 ]5 q* H, @- U% V6 Y
  9.         LCD_Init();$ R; |7 F1 ~$ u1 ]* B/ n
  10.         TIM3_PWM_Init(499,7199);& o' U/ R% ~$ r
  11.         TIM2_Init(4999,7199);
      l+ I* r, [7 f0 A( X5 s
  12.         LED0=0;                                        //先点亮红灯
    ( I2 D, ]% Q0 H! }# o* C! u- C/ \3 }6 v
  13.         TIM_SetCompare2(TIM3,250);//设置CCR2的寄存器值为250占空比为50%
    6 y# U+ |  m9 h: _
  14.         LCD_ShowString(45,125,200,30,16,"-----freqency-----");
    + p' ]8 c. {" H9 x3 k
  15.         LCD_ShowString(130,165,32,30,16,"HZ");0 `% R$ M6 U0 n4 C4 R
  16.         while(1)
    * Y1 [! }0 k) [* ~1 e! |
  17.         {            
    , l, `: [( }% P' ]% M9 q2 M) A
  18.                 freq=10000.0 / (float)time_of_circle;
    8 Y, i3 A, W+ H" h+ H4 G1 X6 ]
  19.                 sprintf(str,"%.2f",freq);
    6 Z( H; P- j6 }# ^; w
  20.                 LCD_ShowString(50,165,64,30,16,str);
    ; f0 g) b; `) u, r* v
  21.                 LCD_ShowString(45,125,200,30,16,"-----freqency-----");
    3 r+ o) P% ]6 R; p9 h0 R
  22.                 LCD_ShowString(130,165,32,30,16,"HZ");6 s2 p. p. V* ~7 ^; o& x
  23.         }         
    8 B$ {9 k% q3 O5 n4 k* Y3 j& ~
  24. }
复制代码

! u# |) M- A% M- b3 C* r& n& @3 J

) u0 v, |. R) j/ Q

+ o& J' _% N4 g$ {! m

       以上就是几个主要的函数,用库函数配置比寄存器配置舒服多了,之前一直整寄存器版本的,现在接触库函数觉得实在是太方便啦!


, O; P8 C; z+ h# s% h
3 V/ n6 w! U4 U, e3 e8 ]
收藏 评论1 发布时间:2020-9-22 10:40

举报

1个回答
289466080 回答时间:2020-9-22 15:10:51
用cube做个教程

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版