本帖最后由 黑夜之狼 于 2016-11-22 16:00 编辑
/ X) x4 `/ g5 I! ~* c$ Z) o) E
- j* D7 A9 W# S, ?+ @! z3 r+ l- { c在前面的两个帖子当中,我们介绍了GPIO和UART通信,这次,我们来介绍单片机里面很普遍也很重要的一个外设——定时器。( ^! d5 w" }) ?
1 f' E" `+ {) W% X为什么说很普遍?现在的单片机最多的共同点就是:串口和定时器。串口未必每款单片机有,但是定时器基本上都有。为什么说很重要?定时器的应用范围太广了,不说别的,单纯看STM32的参考手册,大家应该可以发现讲定时器的内容已经占了1/3(P220~467),可见其重要性!: n/ k2 z8 O$ m/ D! J
; c; f) D3 q( a" J* B z: x
STM32的定时器功能十分强大,F0系列的定时器分了高级定时器(TIM1)、通用定时器(TIM3/14/15/16/17)、基本定时器(TIM6/TIM7)三种。本次实验当中,我们将利用通用定时器TIM3中断来实现闪烁灯这个实验。
n7 y) k4 _6 Y- ?4 t- W" d
$ i7 v5 f( Y$ d7 SSTM32F0的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。每个通用定时器都是完全独立的,没有互相共享的任何资源。( c+ V/ s* k9 t8 X5 W' L6 ^& {
" C7 H6 V5 _6 h) i
主要功能如下图:(参考手册P294)
8 n& [. O, u2 `' H* U1 _ ?* A
, u" f+ J) F0 q$ y3 ?7 Z5 D( Q4 Z* f! z4 c6 v
定时器TIM3中断的配置可以总结为以下几点:
- r2 L% T) \9 v9 j3 ~(1)TIM3时钟使能
- c# ^, ?, T B) K9 `$ ? TIM3是挂载在APB1上的,所以我们通过APB1总线下的使能时钟函数来使能TIM3,调用的库函数是:5 t) O# z/ \! a8 x r2 C. ?0 l" C
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM3时钟
复制代码 6 O7 T* s5 B2 M- b; ^4 O: B: Q% O
0 P$ Y/ a A% h8 a
(2)初始化定时器参数,设置自动重装值,分频系数,计数方式等
, r$ a; Q8 b( Z9 N5 ?* I( ` 初始化定时器参数是由库函数 TIM_TimeBaseInit 来实现的:/ v# y! ?! M: P) t1 t3 Y, }
- void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
复制代码 第一个形参是选择用哪个定时器,第二个形参是定时器初始化参数的结构体指针,结构体类型为 TIM_TimeBaseInitTypeDef,我们可以打开 stm32f0xx_tim.h 这个文件看看这个结构体的定义:- typedef struct
$ E- t3 S8 f7 I& y7 [ - {& C6 m+ g9 V9 d5 _* t
- uint16_t TIM_Prescaler;$ y0 t! d& |6 d( o
- uint16_t TIM_CounterMode;
) w" H) |, s6 o: T; } R - uint16_t TIM_Period;+ X3 `6 @# G; j1 O2 _
- uint16_t TIM_ClockDivision;8 @$ h! E( g4 t' q+ y
- uint8_t TIM_RepetitionCounter;+ l' ~ z/ h; U( ^5 b5 R8 J
- } TIM_TimeBaseInitTypeDef;
复制代码 从上面代码可见,这个结构体有5个成员变量,但是,对于通用定时器来说,只有前面4个成员才有用,最后一个成员Tim_TimeBaseInitTypeDef只对高级定时器才有用的,这里就不多解释了,等到用高级定时器的时候才来分析吧。
( e6 O' Y. D. _; ]4 _ U M# A0 X
; N. [1 K5 e+ t% {/ d针对TIM3初始化,具体配置代码如下:
1 K" O H/ M. k) q6 L- r$ c- TIM_TimeBaseStructure.TIM_Period = arr;//设置在下一个更新事件装入活动的自动重装载寄存器周期的值* D; ]$ o9 k3 ]; [% s* |/ _$ M
- TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值/ P8 \& w/ o) F# J6 Q A L
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim7 h8 a* m9 L! s" L! e1 X
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式( s% P/ m' j& G, T) O
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//根据指定的参数初始化TIMx的时间基数单位
复制代码 这里有arr和psc这两个形参,可以通过在main函数调用的时候作为输入形参使用。/ Q3 I+ \7 W$ @- } `; R
中断时间的计算公式如下:
+ ^9 Z- [/ i- d- R Tout = ( (arr + 1) * (psc + 1) ) / Tclk
5 n6 m. i, i5 [! K4 n/ l0 H Tclk:TIM3的输入时钟频率(单位:MHz)
) y$ n2 L2 j, U1 u; C Tout:TIM3溢出时间(单位:us): B) A8 {) P; T0 D1 A
我们这里定时500ms,可以令arr = 4999,psc = 4799,Tclk = 48MHz
3 w+ \5 ~8 B9 ~. D& f' K即:Tout = ( (4999 + 1) * (4799 + 1) ) / 48 = 500000us = 500ms
+ t! @* F3 u' m3 o# Q# E5 h- O" L7 K2 @
& a( a0 t9 t+ j(3)设置TIM3允许更新中断
& C- ~$ r' J# D 因为这里我们需要利用TIM3的中断来实现闪烁灯,所以要允许TIM3产生中断更新,库函数如下:6 p( D8 {! z# E: ]
- TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能指定的TIM3中断,允许更新中断
复制代码 7 U; G* M1 z. _: `7 \
(4)TIM3中断优先级设置% O# Z; x7 x8 T
既然使能了TIM3中断,那肯定要配置它的中断优先级了,具体代码如下:% k* V& B# ~' Q9 l0 [8 }
- //中断优先级NVIC设置/ L8 E" L. v, e; x4 ]4 O* Q/ y% K
- NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; 2 R. c8 f: b$ B0 ?8 k( o
- NVIC_InitStructure.NVIC_IRQChannelPriority = 3;7 f( n. B# F& Y$ }' ~
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; e7 w( m3 n0 ~ i* @. f
- NVIC_Init(&NVIC_InitStructure);
复制代码 N1 _' f; W8 \0 J& R9 `" J
2 D9 A1 j8 e9 ~9 Y# Q8 i" H! P(5)使能TIM3
1 |5 i% S- O2 e$ ~ 这一点最简单,库函数如下:( ~1 x# m, \- R5 G
- TIM_Cmd(TIM3, ENABLE); //使能TIM3
复制代码
7 R* K* B, D; w& X8 v' Y Z5 i5 p7 M
- q; n8 L, r) V! U(6)编写中断服务函数. z: n/ Z5 w2 C
最后一步,千万不要忘了写中断服务函数(当然,你可以用查询方式,不用中断)!我们这里是更新(溢出)中断,在中断服务函数开头,首先要判断是否溢出,然后执行相关操作(这里是翻转GPIO输出状态),最后清除中断标志。具体代码如下:
8 H- D6 }! t5 Z" m2 i0 T- void TIM3_IRQHandler(void)
9 v o( L( Y/ j9 g: n8 u# ^ - {
2 m0 `8 G) n6 t3 d - if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) * m% ?! p' D! W( n8 p
- { : H6 u! c1 `2 w& m6 H2 e/ U
- TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
' o% Q( g4 I/ @% Y" V - LED2_Toggle();2 T% U, p2 @- Z( X; Z
- } . K' ?8 I) P/ `3 O
- }
复制代码
) o1 r: ~# ]6 C, @1 Z! g0 F通过以上几个步骤,我们就可以利用TIM3定时器中断功能实现对LED的状态翻转
7 p2 u& C4 i* }+ e" a; S9 y& k6 ~' B
$ J L% Q; q H( m$ L' U" Y# m上传工程代码:
) q' ^0 |) R! | x$ @
STM32F030_TIM3.rar
(2.04 MB, 下载次数: 198)
|
可以用,可以参考库函数里面的例程