你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F030 Nucleo64开发板测评之:定时器中断

[复制链接]
黑夜之狼 发布时间:2016-11-22 16:00
本帖最后由 黑夜之狼 于 2016-11-22 16:00 编辑
( Z+ c# K% C% ^& Z8 B; U" d
7 y/ r9 A$ c  _3 ?: c( Y- Q- v9 T在前面的两个帖子当中,我们介绍了GPIO和UART通信,这次,我们来介绍单片机里面很普遍也很重要的一个外设——定时器。7 }7 J$ k7 w0 I. B& r
5 i- G: `/ ~. N" o4 ^- P7 M* c3 O
为什么说很普遍?现在的单片机最多的共同点就是:串口和定时器。串口未必每款单片机有,但是定时器基本上都有。
为什么说很重要?定时器的应用范围太广了,不说别的,单纯看STM32的参考手册,大家应该可以发现讲定时器的内容已经占了1/3(P220~467),可见其重要性!
8 B! F' m: j0 k, T
4 @- g) r8 m( s) hSTM32的定时器功能十分强大,F0系列的定时器分了高级定时器(TIM1)、通用定时器(TIM3/14/15/16/17)、基本定时器(TIM6/TIM7)三种。本次实验当中,我们将利用通用定时器TIM3中断来实现闪烁灯这个实验。
, L* D4 I5 \* x8 G
2 D4 Q7 l  P) `STM32F0的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。每个通用定时器都是完全独立的,没有互相共享的任何资源。

6 Y2 P1 j* h& I
( D1 O+ {" u4 H+ A主要功能如下图:(参考手册P294)5 M. V. O. C; C; _6 d
通用定时器TIM3主要功能.png . [$ |3 L& ?" ]# X7 X! P2 K  O. W3 \
$ I: S  Z0 E9 ]/ ^$ b6 K
定时器TIM3中断的配置可以总结为以下几点:$ h1 T3 u4 a  }7 V- e
(1)TIM3时钟使能
1 {( g4 Z7 Z4 v- d         TIM3是挂载在APB1上的,所以我们通过APB1总线下的使能时钟函数来使能TIM3,调用的库函数是:7 _9 a  k0 z: R! P, I' T
  1. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);    //使能TIM3时钟
复制代码

6 l+ L7 u1 c7 a, W  p6 `' k# k- R- B
(2)初始化定时器参数,设置自动重装值,分频系数,计数方式等
3 W! h; H0 v3 `; m( P         初始化定时器参数是由库函数 TIM_TimeBaseInit 来实现的:# I  v0 B/ q( z1 n9 I3 w
  1. void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
复制代码
        第一个形参是选择用哪个定时器,第二个形参是定时器初始化参数的结构体指针,结构体类型为 TIM_TimeBaseInitTypeDef,我们可以打开 stm32f0xx_tim.h 这个文件看看这个结构体的定义:
  1. typedef struct
    - ~$ N1 F9 }5 C& ]+ B
  2. {
    , B) w( G. H& z+ X+ P! e$ x4 o
  3. uint16_t TIM_Prescaler;
    ) F( m8 _9 W% o/ v" O
  4. uint16_t TIM_CounterMode;
    9 q% V' J! a) `9 Y0 N
  5. uint16_t TIM_Period;5 G( U3 Y5 z/ G. [7 r
  6. uint16_t TIM_ClockDivision;0 {: }& V/ n4 h: H/ J
  7. uint8_t TIM_RepetitionCounter;
      _. ?) ^! l: |+ A! ?" ^
  8. } TIM_TimeBaseInitTypeDef;
复制代码
         从上面代码可见,这个结构体有5个成员变量,但是,对于通用定时器来说,只有前面4个成员才有用,最后一个成员Tim_TimeBaseInitTypeDef只对高级定时器才有用的,这里就不多解释了,等到用高级定时器的时候才来分析吧。4 R) C7 u0 D$ f$ l0 Z

& Y" t7 t! c$ W: D& o8 X; P
针对TIM3初始化,具体配置代码如下:, \& l4 G& D( s0 g. _
  1. TIM_TimeBaseStructure.TIM_Period = arr;//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    1 ^' D; X0 v! t+ k
  2.         TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值4 r0 F0 X. V  }: V
  3.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    $ g8 C" U* V6 H0 y, S7 I( g+ f' w
  4.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
    - i9 H: \5 S1 w/ X* U
  5.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//根据指定的参数初始化TIMx的时间基数单位
复制代码
这里有arr和psc这两个形参,可以通过在main函数调用的时候作为输入形参使用。5 k! |$ [9 p2 O& C1 a# Z' p+ g- v
中断时间的计算公式如下:
0 T3 J) U( s  S" J      Tout = ( (arr + 1) * (psc + 1) ) / Tclk
$ n" R( O* V$ {% \. A1 \) V, e      Tclk:TIM3的输入时钟频率(单位:MHz)
: l6 j% V, d* s' Q/ [* W5 z) s      Tout:TIM3溢出时间(单位:us)
) R9 I9 E# a/ Z8 s' C) A我们这里定时500ms,可以令arr = 4999,psc = 4799,Tclk = 48MHz
5 ?  T! A$ C' q. ]' e2 p. v即:Tout = ( (4999 + 1) * (4799 + 1) ) / 48 = 500000us = 500ms

) J* L6 d  _9 n+ O
: C/ `( P% g4 n1 i7 C

/ ~' m1 \2 Y, Y9 J+ P& l0 G4 w) f(3)设置TIM3允许更新中断) s/ ~* b( M6 D3 h$ M- I1 i
         因为这里我们需要利用TIM3的中断来实现闪烁灯,所以要允许TIM3产生中断更新,库函数如下:

" B1 q8 y  U! J; ^
  1. TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);        //使能指定的TIM3中断,允许更新中断
复制代码

9 @, U8 _" ^: V0 U. z(4)TIM3中断优先级设置  e: ~* n: s+ y2 Y4 l
         既然使能了TIM3中断,那肯定要配置它的中断优先级了,具体代码如下:
: d5 g# X! B' ^1 P8 C# U. s$ d( @
  1. //中断优先级NVIC设置
    5 S3 S/ n5 K- a$ \; R, h+ g
  2.     NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;          + ~- o: x- a6 n) X5 i
  3.         NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
    + D6 q  X9 w! ]7 r( \
  4.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;* J2 h' F0 m" [9 U/ T
  5.         NVIC_Init(&NVIC_InitStructure);
复制代码
, `  u# W2 }: |- `9 s- D3 d

/ M. W& P4 ^. D, S# _* s7 {(5)使能TIM39 b. ~& G3 u  C5 {4 Z, ~
         这一点最简单,库函数如下:
% L$ Z9 ]9 A! o  c+ n. Y* O; v
  1. TIM_Cmd(TIM3, ENABLE);        //使能TIM3   
复制代码
3 H8 V8 [* I2 {

5 @# {/ g4 B3 Q(6)编写中断服务函数
3 v8 [0 {( s/ t         最后一步,千万不要忘了写中断服务函数(当然,你可以用查询方式,不用中断)!我们这里是更新(溢出)中断,在中断服务函数开头,首先要判断是否溢出,然后执行相关操作(这里是翻转GPIO输出状态),最后清除中断标志。具体代码如下:
* a- h: v) V8 c  z- W" D3 ^
  1. void TIM3_IRQHandler(void)! O3 {$ C2 v( b$ j5 ]" ]; c
  2. {& G! r- J' `" A2 M; G
  3.         if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    % o4 l/ D% P: p* t/ Q6 {4 z- p
  4.         {       
    ) l$ K- W  x" f! m/ {
  5.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update);  
      E) Y* G1 ~- C& K0 z" T
  6.         LED2_Toggle();
    0 W; S6 c+ g5 L' x6 j  D
  7.         }                        
    1 i: a0 G( U) C, Q: s, h7 R
  8. }
复制代码

; c9 T- {& _+ {0 B& ~! Q. Z0 _通过以上几个步骤,我们就可以利用TIM3定时器中断功能实现对LED的状态翻转
: s9 Q4 p3 u5 K# Y
# ]2 G# m* l  l0 s$ T( g* _
* p/ C- J+ E% ?7 V9 n1 j) q
上传工程代码:
8 I1 H( {3 y6 r6 z1 D9 ` STM32F030_TIM3.rar (2.04 MB, 下载次数: 196)

评分

参与人数 1 ST金币 +10 收起 理由
zero99 + 10

查看全部评分

收藏 3 评论4 发布时间:2016-11-22 16:00

举报

4个回答
assssdz 回答时间:2016-11-22 23:41:18
zero99 回答时间:2016-11-28 14:14:41
下来看看
花落莫相离 回答时间:2019-7-25 16:24:00
大神,你这个定时器可以用吗?为什么我这STM32F030CCT6这样设置不行啊?我看还有人需要设置TIM_PrescalerConfig(TIM3, TM3_PrescalerValue, TIM_PSCReloadMode_Immediate);这句话,不知道怎么回事啊。
黑夜之狼 回答时间:2019-7-26 08:58:00
花落莫相离 发表于 2019-7-25 16:245 u4 f( H- o; f
大神,你这个定时器可以用吗?为什么我这STM32F030CCT6这样设置不行啊?我看还有人需要设置TIM_PrescalerCo ...
9 V+ D, n4 C+ w. I' G
可以用,可以参考库函数里面的例程

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版