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

【经验分享】STM32CubeMX教程-PWM呼吸灯

[复制链接]
STMCU小助手 发布时间:2022-6-26 13:41
所用工具:
+ a  }/ T1 E  M# B! Z3 A7 E$ n
1、芯片:STM32F407ZET6/ STM32F103ZET6
2、STM32CubeMx软件
3、IDE:MDK-Keil软件
4、STM32F1xx/STM32F4xxHAL库
" ~# g$ H. w# d
知识概括:
通过本文您将学到:
  • PWM工作原理
  • STM32CubeMX创建PWM例程
  • HAL库定时器PWM函数库
  • PWM创建呼吸灯
    2 n& Z& s) S& t5 C9 l
什么是PWM
    脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。
3 j# z& U' {( H/ H" f& h+ w/ M& B
PWM工作原理
SMT32F1系列共有8个定时器:
    高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5);基本定时器(TIM6、TIM7)。
SMT32F4系列共有15个定时器:
    高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5、TIM9~TIM14);基本定时器(TIM6、TIM7)。
    STM32的每个通用定时器都有独立的4个通道可以用来作为:输入捕获、输出比较、PWM输出、单脉冲模式输出等。
    STM32的定时器除了TIM6和TIM7(基本定时器)之外,其他的定时器都可以产生PWM输出。其中,高级定时器TIM1、TIM8可以同时产生7路PWM输出。
1 H- ?) v5 p# D
原理讲解:
    下图为向上计数模式:

4 |8 A8 |8 J) S$ e/ Z0 R* L" [
微信图片_20220626134107.png

0 f  V6 c2 @  A* P
  • 在PWM输出模式下,除了CNT(计数器当前值)、ARR(自动重装载值)之外,还多了一个值CCRx(捕获/比较寄存器值)。
  • 当CNT小于CCRx时,TIMx_CHx通道输出低电平;
  • 当CNT等于或大于CCRx时,TIMx_CHx通道输出高电平。

      p* I. i" X+ |5 M( }9 D
    PWM的一个周期:
  •     定时器从0开始向上计数
  •     当0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平
  •     t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平
  •     当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数...循环此过程
  •     至此一个PWM周期完成
    , P+ _- l9 n9 T7 w1 _2 s
    总结:每个定时器有四个通道,每一个通道都有一个捕获比较寄存器, 将寄存器值和计数器值比较,通过比较结果输出高低电平,便可以实现脉冲宽度调制模式(PWM信号)。TIMx_ARR寄存器确定PWM频率,TIMx_CCRx寄存器确定占空比。
    若配置脉冲计数器TIMx_CNT为向上计数,而重载寄存器TIMx_ARR配置为N,即TIMx_CNT的当前计数值数值X在TIMxCLK时钟源的驱动下不断累加,当TIMx_CNT的数值X大于N时,会重置TIMx_CNT数值为0重新计数。
    而在TIMxCNT计数的同时,TIMxCNT的计数值X会与比较寄存器TIMx_CCR预先存储了的数值A进行比较,当脉冲计数器TIMx_CNT的数值X小于比较寄存器TIMx_CCR的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值A时,输出低电平(或高电平)。3 o: h; W+ V3 o2 v: \4 Z9 q: _
    如此循环,得到的输出脉冲周期就为重载寄存器TIMx_ARR存储的数值(N+1)乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器TIMx_CCR的值A乘以触发脉冲的时钟周期,即输出PWM的占空比为A/(N+1)。

( U9 o6 \+ B/ N1 r/ I
PWM的工作模式:
  • PWM模式1(向上计数)  :计数器从0计数加到自动重装载值(TIMx_ARR),然后重新从0开始计数,并且产生一个计数器溢出事件   
  • PWM模式2(向下计数)  :计数器从自动重装载值(TIMx_ARR)减到0,然后重新从重装载值(TIMx_ARR)开始递减,并且产生一个计数器溢出事件   
    ( M- z/ L( s- r# ^3 {% F: q* q$ k
    设置寄存器TIMx_CCMR1的OC1M[2:0]位来确定PWM的输出模式:
  • PWM模式1:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
  • PWM模式2:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
    . K# V& S8 |- l  B2 z, d; G
    在两种模式下TIMx_CNT(计数器当前值)与TIMx_CCR1(捕获/比较值)   只是决定是有效电平还是无效电平。有效电平可以是高电平也可以是低电平,这需要结合CCER寄存器的CC1P位的值来确定。

/ S) n8 N0 r' n0 \) x
PWM的工作过程

微信图片_20220626134102.png

( j7 n8 {+ r8 a/ `
1、CCR1寄存器:捕获/比较值寄存器:设置比较值。
    计数器值TIMx_CNT与通道1捕获比较寄存器CCR1进行比较,通过比较结果输出有效电平和无效电平。   
  • OC1REF=0 无效电平   
  • OC1REF=1 无效电平
    5 t3 x( t% X5 W. U9 J0 X
2、TIMx_CCMR1寄存器:OC1M[2:0]位:用于设置PWM模式。
  • 110WM模式1
  • 111WM模式2
    * c0 r" I8 q! ^! ]# S' E7 E3 w- n
3、CCER寄存器:CC1P位:输入/捕获1输出极性。
  • 0:高电平为有效电平     
  • 1:低电平为有效电平
    6 m/ A( C. [. @- @$ `0 }8 R  \! m  @
4、CCER寄存器:CC1E位:输入/捕获1输出使能。
  • 0:关闭使能
  • 1:打开使能

    + b( K  O  E9 N, ^/ g
5、输出电平信号。
# O. d; ?3 m6 K# k/ e1 L0 p
    TIM定时器的四路通道TIMx_CHx输出PWM
微信图片_20220626134056.png

6 G" q- o1 |1 q  h
摘自:《STM32中文参考手册》254页  通用定时器框图
附:STM32定时器输出通道引脚) j5 b/ n  ]' h5 w# i
微信图片_20220626134051.png

, G% E. M. }3 K& v# E
    具体不同定时器对应引脚在对应芯片数据手册的引脚说明(pin description) 中查看,这里我们以TIM3_CH1  PA6作为讲解。
$ R- l& d6 R0 y# {, q
工程创建过程
1.设置RCC
    设置高速外部时钟HSE 选择外部时钟源
3 S7 s! P# ]0 j2 `

微信图片_20220626134047.png

* S: S" M4 P9 i( z- n8 i
2.设置定时器

( B  K: }. M" P5 g
微信图片_20220626134044.png

) ^! m9 a  Y7 K  e/ {8 R' @  i+ K  S% k. d+ V- _" G  W) C: p
) o0 ]$ {, [5 l9 _! r
  • 1.选择TIM3
  • 2.设置定时器时钟源为内部时钟源
  • 设置定时器CH1为PWM模式
  • 3.对应管脚自动设置为复用模式
  • 4.可自行选择是否开启定时器中断
    7 h8 e7 u* K4 _! ~7 f$ {% }
    Channel1~4  就是设置定时器通道的功能:
  • 如输入捕获
  • 输出比较
  • PWM输出
  • 单脉冲模式
    & I* [4 R) L7 B  h) t( S

微信图片_20220626134041.png


1 t  d/ v* o' E' A' A/ X
  • Mode   选择PWM模式1
  • Pulse(占空比值)  先给0
  • Fast Mode   PWM脉冲快速模式    :  和我们配置无关,不使能
  • PWM 极性:   设置为低电平        PS:  由于LED是低电平点亮,所以我们把极性设置为low

    & L. ]1 z: P6 X

4 _; r* T1 F4 ?' x/ ^; P7 {, }

微信图片_20220626134036.png


/ g# Y, O  s1 [3 Q* {0 O
    在 Parameter Settings 页配置预分频系数为 71,计数周期(自动加载值)为 499,定时器溢出频率,即PWM的周期,就是 72MHz/(71+1)/(499+1) = 2kHz。
PWM频率:
  1. Fpwm =Tclk / ((arr+1)*(psc+1))(单位:Hz)
    ! y% E0 S6 t! L  \+ B
  2. arr 是计数器值
    ( o, x" d+ G. J1 t; {& C& J7 ~
  3. psc 是预分频值
复制代码
6 w, b3 X% Q& U& b- g- K2 n
占空比:
  1. duty circle = TIM3->CCR1 / arr  //(单位:%)! `5 ~) O3 r8 }6 g3 k; F- |& \$ A; T
  2. TIM3->CCR1   //用户设定值
复制代码
5 |# l+ W0 |$ }1 M
比如:
定时器频率Tclk = 72Mhz,arr=499,psc=71,那么PWM频率就是720000/500/72=  2000Hz,即2KHz。
如果arr=499,TIM3->CCR1=250,则pwm的占空比为50%。改CCR1可以修改占空比,修改arr可以修改频率。

# S1 P: G- K( p( P% n
' d( W6 }. p& f$ `0 \3 D6 q# z
3.时钟源设置
9 B7 E! x  E, Q- O

微信图片_20220626134031.png

9 ?. j+ o7 ^) M+ C7 Y: H1 |3 Z

32的时钟树框图  如果不懂的话请看《【STM32】系统时钟RCC详解(超详细,超全面)》

! {) r# b0 z; r' K- |6 k( T5 V

  • 1选择外部时钟HSE 8MHz   
  • 2PLL锁相环倍频72倍
  • 3系统时钟来源选择为PLL
  • 4设置APB1分频器为 /2
    8 m* Y6 q, `. k" {
   
4.项目文件设置
$ g+ y, V! I% T. F' @

微信图片_20220626134027.png

8 C  n, h7 |6 r# Q
  • 1 设置项目名称
  • 2 设置存储路径
  • 3 选择所用IDE

    * g9 T, J0 t- V5 I9 {" E

微信图片_20220626134022.png


1 O7 R9 W7 c* |% K6 N) Z# U8 M6 @- \
5.创建工程文件
    点击GENERATE CODE  创建工程。
    新建的工程所有配置都是默认的  我们需要自行选择下载模式,勾选上下载后复位运行。

) {& k9 @. e1 I# P
微信图片_20220626134019.png
& {) Z, Z6 H8 Z4 y* Z
3 {) W; o# w7 s

/ V7 J) G% t1 F' j) V, v# }
例程
    这里我们创建一个呼吸灯的例程
定义变量:
  1. /* USER CODE BEGIN 1 */' p- V) r/ ?; a4 s1 f
  2. uint16_t pwmVal=0;   //PWM占空比 . \& \- [7 a) l4 \7 V) d+ y9 S
  3. uint8_t dir=1;8 i4 M. W% j. L/ c2 s
  4. /* USER CODE END 1 */
复制代码
" S5 F3 f6 Y) ]5 l; d1 Y) n. n7 d/ [
使能TIM3的PWM Channel1 输出:
  1. /* USER CODE BEGIN 2 */9 O4 y  l4 R) o% o6 {. T
  2. HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);6 l! k3 U: x- Z8 b
  3. /* USER CODE END 2 */
复制代码
$ i5 |, l% Z" L+ a; ~1 Z
在while循环中添加代码:
  1. while (1)$ S$ z3 n5 R/ s# S
  2. {
    ! l5 v; [! J3 B- e8 {
  3. /* USER CODE END WHILE */
    - \6 p: N- x" r+ o5 X

  4. ( ?; L* G6 D) `' [2 d

  5. " }/ x: G; y6 j  }; [
  6. /* USER CODE BEGIN 3 */
    ; ~! l; Q9 u* k7 x4 Z

  7. - g8 {7 K6 `0 Y; v
  8. - H! u  u& b1 A6 @8 U2 Z
  9.   while (pwmVal< 500)3 X$ x  o0 ?- j8 j' f$ V
  10.   {4 l7 x: {5 K' C- Q! ~
  11.     pwmVal++;
    , t; `% Z* p- H$ _1 x
  12.     __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, pwmVal);    //修改比较值,修改占空比
    4 M& ]8 B) R5 G8 g6 d$ a& h! C
  13. //      TIM3->CCR1 = pwmVal;    与上方相同
    0 E3 c) Z# {* ]# S8 Q
  14.     HAL_Delay(1);# i5 f/ N1 P  P' w
  15.   }
    ) z' b1 m9 F5 m; P& {: f- q0 m
  16.   while (pwmVal)
    + W/ ?4 `8 s% ?4 O% v% e0 d8 c
  17.   {/ k+ p0 L/ ^- x" ~2 d6 _# s
  18.     pwmVal--;
    / a  G9 i! S# W: n; ?; i% Q
  19.     __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, pwmVal);    //修改比较值,修改占空比
    1 J$ ]4 Q$ a# r: }/ @0 j5 _
  20. //      TIM3->CCR1 = pwmVal;     与上方相同
    ' K; y9 v4 A7 }. I* g
  21.     HAL_Delay(1);
    - s' k6 D( x$ N8 r
  22.   }: q! j2 L8 _/ i8 w* m0 V
  23.   HAL_Delay(200);- m% l5 k# u8 O' P9 R  U! a; L
  24. " s1 ~) w  t: k9 A8 q* I
  25. : z+ ?" _7 j$ _; y
  26. /* USER CODE END 3 */8 p6 k8 c; b' D! l
  27. }
复制代码
) q4 t1 J" J! j& Q/ @
或者直接修改CCRx寄存器的值:
  1. htim3.Instance->CCR1 = 300; //通过 htim3.Instance->即可访问与定时器相关寄存器
复制代码

1 O5 g0 |: G2 C, p" T7 r, u* Q. i) M
    实验现象如下:
) r( k7 O/ y# U4 l
微信图片_20220626134009.gif

1 x1 M# y$ j0 K- k7 I
1 J3 Q/ s/ r# b! T5 W0 u
收藏 评论0 发布时间:2022-6-26 13:41

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版