实验内容:使用通用定时器输出PWM,实现呼吸灯效果,呼吸周期3S。
8 S8 Z: {" Z |1 p; y4 s! V" g X5 h d/ y% E M- R
一、原理图
3 T& }/ _& {5 p+ E1 \
: N* [! p. t) O- u, |
2 \4 F! T$ e4 p
+ I4 V' `. \- @+ C/ \; ~! ? 二、 CubeMX配置
3 T r! ]+ ?" b) n ]+ E5 C, O# s2 J: A
Step1.打开 STM32CubeMX,点击“New Project”,选择芯片型号,STM32F103VETx。5 y/ S0 r# v1 q0 q
9 {" X& I, y9 q! H
# g) X' [$ |6 ?" W9 ]
4 e. h6 t2 s6 H) u9 u1 b! u+ v Step2.选择时钟源,并配置时钟树。选择Crystal/Ceramic Resonator,并配置系统时钟为72M。
& Y+ w+ `4 Z; A7 _/ P6 j- Q$ L7 M+ @: V' s X6 d# d
! n7 r' }4 h$ w. {
2 r' A5 ?0 }6 E" l8 W, m1 e
7 o" ~5 H- D$ L4 y6 ?
( V+ g! c3 O3 l9 }% TStep3.配置SYS,我们这里选择的是Serial Wire。(正常情况配置不配置不影响,debug可以使用。但是你不可以把这两个引脚用于其他复用功能,如果用于其他复用功能,debug就不起作用了。)& i) n& U. w3 E3 y8 w9 q' q- u& G
8 Z& i6 [. }: q) Q) U& k# I0 m
8 y9 a( b2 I+ x. c7 b; n# h0 ?2 L7 _% \& x* N. o
Step4.配置定时器,时钟配置计数器时钟经过(719+1)分频配置为100khz,即计一个数的时间为10us,一共计数(299+1)次,即进入一次中断的时间为3ms。(注:图中计数周期应改为299)
: o) ~; r( J: ^! ]1 N+ a( u' T/ ?: {* ]0 U
# L$ {$ K6 ?+ H
" x M; {( ~% ?( `5 t, G1 r
9 w9 g' @: D1 O0 W. s7 T- m: l
1 z$ n0 I3 D4 p- r3 U. j2 L
5 W0 A3 Y, T' T/ b6 F# o# I, c 到这里关于相关参数配置基本已经完成,只需要根据之前文章《STM32Cube HAL:GPIO输入/输出(一)》Step4-Step8,设置相关工程参数和生成代码。; _* \0 Y4 i) g6 ]- Q
`# q$ J8 b# q E8 g# m+ C三、添加功能代码
% i- {) m8 f$ J4 i# P
6 I3 C; v. @1 w& X我们此次采用的查表法进行占空比的修改,我这边是用excel生成了一个呼吸曲线。(采样点为100个)
# Q6 a: q6 ~: _3 \ K- ~
/ j0 Y& j2 q/ i( ~/ F7 a3 j
3 S# J3 ^. B! c8 S+ f' X$ d3 A% {9 k# |( e% v; e6 r9 U/ ]
在main.c主函数外定义相关变量:
! L% z( Q$ d7 y d5 {) e
7 l7 D) H4 t) G; C" J5 v- X- uint16_t int_cnt;//中断的次数
( R1 o! o8 _ F+ U$ r6 Z: _ - uint16_t duty_cnt;//不同占空比在数组的位置: K/ f, y W+ g( V( w' R, r6 k
- 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,
( |& _" J. M1 S5 j- D - 12, 13,15, 16, 18, 21, 23, 26, 29, 33, 37, 41, 47, 52, 59, 66, 74,
* \. r3 I9 X- n - 83,94, 105, 118, 133, 149, 168, 188, 212, 238, 267, 300, 300, 267,
# A4 b( N; J3 X, J9 x7 b5 m - 238, 212, 188, 168, 149, 133, 118, 105, 94, 83, 74, 66,59, 52, 47,, f4 R9 h: X5 Y$ ~, T
- 41, 37, 33, 29, 26, 23, 21, 18, 16, 15, 13, 12, 10, 9, 8, 7, 6, 6,; B2 g8 {, o7 D+ L/ \
- 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1};//占空比的取值(采样点)
复制代码 9 M4 y0 w' c; Y$ D' d3 w
在main.c,主函数内(while(1)循环外)开启定时器,使能更新中断和PWM输出。- __HAL_TIM_CLEAR_IT(&htim3,TIM_IT_UPDATE);//清除中断标志位,防止一使能定时器就进入中断
! {5 p. a+ t r# b t' U1 \' Q - HAL_TIM_Base_Start_IT(&htim3);//使能定时器,和更新中断- e$ c# M& K% W
- HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);//使能定时器,和PWM输出
复制代码 8 h% k' [! A$ E( |" v7 _
在main.c文件中,写入回调函数:
, T3 d0 P& V% O9 m6 b# q7 O( i ?; Y) V, w* t I
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
* R# I p# J4 P* j7 P" m3 P3 L3 F - {
0 w' e# d1 |, e- d1 l- [$ X: D4 E - //每进入一次中断,int_cnt加1
7 X: ^ [& @7 R8 @, ` L - int_cnt++;, S- ~/ q) @) n, F" v- C7 F1 p
- //int_cnt=10,说明进入10次中断,变换占空比" [* y/ u9 o$ |2 M! I* G
- if(int_cnt==10)0 G. O: a* {3 U" V& z
- {1 J8 z2 R3 I) T0 [( x6 B
- //从duty_value[0]到duty_value[99]共100个数; _7 i5 ~$ C+ S. ^. O
- __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4,duty_value[duty_cnt]);//用于变换占空比 h! i( |; C+ @" M$ c7 w
- //通过自加,来变换占空比* [7 i& G! M) A+ s6 S7 S: r
- duty_cnt++;
* ~$ @" }3 v7 }( [, V; m( m* m - //表**100位数,使用完以后重新从第一位数开始
4 o6 T8 _. y/ q+ z7 E6 W5 q( t - if(duty_cnt==100)+ k3 N9 U3 y6 }. s9 i. C
- {
' o7 w; l4 b |4 j+ d+ { - duty_cnt=0;, z! C S2 F# R5 m. b) O) z
- }
: c' s$ M* ?0 s: h2 x - //每十次中断以后,中断重新计数
9 [+ S& `* K' s9 J- A - int_cnt=0;" F( c5 ^; N1 g- j5 ]1 O* i
- }# r* {- G6 Y- I, M3 O7 q+ t5 O
- }
复制代码
+ I8 k. L; k+ `. T6 w5 O
8 O$ @0 T# B; d; {1 k& I( g 结合时钟配置以及回调函数我们可以知道,我们每进入一次中断的时间为3ms,而每进入十次中断就会变换一次占空比,即每变换一次占空比耗时30ms。我们一共需要变换100次占空比,即一次呼吸灯耗时3s。
* g+ O0 }( O6 ?0 r
% [* V, [0 ^ k. K3 I0 G. S' n4 r+ h7 j, ~# {4 X( M
|