定时器分类
$ [ b' u% H9 m( |5 Q1 G4 _G0系列有TIM1、TIM2、TIM3、TIM6、TIM7、TIM14、TIM15、TIM16、TIM17,它们区别如下图/ T7 i- C J1 i
* I" C( i( V v5 R1 D0 @: O
其中TIM1为高级定时器;TIM2/3/14/15/16/17为通用定时器,TIM2支持32bit;TIM6/7为基本定时器
/ i7 {+ N% L7 {1 B; X- I1 c$ B9 F, h4 X
; D$ R: V7 Y7 _( n6 Z
3 ]+ C4 ^6 `) K- y4 O
* q0 O( w3 k; c( s: {5 x# X( z' ]: X
1 n# | c8 I' R* R 计时器时序图* P w2 L* @: l( ~* ^
TIM1,TIM2,TIM3支持(中央对齐)向上向下模式,方向在向上向下时发生变化,减少对电机的噪声干扰。
: E+ N0 g) F1 G7 ^9 o, N' q+ C$ q$ e, g9 a) y
& S/ d. r+ g' `1 H
& R0 v: j/ e+ R2 U# _" U# L' v( F
5 v/ }- Y1 c1 @/ z$ f3 i2 I/ T 基本PWM模式,边缘或者中央对齐模式
7 W- v2 ^8 k) U
4 Q9 S* F$ L$ \8 D/ ]) c6 o* H; }5 v% x
( j z7 O5 r" D0 s/ n 非对称PWM模式: _/ s5 f h, h$ ]4 e
* p! ]% b' |$ N8 }+ M: k2 ^* p1 y1 g# G& W5 r" G
% W1 |4 Q% {9 N" x; T& h( i) k三相组合PWM模式
4 b0 Q9 y' V5 M# E1 m% V/ `
. \2 S7 M9 W& I: \& m) ]! h* y
K. S0 R& Q1 h, o7 q' ~
; I3 u9 G' l8 Q3 B, Y5 ]; N 可变频率pwm,由外部信号驱动。 逐周期控制的占空比。
9 k; N- [* f0 `& }$ J6 @( Z# `* C% |7 S' q8 r. M6 k9 a0 d
$ v% p# C/ J$ B- i4 t- Q. @( ^2 R1 t ?, p! u: U; y. [
4 Z8 J1 Z' x; i* r
) `3 e% m: o1 `0 _ TIM2定时器实验
9 H) Q3 E! P/ v" C! `本次实验,我们选择TIM2定时器,通过设置预分频系数(PSC减去1)和计数器周期(ARR减去1)的数值,来控制整个定时器周期。让定时器周期进入中断,在中断函数中翻转PC6引脚电平,达到闪烁的目的。* a; d, \- C3 z4 K; G0 ~1 `8 k! V
! t' N' `8 H/ Q$ g e3 t7 ~3 j如何计算定时器周期?
# r8 q2 e, F" Z. `7 p6 t& |
. ]( w3 p, T( n* s+ R1、在时钟树中确定好TPCLK频率,这里已最大化频率运行;
0 S5 L0 Y% v, h4 U2 N
/ S4 Y1 q+ S2 S. {7 P& t0 x, Y9 Z
" T9 O) e7 j5 W0 ~8 Q B1 I. N& V& I g
2、确定CK_CNT的值 ,CK_CNT=TPCLK / PSC,为了便于计算我们一般都是将CK_CNT的值化为整数,
1 ` ^6 A0 D. I/ N( a; Y, Q+ {! G2 M W' t6 a9 k6 \- `+ t
如 64MHz / 6400=10000Hz. X( U" O1 }& n: ?
! {0 A: G7 @$ y8 P; H# n5 o' |, D3、确定ARR的值,ARR=CK_CNT* t(s),
- w& b1 ^' y; e! B' R" B* U( m* t9 z6 \% X- |9 T
如要1秒周期,10000Hz*1s=10000。+ K- }% Q) D/ n! d& v
' s) d% k: J+ a1 `; n( s, Q, L- c
实验代码
3 K+ A& P$ o' c d4 H; z1、新建芯片工程,"SYS"打开"Serial Wire"调试接口,"RCC"中HSE使用"Crystal/Ceramic Resonator";" \3 h5 I8 C" N! e/ Q% {. P
# |. c7 U, o, m& }% M2 @) z2、在"Pinout view"中设置PC6为GPIO_Output,默认电平为low,开漏模式,不上下拉,速率为低
* R. S6 q; G4 o) H9 V' e, F0 e/ w: \+ b0 `
) y& q) C( s5 Q% K, H+ G3 D2 S8 L! [( z
% i. i' l: v2 z# D& k, `
" E+ d" u* }" D G, O: ]. {+ {+ l
3、设置时钟树,使用HSE、PLLCLK,HCLK为64,APB分频系数为1,APB时钟为64
2 @* j* N2 w4 o/ T/ j9 z! l/ d' p& B: p
: O, C; y0 P( b9 W+ Z) f4、 设置TIM2,在TIM2选项卡中,"Clock Source"选择"Internal Clock"
; g$ Y5 r& z& L; c9 z4 l! Y9 R
) c: u+ j3 p2 [, `: L5、下面"Counter Settings",Prescaler填入"6400-1",Counter Mode(计数模式)"Up",Counter Period填入"10000-1",其他参数默认值
( Z1 p5 \; w+ E* ~' K8 f8 e) n& e' x2 a7 k' G4 d
如想要1秒周期,ARR=10000,PSC=TPCLK / CK_CNT
0 R6 ]( V' W; ?1 b" q- |, g+ x/ \& P0 v
0 K6 C3 o% a4 v
n' O2 F6 }* [! J6、在"NVIC"中,配置页面中找到"TIM2 global interrupt"使能,优先级选择"2"" ^+ y3 j' U4 f. I, y, Q
% n+ ], ^ A9 ]$ F7 U l& Y$ w H- s4 r
4 b# W( m( X& m, `- w% ?
7、在Project Manager中填入项目名,IDE版本“MDK-ARM V5”,在Code Generator打上勾,生成代码。* B% [3 R0 s# ^. {9 W. z i
w6 }2 z+ Y& k3 M, a
4 V: u4 S+ p! {
$ {" A/ e. [0 P9 K' ^9 q( Y8、在main.c文件,int main函数里面,在代码MX_TIM2_Init()定时器初始化后面加上定时器中断初始化函数
! }- ]% y* G/ X6 a# s4 M V; d/ e) q0 n8 t
- int main(void)# p; j! g$ _: W! Y9 n
- {& A; s; p( ?) b0 f! y3 o
- **
, t) J, ]: g4 m/ \- S/ w - **8 G: B; J" a( M( ^8 o* E
- MX_GPIO_Init();
( }" h. |" q7 ]2 O' m - MX_TIM2_Init();" ]: W% W4 F8 c% E0 G
- /* USER CODE BEGIN 2 */
# R: H0 @: y' ?' |7 _2 H: U: z - HAL_TIM_Base_Start_IT(&htim2); //初始化定时器中断
( ^, }. h7 l* f( b; H+ W1 d. @9 w' | - /* USER CODE END 2 */
8 m# c# k! l* y3 j - **
, v1 n4 L& s, j1 U" Q+ a - **
复制代码
, ]$ }- n' m4 w3 U. Y# C4 `9、定时器中断函数原型为void TIM2_IRQHandler(void),里面调用了HAL_TIM_IRQHandler(&htim2),该函数有很多个中断回调函数,我们这个定时器更新中断,找到我们需要的函数HAL_TIM_PeriodElapsedCallback(htim),需要手动写这个回调函数,把一下函数复制到main.c文件中
R8 v) l, n/ x! p$ K! V
. X5 e( d0 Z5 x! y: _3 a- /*
0 r; Z: q; o/ T8 ` - *stm32g0xx_hal_tim.c
7 k( F! f! k( z. L# D - */' L( n: Q: b0 f, n; w: n
- __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
: V g% x- D0 C8 |% A8 J$ r% V. b - {
+ g7 T/ Z1 C; w" x; a/ l - /* Prevent unused argument(s) compilation warning */
0 E& s: k( ~! b5 Q" o6 X - UNUSED(htim);9 L3 z2 H# }/ C
- + z, U: q% q( S! j8 F6 O% E6 \
- /* NOTE : This function should not be modified, when the callback is needed,: }7 j8 P) X- I4 w) o/ u
- the HAL_TIM_PeriodElapsedCallback could be implemented in the user file3 O6 ]" ?( N* T2 u* ~
- */& m' s- F* O! x; ~0 t9 C
- }
复制代码
0 k9 S) {4 e) D! L, X, U# x$ [10、在int main(){}后面编写代码,编译,debug中勾上"Reset and Run"烧录固件,就能在开发板上看到输出闪烁。
3 _- C# ]. B6 @5 Z. T) z7 w, E& u9 p8 |# g4 @$ r
- /* USER CODE BEGIN 4 */& x* |% b/ D! ?+ {& ]
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)0 S7 ~$ n% s6 T# o7 I6 j y
- {& f7 }' h* A% W
- /* Prevent unused argument(s) compilation warning */
3 _- o: x+ @7 Q- Y8 H' x1 _7 K - UNUSED(htim);
. L& V6 U& x& x. @) k: F - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_6); //只有定时器有中断,就翻转一次引脚电平
5 a' E$ q( D6 l* M5 h - }
" R- h1 [) c K% {9 b8 { - /* USER CODE END 4 */7 {& Y0 v5 T p% _# B5 m
& L6 {. x" m0 `& T* E) _
复制代码 ( k9 \/ j7 h. I D$ E1 B" O) w' k( _
|