STM32F103单片机中定时器分为3种,高级定时器、通用定时器、基本定时器。
9 b& M: z" C1 t j1 V J t! a
" k5 O: H: ]9 N- G4 K4 F 基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。它们可以作为通用定时器提供时间基准,特别地可以为数模转换器(DAC)提供时钟。实际上,它们在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。这2个定时器是互相独立的,不共享任何资源。% S1 G8 U' e4 P% E+ F7 S& ?
* l& U+ p0 D. T- O' w; V1 E3 c6 o
TIM6和TIM7定时器的主要功能包括:$ u) @8 N9 Q/ Z$ Y3 X: X2 l
8 o: x% C& l' ?- ]$ C4 {* Q16位自动重装载累加计数器
$ x! ]: r$ F" o0 A( {& a. J* L16位可编程(可实时修改)预分频器,用于对输入的时钟按系数为1~65536之间的任意数值分频, q! \( s8 `% c& w- B5 ~. s' _
触发DAC的同步电路
5 v' A/ q1 v' d. s' @6 m/ ^+ H7 K6 ~在更新事件(计数器溢出)时产生中断/DMA请求8 i N/ ~$ y, @. F4 ^5 u
这个可编程定时器的主要部分是一个带有自动重装载的16位累加计数器,计数器的时钟通过一个预分频器得到。软件可以读写计数器、自动重装载寄存器和预分频寄存器,即使计数器运行时也可以操作。
& Z% q: U6 B# G* @8 d9 A& A0 b7 [; t3 Y7 R4 Q: A
通过上面的介绍可以看出,基本定时器的功能很简单,就只是提供一个简单的定时功能。下面通过代码演示基本定时器的定时功能:- // 中断优先级配置
0 P; [* ^ w V" h - static void TIM6_NVIC_Config(void)* d, A% `& c* c: n4 \7 o* T5 l B
- {
- p' f5 Q5 Q$ ?9 V3 L8 @6 Z - NVIC_InitTypeDef NVIC_InitStructure;
" e: }: m# p7 _7 v8 w - 1 i$ ~: q1 [, X+ U9 f
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断组为0
m- M5 F' H3 u3 I/ L - NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ; // 设置中断来源
" v1 G- f8 O0 m8 g8 `4 e+ x - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置主优先级为 0 # v' o, n. _. o, R( y
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 设置抢占优先级为33 S5 Y8 V+ E# {$ Q
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
* i$ }! z3 c, i6 x/ A1 Y- b: K - NVIC_Init(&NVIC_InitStructure);& p1 T' q6 T# ]; t' L
- }
# J4 [% f1 a- n3 h7 H- J4 p* p - /*6 c9 I# u- v3 E9 S
- * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
% s, }: M5 K$ J2 d7 b - * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
! ^ `: v; _. d6 z) a+ u - * 另外三个成员是通用定时器和高级定时器才有.
' K6 p, E! S W+ p' {# M - *-----------------------------------------------------------------------------
. i. \& |1 l- Y, q - *typedef struct
9 t) K/ @* d! @! O* A: q - *{ TIM_Prescaler 都有
9 s& n0 c' v. R - * TIM_CounterMode TIMx,x[6,7]没有,其他都有! C. B# S7 f1 a
- * TIM_Period 都有3 ?5 h3 M. h K8 R: S3 R: C4 e
- * TIM_ClockDivision TIMx,x[6,7]没有,其他都有
" X7 ], |' R+ t, w" |6 M, G7 c - * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有. g7 X: e i* y0 E3 B; \
- *}TIM_TimeBaseInitTypeDef;
9 C8 v4 @) z' m6 g1 x - *-----------------------------------------------------------------------------
0 P8 r1 ?7 [5 Q9 J+ d1 i& I' y - */3 i; J W8 ^/ t4 r7 N
- static void TIM6_Mode_Config(u16 arr, u16 psc)
: |1 w- `8 G6 T - {
5 @; z" {0 u3 v% \) l' X - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;- a( r5 H+ R$ E2 m/ l% g7 x
O2 P( U2 \5 s" [3 o, E. X" o- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); // 开启定时器时钟,即内部时钟CK_INT=72M
4 T( W6 k" L; B7 I* M: e$ \ - TIM_TimeBaseStructure.TIM_Period = arr; // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 E$ y' V/ q @1 K3 P
- TIM_TimeBaseStructure.TIM_Prescaler= psc; // 时钟预分频数为
1 F' L# w' L3 } - //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 时钟分频因子 ,基本定时器没有,不用管 # J- X$ c) i2 z+ ]
- //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
! G# j/ H$ Z* b9 t9 u9 l- I - //TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 重复计数器的值,基本定时器没有,不用管
- c8 {* B/ K$ i9 Q; j - TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); // 初始化定时器
( F: {6 ?7 p/ ~. @8 p9 H, S: d9 N/ d - TIM_ClearFlag(TIM6, TIM_FLAG_Update); // 清除计数器中断标志位
- Z2 K- H7 a5 e - TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); // 开启计数器中断 ; J# ^( \4 C& e! k _+ H$ h! _
- TIM_Cmd(TIM6, ENABLE); // 使能计数器, B0 w& `3 D1 q
- }
, u. x+ }) {5 U! ]1 p
9 C: r4 |( |4 N- void TIM6_Init(void). P+ r- b9 r, ]3 D7 t% N; u% B
- {: U6 b, i; O( P# L$ m4 Q6 b' X
- TIM6_NVIC_Config();1 r6 Q, z! n- _5 @5 [, Y
- TIM6_Mode_Config(10-1,72-1);
# s! @$ J( L5 K+ S# k( | - }* ^1 K! `) s2 U) T u) z6 ~
- & p0 G, B/ |/ `4 }9 U4 e( K
- void TIM6_IRQHandler ( void )
& r6 T4 g6 [; T( B; i# {: R/ ^ - {/ O" p7 f# A, r: u% G7 V
- if ( TIM_GetITStatus( TIM6, TIM_IT_Update ) != RESET )6 _$ p. k9 N3 M& ^1 ]% W
- {
" k, q. u3 k$ |3 Q5 ^1 c& Z - LED0=!LED0;
, o f5 j# T" l; l6 S - TIM_ClearITPendingBit( TIM6, TIM_FLAG_Update );
* c2 f( K/ f5 H3 _; o$ ~! Z; ? - }
4 F# E; d. H* p# ` - }7 l# ^: K! K5 y& Q" N; V
复制代码
6 f) E, R/ e! X. J% F 基本定时器的初始化高级定时器和通用定时器简单很多,只需要设置定时器的周期值和时钟分频系数就可以了。如果要使用中断功能时,需要设置NVIC寄存器,这个寄存器主要是用来设置中断优先级。
& o1 g6 \) }/ e2 Z, R; c/ ~ a( W8 f R& b. ?0 f
- int main(void)
9 E6 N* } O, R! }7 C - {7 l0 i; u4 y; v; N U. @
- u8 key = 0;
) d: ]1 w0 }! i @ - delay_init(); //延时函数初始化
4 @0 n0 V1 W) K+ B; \" \ - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
z% _1 q0 Q0 e, I$ V0 E - LED_Init();% s# T9 M4 n# y, t* E" d
- KEY_Init(); + \4 g8 f& S m4 c( h
- TIM6_Init(); 1 b! R L8 z* p, U- C* }( u
- while(1)
2 ?' h& f5 c( x, [ - { F0 J! Z7 U. m1 ^: U( r, j
- }
0 g. s" l: _2 U5 p+ t8 [ - }
' q6 ~. v; _2 ]6 U5 h+ q- y0 M
复制代码
- D5 q5 h R; N* N% e 在主函数中调用定时器初始化函数后,定时器就开始工作了。定时器时间计算公式为(arr+1)*(psc+1)/72MHz,将参数9、71带入公式后,计算出定时器的定时周期值为10us。/ A. a# e, e5 r* y/ x
( P& U+ p) H& d6 z" j9 w9 r! q5 {6 N* [
- g; p' x8 ?: C0 Z& ?6 b& z |