实验内容:使用通用定时器输出PWM,实现呼吸灯效果,呼吸周期3S。" V; o) q9 C! J) K+ X* q9 H( b
. H3 ~) t% x) B! `
一、原理图
c$ [0 j; s% q& W* w4 C" [8 f
0 t+ u( G6 x- a2 c$ U- H
4 [) ]/ ?+ F( g$ C! r; p% e6 c! w7 ]( D4 h) E g
二、 CubeMX配置
+ N9 Y1 c w, b6 ?) M" E( E$ J8 g
* c# |+ z& \" C- FStep1.打开 STM32CubeMX,点击“New Project”,选择芯片型号,STM32F103VETx。3 ? X6 P0 \5 j! P
: V% J9 g4 Q! \! B8 {: h5 ~
. g% I9 P; U( F: c9 D! I9 |* y
7 R9 w8 {0 R; `& T5 ] Step2.选择时钟源,并配置时钟树。选择Crystal/Ceramic Resonator,并配置系统时钟为72M。7 J; G2 b# T! r) R0 D: K
5 |6 l3 H2 N- b/ O6 o" L( m
2 {3 M: n3 ]# O1 u- _; c
2 L" a4 }) {8 g" [ b; T. ^. Z
% z0 M) \1 y* n; q% }1 @# J8 A% L
/ w: b* q) `) VStep3.配置SYS,我们这里选择的是Serial Wire。(正常情况配置不配置不影响,debug可以使用。但是你不可以把这两个引脚用于其他复用功能,如果用于其他复用功能,debug就不起作用了。)9 N7 J: E- \" X8 G+ R }
8 Y/ D4 A: O3 Z3 k. f0 C! B
- U B8 t" ~& S% Y8 _
: J3 O+ }0 G! j2 a* P* b" vStep4.配置定时器,时钟配置计数器时钟经过(719+1)分频配置为100khz,即计一个数的时间为10us,一共计数(299+1)次,即进入一次中断的时间为3ms。(注:图中计数周期应改为299)
9 X% x2 u) n; |) t
1 H+ e# n0 l! e: }" a. |, A
& `; k9 s( Z6 N0 m" r& E! ~/ o% c6 O! E( S
, t/ k' a' n: c! k# ], ?, J- G
5 S( g2 l" u2 e+ v2 g
. ~5 l* u" H0 v4 {8 c4 q
7 u. d2 {1 e, O$ Q+ V5 E 到这里关于相关参数配置基本已经完成,只需要根据之前文章《STM32Cube HAL:GPIO输入/输出(一)》Step4-Step8,设置相关工程参数和生成代码。
; M6 H/ B: w: w s1 R' M# [+ c7 l/ X; Z* b$ w
三、添加功能代码
3 Q. l$ {: g# F
, Z* @. z3 }9 v3 f7 Y1 T我们此次采用的查表法进行占空比的修改,我这边是用excel生成了一个呼吸曲线。(采样点为100个)
9 J0 f7 z8 U$ I, e2 x+ A `
( m5 \) r s' s/ s: e8 P; ^
$ D) I8 z6 r, `% ?; W# k# i
: [# i' T: F/ [ 在main.c主函数外定义相关变量:
5 ?6 F# Z( @" ^0 L! Y; J- V8 W
0 @1 [' N+ {) g- uint16_t int_cnt;//中断的次数
( }) d( F4 a3 |6 d0 K - uint16_t duty_cnt;//不同占空比在数组的位置( l5 l- x2 E% z* v) G# w
- uint16_t duty_value[100]={1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10,
1 L8 D4 l$ X5 }) Z* c; e' C - 12, 13,15, 16, 18, 21, 23, 26, 29, 33, 37, 41, 47, 52, 59, 66, 74, , s8 K4 G# K$ w& Y3 O
- 83,94, 105, 118, 133, 149, 168, 188, 212, 238, 267, 300, 300, 267,5 y6 F! p9 O4 F; o' b( g% K
- 238, 212, 188, 168, 149, 133, 118, 105, 94, 83, 74, 66,59, 52, 47,- ^+ d9 H1 @9 r" r _* I3 ^8 ^3 n
- 41, 37, 33, 29, 26, 23, 21, 18, 16, 15, 13, 12, 10, 9, 8, 7, 6, 6,9 Q7 g8 k: l0 X7 A) e) c# N
- 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1};//占空比的取值(采样点)
复制代码
3 h( w; j/ {* W/ g& e4 a在main.c,主函数内(while(1)循环外)开启定时器,使能更新中断和PWM输出。- __HAL_TIM_CLEAR_IT(&htim3,TIM_IT_UPDATE);//清除中断标志位,防止一使能定时器就进入中断" o0 |7 |8 t! m% i8 k
- HAL_TIM_Base_Start_IT(&htim3);//使能定时器,和更新中断! `$ V. U5 [, C* q! k
- HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);//使能定时器,和PWM输出
复制代码 + M [3 X, q* v+ I9 c; t
在main.c文件中,写入回调函数:
; M. \! R+ \% j- J8 d2 `1 P) H
# M5 u! Z) P5 z: q- T" u. a9 q: u- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)# w- p9 w7 [( F4 T3 ? R( @
- {7 v; }, u2 }; O+ h% I" {
- //每进入一次中断,int_cnt加18 B n# n' l' e+ c) z7 c0 g
- int_cnt++;
' y) |& ]0 B0 N4 d. k' f2 X - //int_cnt=10,说明进入10次中断,变换占空比
( _! I3 W, t; n+ t; R$ J. K) l' l - if(int_cnt==10)
! f Z: v/ j" N - {
% k$ d' U" i- h3 I- \ - //从duty_value[0]到duty_value[99]共100个数
& C: t* ~2 U. C - __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4,duty_value[duty_cnt]);//用于变换占空比9 d+ i( P3 D4 L' T/ j
- //通过自加,来变换占空比+ T( J, A3 e: M7 Q( n6 A
- duty_cnt++;
& X) [9 r J& l& Z. \ - //表**100位数,使用完以后重新从第一位数开始
0 `! z2 |" _2 W! T - if(duty_cnt==100)
& A- N5 g; w: l1 V+ U+ l8 l5 C - {: z' C& u5 t8 W; i' a* _
- duty_cnt=0;
; C1 Y m% {( [9 S& Y - }
3 w. |- \' v0 i/ v - //每十次中断以后,中断重新计数
& ]; I9 }& k$ A. U$ \ - int_cnt=0;
6 O0 N4 A7 w5 v* X - }& J" A* b9 ]2 X) v3 u
- }
复制代码
: N/ |9 X1 _, b; m3 k! u
. ~& o) i: V7 ~+ J 结合时钟配置以及回调函数我们可以知道,我们每进入一次中断的时间为3ms,而每进入十次中断就会变换一次占空比,即每变换一次占空比耗时30ms。我们一共需要变换100次占空比,即一次呼吸灯耗时3s。
$ }7 S, h: d# u- N L
i' C3 d9 E0 C6 |- a
- m) j9 D4 ?: d2 ]$ F" ~0 z I" p |