STM32F103单片机中定时器分为3种,高级定时器、通用定时器、基本定时器。
5 ^3 }( d' D( e4 t* ]0 A
; z3 o; f1 r& H% I- X 高级控制定时器(TIM1和TIM8)由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、PWM、嵌入死区时间的互补PWM等)。使用定时器预分频器和RCC时钟控制预分频器,可以实现脉冲宽度和波形周期从几个微秒到几个毫秒的调节。高级控制定时器(TIM1和TIM8)和通用定时器(TIMx)是完全独立的,它们不共享任何资源。它们可以同步操作。+ G# }- E# h! i5 M4 v& p
) j) Q, M" O f' j
TIM1和TIM8定时器的功能包括:
, I8 U7 b% w0 x1 \: H+ \3 h2 T$ ]# T' Z) g; ^2 Y+ P q3 R
16位向上、向下、向上/下自动装载计数器
7 A! a7 m* G4 g& e16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值
- N' _; F8 M6 o* W! ]4 B多达4个独立通道:5 E+ ?( k0 c4 ]% h: l8 Z
输入捕获
( u+ }1 c2 n4 ?2 r 输出比较! {! U9 n, L7 w
PWM生成(边缘或中间对齐模式)
8 w2 T- ^1 W# T* _6 e 单脉冲模式输出- F/ K- u8 H; m2 W0 D- o3 Z# U
死区时间可编程的互补输出1 ]7 Y7 g* M$ k- n1 x& ^% K
使用外部信号控制定时器和定时器互联的同步电路# [$ v, E' ?! Z% ?
允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器$ f" l/ W6 V* i, ~* I
刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
- w3 W! b1 w3 n) Y4 @+ g* ~. D9 d7 h如下事件发生时产生中断/DMA:1 T, ~7 Z1 j* I! N+ `& S3 U0 j
更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
4 O% J% j+ v) _+ d1 ^3 N 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
0 p, `- R4 F! }* A& E 输入捕获 输出比较; Q7 r% x8 v' f' K* M. |4 D$ K/ I
刹车信号输入3 d6 ?$ J$ J5 P: V9 g% R7 i
支持针对定位的增量(正交)编码器和霍尔传感器电路) E% R7 n' J3 c5 A3 l( M" n
触发输入作为外部时钟或者按周期的电流管理
& \/ d7 C9 l8 _$ N, P# `; U# l' D/ K
可编程高级控制定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数
/ j# Q$ h5 [* m器可以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。计数器、自动装载寄存器和预分频器寄存器可以由软件读写,即使计数器还在运行读写仍然有效。7 D; ]: u+ O7 U4 {8 O$ Y
# r, d+ n7 ?0 x 高级定时器初始化方法如下:9 ?$ Y6 z g( v& [. j8 K
5 |+ ~$ s8 F( k$ ~8 P, N
- void TIMER1_Init(u16 arr, u16 psc); _/ t9 f! L4 i1 i
- {* @/ y* Y% s7 s. a% l/ ], f
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
* K: N9 T; d; l* [" i+ } - NVIC_InitTypeDef NVIC_InitStructure;( D4 U- H) F& M; }6 Q7 x' t
% f% x1 Q8 X% I! Z7 p- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);% b$ U5 t7 F% f, {( k' o( O
- ! Y* i: s, [8 V) R$ h$ E
- TIM_DeInit(TIM1);
. q+ \0 R: e0 Q2 l - 0 Y/ B) r* j/ l8 }% q9 I" H
- TIM_TimeBaseStructure.TIM_Period = arr;
8 l t- i. G; K* u - TIM_TimeBaseStructure.TIM_Prescaler = psc;
/ r% U ~6 s) [/ U5 b! e- W - TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
9 W: i5 v: F$ T! o# \, h. S - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
7 ?% ^, g+ L$ z0 `, ]4 @% ^2 { - TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x00;
U3 @7 U2 }! m$ ]0 ] - TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
$ X! @# _2 u5 J3 s2 X - 3 {7 X9 Y5 G3 d% `$ }
- TIM_ClearFlag(TIM1, TIM_FLAG_Update);( W8 O" q* H1 q: c* v
- TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //允许更新中断
8 c) m* p$ Q. @, M6 F4 b
" Z; J0 a, b6 P$ E& Y$ V- NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn; //TIM1更新中断
! ]; d- ^! E; ^. u* Y - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
+ b$ _8 E+ ~! l; L; u8 P - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;1 c' ~8 O+ }9 m) E0 S Z( c/ z
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
8 o$ b! o9 g+ |- y1 S - NVIC_Init(&NVIC_InitStructure);
8 @) _/ x) a- ?' m
0 v/ }6 G% R5 ^ c- TIM_Cmd(TIM1, ENABLE);
3 ~& W1 B; H, y% n# V - }4 u2 y% n8 k! C4 l7 [3 ^
- void TIM1_UP_IRQHandler(void)- l6 R0 G* f* v; K( P7 @& S; q: W6 o
- {
+ S4 k- p2 v" y8 H - if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
. [) r9 B7 u% v3 v% M - {" H7 ~& [& t- z
- TIM_ClearITPendingBit(TIM1, TIM_IT_Update);: `* G4 e+ Q; e! s) j d3 c
- LED0 = !LED0;7 _+ w1 C. `/ l6 e* v* W" U( `* {5 g
- }
; h( c6 s) `( u" ]! | - }
复制代码 ; E9 B) `; A* W9 m
这里使用的是定时器1,在初始化时传递了两个参数,其中arr用来设置定时器的周期,PSC设置时钟的分频系数。默认定时器的时钟频率为72MHz,所以带入这两个参数后,定时器的周期计算公式为:
! {& O( Q9 Q) Y' O, }(arr+1)*(psc+1)/72MHz,设置定时器的计数模式为向上计数。接下来还需设置重复计时器的值。TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x00;这个是高级定时器特有的一个计数器,默认设置为0,表示定时器永远循环计数,不会停止。如果设置为一个确定的数据,那么定时器执行一定次数后,就会停止运行。如果定时器需要开启中断功能的话,还需要设置NVIC寄存器,用来设置定时器的中断优先级。3 \$ U+ C/ Z/ F
$ ~* F u( q( w; J9 m3 V, G- int main(void)6 a; u* x( a3 `
- { ( W* n; Q% Q; A D
- delay_init(); //延时函数初始化
6 P( k( U3 q( u* d* } - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);9 ^1 x: i, P/ D. g- O. X- \( f
- LED_Init();( f" `& L+ k! Y/ X1 w" i9 r
- KEY_Init();
$ K* Q7 U2 V& d - TIMER1_Init(9,71); //50Khz 10us Tout=(9+1)*(71+1)/72M=10us- m/ Q5 P* Y7 V# I5 Y; |8 f
- + J t8 P/ l' T7 z
- while(1)
3 R- j) X" B# ?9 z6 r/ Q. o. b - {
+ X0 g9 U- E! h7 r: b. h0 y4 x - }) ^6 s2 K" P! c; c/ A
- }
复制代码
! ^4 y+ j$ Q1 c( k7 S 在主程序中初始化定时器,这里设置定时器周期值为9,分频值为71,计算出来的定时器周期为10us。在中断函数中让LED灯取反,通过示波器观察就可以看到,LED等每隔10us电平就会变化一次。' p5 P- o& `$ ~- l. R
N* s* l3 U+ @
7 m( {. a, k- G) y( a. c3 O$ s3 z
|