定时器分类
- A& h% [/ B0 N9 uG0系列有TIM1、TIM2、TIM3、TIM6、TIM7、TIM14、TIM15、TIM16、TIM17,它们区别如下图
4 l4 E7 r J8 Q& i0 l, f5 u9 w
$ |' V: R1 k/ L其中TIM1为高级定时器;TIM2/3/14/15/16/17为通用定时器,TIM2支持32bit;TIM6/7为基本定时器' G4 T0 ]- L* F! \7 ]5 H/ G
w7 d, {& q5 b* z; Q. i7 I9 P
- r& D0 E: x( x, v
% c, N* Q% {) N- Y7 ?3 ]. K. m' v
6 x$ e( H1 I: S$ I3 M4 Y8 ^; s0 D8 g/ k w# d, X
计时器时序图( S) \2 R3 j( T' g
TIM1,TIM2,TIM3支持(中央对齐)向上向下模式,方向在向上向下时发生变化,减少对电机的噪声干扰。6 P* j# Y6 Q I
& X4 f4 k/ W: I1 b
$ X Q+ f/ n8 \8 M+ b: {2 R3 O' p3 z' w ~
0 `6 u. d& Z/ T# a( T
- _% ^' N7 r( k+ T0 L' o$ v/ k 基本PWM模式,边缘或者中央对齐模式
& @6 q8 ?5 r+ `+ f# M) v* R5 c* Z! ]$ y$ e
1 Q8 r9 j( e8 C8 i$ u3 H; M4 D( ] p. k( l, z7 {* _
非对称PWM模式
2 N* i5 g2 O7 U- e, K+ t# r. k4 I' u* F2 X$ d$ p
! d2 p! @$ j7 \. Q) Q
& i- l: e" p8 k( A; L# ?3 f4 t三相组合PWM模式' M% v8 k& Z9 w5 o3 s6 e! F
! E) w2 P: }1 }( b3 P4 ]: B; M
) o+ z. C5 T3 o5 K7 {# U" f3 q/ Y
可变频率pwm,由外部信号驱动。 逐周期控制的占空比。6 i; X$ K- W+ K6 Q; R
; G1 n9 v- F, L9 G% W
1 s, D% O& Y, e5 s4 c# ^
! p1 B% U1 s. q2 J# z- p+ W
TIM2定时器实验; S' y; p D% ^4 j* |: ^
本次实验,我们选择TIM2定时器,通过设置预分频系数(PSC减去1)和计数器周期(ARR减去1)的数值,来控制整个定时器周期。让定时器周期进入中断,在中断函数中翻转PC6引脚电平,达到闪烁的目的。
: Q1 ~5 N4 o8 Y8 G! E* Q. Z+ L1 q& l* D. [9 N( O/ q
如何计算定时器周期?0 ~# |6 w, K& C/ R& F. H5 }/ u) ~
6 u% r6 m5 H9 F' Z3 r3 W1、在时钟树中确定好TPCLK频率,这里已最大化频率运行;
$ q# l+ |/ `) J; M0 G8 Y; @
) q3 t9 S$ y9 C4 |( S% i5 K5 t ]' ?
) ^# [4 r3 ]6 n# m2 e, `5 ~2、确定CK_CNT的值 ,CK_CNT=TPCLK / PSC,为了便于计算我们一般都是将CK_CNT的值化为整数,
* }; d% f! D0 h
[: _% l7 a; g2 O4 q2 x如 64MHz / 6400=10000Hz
4 q9 o# e `- H& d7 C4 l- q3 ?0 Q( \2 @9 m- Y
3、确定ARR的值,ARR=CK_CNT* t(s),
) d# o3 }- x: q. ~' K
8 [3 L0 w: }* f5 L1 X- F% X5 T: p如要1秒周期,10000Hz*1s=10000。1 h* w4 N/ C9 B/ ?7 N
# R0 c- c/ s' o, Y8 v实验代码
2 f7 B( E7 G/ z' S K4 d1、新建芯片工程,"SYS"打开"Serial Wire"调试接口,"RCC"中HSE使用"Crystal/Ceramic Resonator";
! D% Z/ R. D) `1 _7 p" U; B4 A3 G8 S2 C7 p
2、在"Pinout view"中设置PC6为GPIO_Output,默认电平为low,开漏模式,不上下拉,速率为低1 {2 N' g9 t% x$ E
8 v1 ]$ l, _7 h% d0 T2 J
& `" b$ d2 k( |& `
% S; A, w, N% G* f6 S
7 W* |8 [ n! d' @5 V; g; e0 M! K( S) T( r# L+ b) F( O
3、设置时钟树,使用HSE、PLLCLK,HCLK为64,APB分频系数为1,APB时钟为64
2 P# P/ ]5 t9 [. Q1 ]3 F, v- `$ A `& c
1 N9 C& j2 H) r3 g, k9 x
1 ^1 {0 s7 |- E4、 设置TIM2,在TIM2选项卡中,"Clock Source"选择"Internal Clock"4 F. o' ?+ f% c3 [0 R; n
( h! S4 @0 E. h* M& r* M' ]6 R! a! d
5、下面"Counter Settings",Prescaler填入"6400-1",Counter Mode(计数模式)"Up",Counter Period填入"10000-1",其他参数默认值
5 m' E% l( `, d% q, H' S3 T0 u4 r/ A
如想要1秒周期,ARR=10000,PSC=TPCLK / CK_CNT
" [' j8 R2 y* P+ L. k5 ^7 E7 t; \
f$ m% f. t* W# i O* T: E) Q: A: A/ V
6、在"NVIC"中,配置页面中找到"TIM2 global interrupt"使能,优先级选择"2"8 U' g, ?3 F5 c$ G# U
# y. d- K% n* k4 w& v& X( N
: [9 p6 m2 Q z, q* N, r; F- I) ~; l( U1 Y' q/ B/ N
7、在Project Manager中填入项目名,IDE版本“MDK-ARM V5”,在Code Generator打上勾,生成代码。
+ t# m7 X$ ] X
4 G# r/ y4 s) v8 L& ^
J3 k, k$ c1 g- t
+ {& C% _& m3 H+ j' V8、在main.c文件,int main函数里面,在代码MX_TIM2_Init()定时器初始化后面加上定时器中断初始化函数1 }7 S" P; h3 R/ u2 Z5 F
3 J% i5 J7 C& M3 V1 y" E- int main(void)
2 L7 B* v' l) i- h: r! k, `9 J% a - {
. X, W) z& ^' T5 N" u - **
4 F: h/ L5 U5 W& T* }' }4 n - **( |# ~% @4 K/ I
- MX_GPIO_Init();
. `: f, U3 H# V. ~* U7 R/ L& V - MX_TIM2_Init();
! L ~' O" t( |0 r) H& E - /* USER CODE BEGIN 2 */* v* c" y; P8 y2 k5 z
- HAL_TIM_Base_Start_IT(&htim2); //初始化定时器中断: Y$ G; s/ k# k& y+ v2 m, L
- /* USER CODE END 2 */$ m- {' L4 V, H$ [
- **
0 g7 o) z9 v* [$ e5 h* I% X9 K - **
复制代码 . M6 w1 P* d$ e
9、定时器中断函数原型为void TIM2_IRQHandler(void),里面调用了HAL_TIM_IRQHandler(&htim2),该函数有很多个中断回调函数,我们这个定时器更新中断,找到我们需要的函数HAL_TIM_PeriodElapsedCallback(htim),需要手动写这个回调函数,把一下函数复制到main.c文件中( Q$ C, z9 K L k
% |3 x/ S( \5 T( u; ~+ c- <span style="background-color: rgb(255, 255, 255);">/</span>*3 Y- d% \( c' F" M
- *stm32g0xx_hal_tim.c5 [) q/ Y. I0 J7 H, i5 `( J
- */( C4 d- m5 |0 V: {. Y0 n3 [/ @% O
- __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)/ y& t4 ^8 ?7 h4 G/ I5 z
- {7 e! w2 M& X& |- s7 L* V7 Z
- /* Prevent unused argument(s) compilation warning */
c# ]8 _: Z1 u& n - UNUSED(htim);# Z8 K" o- E$ n+ Y, y
- % _! g( q* H: B: M* }. L2 D
- /* NOTE : This function should not be modified, when the callback is needed, R: O' g5 h$ G% c
- the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
# n: W" a2 }9 v3 W4 r" p/ ? - */
2 W0 A6 w# W8 d7 v9 ] - }
复制代码
7 b3 Z' D. Q; ~2 ?10、在int main(){}后面编写代码,编译,debug中勾上"Reset and Run"烧录固件,就能在开发板上看到输出闪烁。
2 q6 K* G6 S& M( b5 m8 z2 G5 M
7 Z! ~7 @8 A5 ?4 M! y6 n1 N- /* USER CODE BEGIN 4 */# o: S2 g* Q! l5 r
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
9 ? d- A7 a: d' Z - {! J, ~0 D1 Q3 M- |
- /* Prevent unused argument(s) compilation warning */
+ |/ i& w* @ ^# q - UNUSED(htim);+ E8 b; Q; b8 r2 [
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_6); //只有定时器有中断,就翻转一次引脚电平
: ]+ B9 T, k- A& \% E; v - }
7 T- H* r" `4 `8 d& E - /* USER CODE END 4 */
复制代码
- s1 k/ h5 J" B" P+ p2 m* @) V6 V9 R8 d1 m1 l- u4 j. C: ?( E% k# c
- Z7 S% H+ i% R. C9 F
, v0 a! F; o- n) P
8 O" O1 h/ K' P. ]- c) s
2 [2 M G q# _
6 M& _7 b) r+ x |