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

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

[复制链接]
黑夜之狼 发布时间:2016-11-22 16:00
本帖最后由 黑夜之狼 于 2016-11-22 16:00 编辑
. [2 f  i  ~2 A" l9 y9 F  H5 a* Y0 w; U6 u% v
在前面的两个帖子当中,我们介绍了GPIO和UART通信,这次,我们来介绍单片机里面很普遍也很重要的一个外设——定时器。9 o, C, m1 k/ D# Y

) |* c' ]& p% ^0 `为什么说很普遍?现在的单片机最多的共同点就是:串口和定时器。串口未必每款单片机有,但是定时器基本上都有。
为什么说很重要?定时器的应用范围太广了,不说别的,单纯看STM32的参考手册,大家应该可以发现讲定时器的内容已经占了1/3(P220~467),可见其重要性!+ Q, n% f- u$ B: y3 M
  A+ A7 S) B! B, ?
STM32的定时器功能十分强大,F0系列的定时器分了高级定时器(TIM1)、通用定时器(TIM3/14/15/16/17)、基本定时器(TIM6/TIM7)三种。本次实验当中,我们将利用通用定时器TIM3中断来实现闪烁灯这个实验。# j  Q+ X0 D  O- S! g: i2 h/ Q/ h0 j
  p; N( `. U% ?, E; M
STM32F0的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。每个通用定时器都是完全独立的,没有互相共享的任何资源。
$ h- I/ q, K( D9 G4 P  E

# H& g; B8 k; q主要功能如下图:(参考手册P294)
) J/ l7 r/ c9 y 通用定时器TIM3主要功能.png
7 X5 }- B: u+ [( S  F: O8 G8 w
2 z# N9 g' E  b! L, W0 ], m定时器TIM3中断的配置可以总结为以下几点:
& s1 f# y2 y) Z4 p3 J(1)TIM3时钟使能
: |* k, p: ]9 R. U5 C! j3 o5 b         TIM3是挂载在APB1上的,所以我们通过APB1总线下的使能时钟函数来使能TIM3,调用的库函数是:9 `+ ~- a+ q! ?; K. j
  1. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);    //使能TIM3时钟
复制代码
% v- I8 e) e) ~, K- B$ Y

* h! o+ C# {1 q& w& A(2)初始化定时器参数,设置自动重装值,分频系数,计数方式等
' I3 T4 S9 S) ?         初始化定时器参数是由库函数 TIM_TimeBaseInit 来实现的:) Y. _/ K1 S( T% K& Y9 ?: `
  1. void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
复制代码
        第一个形参是选择用哪个定时器,第二个形参是定时器初始化参数的结构体指针,结构体类型为 TIM_TimeBaseInitTypeDef,我们可以打开 stm32f0xx_tim.h 这个文件看看这个结构体的定义:
  1. typedef struct' |) o( W* u* ~  s& [& r  H+ \+ l1 n
  2. {4 b" C5 u0 X* ^, q' d! t/ j
  3. uint16_t TIM_Prescaler;
    , U1 p; i5 f, M% R7 ^$ Z$ Q
  4. uint16_t TIM_CounterMode;
    & F( C9 x* q  k. O5 _
  5. uint16_t TIM_Period;/ a, L% M0 p  j8 Z! x  j# z1 K
  6. uint16_t TIM_ClockDivision;4 N" q1 k: @( R5 [5 Y4 x, \
  7. uint8_t TIM_RepetitionCounter;
    2 G% ]3 ?8 \; g( ]3 A
  8. } TIM_TimeBaseInitTypeDef;
复制代码
         从上面代码可见,这个结构体有5个成员变量,但是,对于通用定时器来说,只有前面4个成员才有用,最后一个成员Tim_TimeBaseInitTypeDef只对高级定时器才有用的,这里就不多解释了,等到用高级定时器的时候才来分析吧。+ Q% p" F- h1 ^# z7 E' q  d+ `" {

: H/ R3 H+ u# B0 l; @
针对TIM3初始化,具体配置代码如下:/ n+ |# X5 {5 L$ T2 b, l
  1. TIM_TimeBaseStructure.TIM_Period = arr;//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    8 Z* ^  D" e6 [5 ?( h7 M7 z8 z+ |
  2.         TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值
      \+ d. k8 ?  G. D' N8 x0 s
  3.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    " c' _" f0 `' p% `- s6 i
  4.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
    % y3 S! B" K/ p* w# j; N/ n
  5.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//根据指定的参数初始化TIMx的时间基数单位
复制代码
这里有arr和psc这两个形参,可以通过在main函数调用的时候作为输入形参使用。
0 F/ c4 K7 l5 {7 ^中断时间的计算公式如下:
; o% m, c* ^! d0 T) A      Tout = ( (arr + 1) * (psc + 1) ) / Tclk' P- y% y& I4 u; \8 k6 y
      Tclk:TIM3的输入时钟频率(单位:MHz)
4 d2 s6 k5 @  T* @# e* p1 r      Tout:TIM3溢出时间(单位:us)
+ ^# l- Y* H$ w/ z6 \0 P我们这里定时500ms,可以令arr = 4999,psc = 4799,Tclk = 48MHz
- Q6 d4 l. g* O, B# Q* ?/ c即:Tout = ( (4999 + 1) * (4799 + 1) ) / 48 = 500000us = 500ms

* }+ b5 b3 X  x3 `0 M0 h
  l( m( s! Z% z2 x  y3 K
0 i$ ?* X  p' r* ]: C4 a
(3)设置TIM3允许更新中断' H- I. Q; C# Z
         因为这里我们需要利用TIM3的中断来实现闪烁灯,所以要允许TIM3产生中断更新,库函数如下:
, o5 C+ x/ N: K7 z$ u
  1. TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);        //使能指定的TIM3中断,允许更新中断
复制代码

4 r  f- A5 \" D+ A1 g. j7 r(4)TIM3中断优先级设置
. A% D- I) ?0 ~* Z! j7 ?         既然使能了TIM3中断,那肯定要配置它的中断优先级了,具体代码如下:
8 X& ?1 v6 K# y3 n$ ^% d
  1. //中断优先级NVIC设置
    0 D/ F- k/ J# G
  2.     NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;          
    & C  E' f9 D6 U/ ]% K; ^
  3.         NVIC_InitStructure.NVIC_IRQChannelPriority = 3;0 U; K  S4 q# B: n( `( l/ x
  4.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    0 O) k6 r/ w0 S4 ^4 x
  5.         NVIC_Init(&NVIC_InitStructure);
复制代码

7 e- {# L' A8 I6 r1 h: ]" s. C
0 E+ Y& c: q2 ~& X(5)使能TIM3
0 d7 P$ n  E: r+ |* h- {% c) V         这一点最简单,库函数如下:

& {( L% a- h3 D; v3 n# S
  1. TIM_Cmd(TIM3, ENABLE);        //使能TIM3   
复制代码

1 u* y- k7 N- S8 e: [% f
' D4 d# h1 h5 y. }( ]. H3 f(6)编写中断服务函数
/ ]# r0 z) w" L/ I+ n         最后一步,千万不要忘了写中断服务函数(当然,你可以用查询方式,不用中断)!我们这里是更新(溢出)中断,在中断服务函数开头,首先要判断是否溢出,然后执行相关操作(这里是翻转GPIO输出状态),最后清除中断标志。具体代码如下:
, n, m  V( \0 f9 w
  1. void TIM3_IRQHandler(void)
    % |% I& G# w0 D- n. F
  2. {% S5 s, Q, |9 Q  Y8 D
  3.         if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    - k8 n9 T# g( L  @
  4.         {        . b! e, S% M$ K( R, Y
  5.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update);  - n9 x# N& j* q" f& O/ m$ }8 P
  6.         LED2_Toggle();( n9 E! t  f; f( e
  7.         }                         1 {: |: _0 F2 ?& r5 u/ X! {
  8. }
复制代码
0 c* B$ s2 F, S
通过以上几个步骤,我们就可以利用TIM3定时器中断功能实现对LED的状态翻转6 Q3 c, h' d. w+ K$ @; t% L/ @. V' b

8 u" ~% L. }+ r9 s9 X" B
9 A, J9 B+ E5 {: m
上传工程代码:
+ d- c6 L8 ]: g5 r) ]4 J7 N. l, ` STM32F030_TIM3.rar (2.04 MB, 下载次数: 198)

评分

参与人数 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:24
/ Z' Y" w( [; z大神,你这个定时器可以用吗?为什么我这STM32F030CCT6这样设置不行啊?我看还有人需要设置TIM_PrescalerCo ...

( {) S6 U" a7 R+ x" `# B' D( d' \可以用,可以参考库函数里面的例程

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版