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

【零基础学习STM32】第五讲:SYSTICK定时器实验——定时点...

[复制链接]
kkhkbb 发布时间:2018-3-6 14:53
本帖最后由 kkhkbb 于 2018-3-19 09:11 编辑 * E9 R- e+ ~8 Y) w3 }$ C- s: n8 W$ Q

) g# I- z1 F% z+ t9 D
一、 概述
1、 时钟系统简介
(1)STM32时钟源分以下五类:
  • 高速内部时钟(HSI):RC振荡器,精度不高。
  • 高速外部时钟(HSE):可接石英/陶瓷谐振器或者接外部时钟源。
  • 低速内部时钟(LSI):RC振荡器,提供低功耗时钟。应用如WDG。
  • 低速外部时钟(LSE):接外部低频率石英晶体。应用如RTC。
  • 常闭不带复位:锁相环倍环输出(PLL):其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频倍数可调,但是其最大输出频率受限数值因芯片型号而异。' U( \7 s2 P0 j1 b9 T0 D
(2)系统时钟SYSCLK可来源于:HSI振荡器时钟、HSE振荡器时钟、PLL时钟。
2、SYTICK简介
     在STM32中,SysTick是内核CM4中的一个24位的递减计数器,也称系统嘀答定时器。SysTick的最大使命,就是定期地产生异常请求,作为系统的时基。操作系统需要这种“滴答”来推动任务和时间的管理。
     SysTick在设定初值并开启后,每经一个系统时钟周期,计数值减1,计数到0时,将从重载寄存器中自动重新装载定时初值并继续计数,同时内部的COUNTFLAG标志位置1,触发中断(中断允许情况下),中断响应属于NVIC异常,异常号为15,Systick中断优先级可设置。
3、SYTICK寄存器控制
     STM32内部有4个寄存器控制SysTick定时器。分别为:控制寄存器STK_CSR、重载寄存器STK_LOAD、当前值寄存器STK_VAL和校准值寄存器STK_CALRB。下面分别对这4个寄存器做详细介绍。
(1)控制寄存器STK_CSR(地址:0xE000E010)
       控制寄存器STK_CSR中有4个bit具有意义,其内容如图4_0、表4_0所示:
    784b0304d5f54e0978959d5fda1c0d8.png                         " b! N. _$ R. n$ c% b* j! h! W
           图4_0 控制寄存器STK_CSR的格式
ENABLE(位0) Systick使能位。
0:关闭Systick功能;
1:开启Systick功能。
TICKINT(位1) Systick中断使能位。
0:关闭Systick中断;
1:开启Systick中断,systick倒数到零时产生systick异常中断。
CLKSOURCE(位2) Systick时钟源选择位。
0:使用HCLK/8作为Systick时钟(外部时钟);
1:使用HCLK作为Systick时钟(内核时钟)。
COUNTFLAG(位16) Systick计数比较标志,如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1。如果读取该位,该位将自动清零。
           表4_0  控制寄存器STK_CSR的格式0 c, f# U4 n) r; i) r
(2)重载寄存器STK_LOAD(地址:0xE000E014)
微信图片_20180306142932.png
             图4_1 重载寄存器STK_LOAD的格式
     重载寄存器STK_LOAD为24位的寄存器(0:23有效),最大计数0xFFFFFF。SysTick定时器递减至0时,重载寄存器中的值就会被重新装载,继续开始递减计数。
(3)当前值寄存器STK_VAL(地址:0xE000E018)
微信图片_20180306143229.png
            图4_2 当前值寄存器STK_VAL的格式
     当前值寄存器STK_VAL为24位的寄存器,读取时返回当前计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG标志。
(4)校准值寄存器STK_CALRB(地址:0xE000E01C)
微信图片_20180306143432.png
         图4_3 校准值值寄存器STK_CALRB的格式
NOREF 0:HCLK可用;( [+ E5 a' n, N" F3 v+ W
1:HCLK不可用。
SKEW 0:校准值是准确的10ms;
# M) l2 P: O- \4 X1:校准值不是准确的10ms。
TENMS 该值是10ms定时的重装值。其值取决于SKEW,它可以是精确的10ms,也可以是接近10ms的值。如果该值为0,则表示无法使用校准功能,这很可能是因为时钟是系统的一个未知输入或者时钟可以动态调节。
           表4_1寄存器STK_CALRB的格式
二、实验原理) w+ q* ]" G4 w  l# k+ a. u
     通过STM32的三个GPIO口驱动三色LED的三个通道;设定GPIO为推挽输出;采用灌电流的方式与LED连接,输出高电平LED灭,输出低电平LED亮。通过系统定时器实现1s定时,每秒变换一次LED颜色。
5 M, z- i6 B; H 微信图片_20180306143629.png $ V, s" i2 i. D2 |
             图4_4 驱动示意图
三、源代码
1.主函数
  1. /*
    * t+ }" f0 e+ \1 H8 P5 [9 [$ d2 B
  2. * Name                : main
    / `  v# f* M, r( L, O$ ?& c, N# b
  3. * Description         : ---
    4 \' {( @5 X* b0 T8 u( B6 w# D; r
  4. * Author              : ysloveivy.
    * ~  Z  |5 d5 }
  5. *# e! ?  D5 l/ i0 e+ Y0 c& ]( E
  6. * History
    ; |; e; M. W* L8 o1 n% ?
  7. * --------------------( L) g. h' D6 M5 C: Z4 G
  8. * Rev                 : 0.000 B9 |- U& M9 x- N
  9. * Date                : 11/21/2015# a9 [) o* z: v' f: M& ^
  10. * 5 P1 N+ J( o9 f
  11. * create.
    + i6 ]0 l2 Q( Y( N
  12. * --------------------
    4 {. K# ?+ H: f
  13. */+ q8 c6 d1 U; o: m# h  y, I: Z2 @
  14. int main(void)
    0 R- M' O1 t- D' S; q: x/ }% ~- E
  15. {/ s8 S" E3 K, g5 \7 Q- l
  16.         static int work_status = 0;; o$ w6 O* g5 U0 U9 K( R/ w0 c
  17.         led.initialize();( K( X6 }6 h" ?- Y
  18.         systick.initialize();3 j2 l: {" n& N9 O$ R' A
  19.         //每隔一秒三色灯进行交替循环闪烁
    : f6 l! C6 M, r
  20.         while(1){
    6 u9 K  Y7 c# ^. b7 G
  21. if(systick.second_flag == 1){ //每隔一秒标志位置1,执行一次  N4 ~6 ]* j3 ?8 l7 J, z# B
  22.                         systick.second_flag = 0;  J/ _( q8 Q+ f- g1 ?6 u' z
  23.                         work_status += 1;
    3 W9 z8 j# i- F" W- }4 k
  24.                         if(work_status > 2)work_status = 0; ( r* O& A2 H! K7 H2 ~4 S
  25.                 }' o1 X6 l& }" r$ U0 V1 H$ R: }; y
  26.                 switch (work_status){
    1 y# s* Y" a/ O; l
  27.                         case 0 :
    1 B9 s9 R' A' o6 I% K& O1 _
  28.                                 LED_RED_ON;( f' s: j' k$ k; x7 @: V. M
  29.                                 LED_GREEN_OFF;1 ?/ L8 P2 o5 A6 @2 B" \: w
  30.                                 LED_BLUE_OFF;
    8 }! c4 j& J. r7 ~
  31.                                 break;* d9 ]/ y' E1 i3 }* E

  32. % _) ]; l. j/ ^
  33.                         case 1 :  I6 Y7 Q2 E- x/ V9 b, f
  34.                                 LED_RED_OFF;; G0 ]3 z' h5 q: [$ S, C
  35.                                 LED_GREEN_ON;
    # ~( b3 L4 a. S. @
  36.                                 LED_BLUE_OFF;) K! U5 o  K% @( f: {5 K
  37.                                 break;" K9 u6 i3 `: f& r

  38. 5 b, O- W3 w) e3 `: W% o7 R
  39.                         case 2:
    ' G4 I& Z* I* A: N, W! u
  40.                                 LED_RED_OFF;% u; x) l6 u/ L  W2 p: C. l* W
  41.                                 LED_GREEN_OFF;
    " Z6 |& r, x8 Q: t( A
  42.                                 LED_BLUE_ON;
    7 D7 m* O" z. G# o" @
  43.                                 break;
    ) [/ u5 {0 T) M- l8 Y1 ^% r, R6 _: l
  44. ! B& y# P5 _2 c3 k/ _  o
  45.                         default:
复制代码
2.Systick初始化
   以下是Systick初始化及中断设置函数,主要实现定标志位的时1s,改变一次标志位,使用LED显色状态变换一次。
  1. /*
    4 k( P' b( F% [& j. Z, ~6 D
  2. * Name               : initialize. t, M$ R9 @" G: _1 l" x
  3. * Description        : ---
    6 ~" B. [" X0 y0 ?, }
  4. * Author             : ysloveivy.: _, M$ k/ y) M& O
  5. *& D4 J) L: l" O9 Q1 o  G
  6. * History
    * J5 T) ?' O# N# `0 g# v
  7. * -------------------! T; c4 V0 D' M- t: l! `4 f
  8. * Rev                : 0.00
    : D/ [5 X8 L( {" m' {+ d1 r
  9. * Date               : 11/21/2015
    8 {  s6 V' {+ Y
  10. * $ v9 K: d" B7 ~: D2 Z
  11. * create.
    3 i7 Z0 f5 b% ~5 @+ `( K
  12. * -------------------5 V& a+ B! g5 t# F) A
  13. */
    5 L5 t9 h/ m( {" a  X
  14. static int initialize(void). a2 R; U1 T/ _1 e+ [& f, z3 P! |
  15. {
    7 U: ?, C" Y  N8 c" h' n
  16.         //定时1ms
    0 N4 e( D* d, H# B  y
  17.         if(SysTick_Config(SystemCoreClock / 1000)){
    8 I/ Z& Z" q; n8 z
  18.                 while(1);' p+ c7 E$ a+ d
  19.         }
    * h+ k/ z- m  q6 c( M9 a8 W
  20.         return 0;% G! [3 H4 Y  n
  21. }
    ( u- @" P' K1 K8 a/ h0 _$ \/ ~( E
  22. /*
    2 H) W7 y5 w$ H! u" R9 \: x: M
  23. * Name               : SysTick_Handler
    % j6 ~- p& V! Y6 J0 I
  24. * Description        : ---8 O7 b- y. d6 U& a. W
  25. * Author             : ysloveivy.- a3 g- J! i* P. p  X" V3 p3 V4 O" s
  26. * History
    9 _# J9 p$ l- o+ ^( u$ ?0 g
  27. * -------------------2 ?+ H1 o! I/ R; q( t; b4 \2 P. s
  28. * Rev                : 0.00: Z) t$ e' z6 \( I9 o, P
  29. * Date               : 11/21/2015" ~) |  G: r) z$ b1 O
  30. * . O9 E4 X( c/ W- ~+ D2 J) T9 _
  31. * create.2 k/ B8 ]! ?# D9 E6 e/ i9 w
  32. * -------------------
    $ l% l4 l# e( Y* T6 S/ ]7 N
  33. */
    - n) A0 o/ R+ o$ u* T
  34. void SysTick_Handler(void)
    * y! i, S; F1 c% A4 U+ d
  35. {1 n* l7 R+ v, G& m+ M. @
  36.         static int counter = 0;. s/ ^1 a& ?& m# V% {
  37. 1 w- }2 p+ f9 Q# F4 o* l$ ]5 F
  38.         if((counter ++ % 1000) == 0){ //每次中断counter自加1,判断是否整秒
    & N; |& X# `" a! X3 q7 S; n
  39.                 systick.second_flag = 1;
      W7 _' d; Z. ^1 ^$ H8 d
  40.         }
    , C( K: {% K, L6 l
  41. }
复制代码
3.小知识
   在上面有两个重要的函数
   1.SysTick_Confing(uint32_t ticks)
    该函数的作用是初始化systick,时钟为HCLK(CM3一般为72M,CM4一般为168M),并开启中断。
  1. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)% m+ A6 t; m& ?/ \3 v
  2. {" }" y/ @; I0 W" k
  3.   if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)  //大于重载寄存器最大值0xFFFFFF
    ) r3 U$ x/ A/ t: E
  4.   {
    $ B! B; L! q  l6 v! j: N/ A! F
  5. return (1UL);                                //重新加载值不可能,返回错误           
    + K% [. W, s) p& @7 }. o1 S: G
  6. }
    # [! N! h* J# e1 X$ _
  7.   SysTick->LOAD  = (uint32_t)(ticks - 1UL);      //计数范围0到ticks-1                  
    % o7 f! {: j, z! ]/ n
  8. NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
    , e- N/ c% I; W+ H6 q1 R! W$ B
  9. //设置优先级
    ' i! K+ U+ Q8 x7 K3 W, _
  10. SysTick->VAL   = 0UL;                              //当前值初始化为0   
    $ E* @/ `; i- r9 b
  11.   //接下来设置控制寄存器,以位与的方式实现三个控制位的设置。; a6 S/ H) d* h$ A: e( T
  12.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | //选择时钟源3 u% [# O4 b; S6 F
  13.                       SysTick_CTRL_TICKINT_Msk   |  //开启中断
    1 Z! G" S. P' e$ c
  14.                       SysTick_CTRL_ENABLE_Msk;      //使能定时器               9 \. s! g& ^  ~# g
  15.   return (0UL);                                       //初始化成功返回         
    2 m) h7 R9 {1 d4 ~) e0 g
  16. }
复制代码
     回头看看程序中的SysTick_Config(SystemCoreClock / 1000)语句,该函数中的SystemCoreClock为时钟频率已在库函数中宏定义。如在iCore3双核心板ARM的HCLK为168M(每秒168M次计数),则程序中SystemCoreClock / 1000即意味每1ms中断一次。
    2.void SysTick_Handler(void)
    该函数是中断函数,即每次SysTick中断产生时运行一次函数,其在启动文件中已有设置,在驱动文件中使用时无需再次声明。/ k+ F0 s% V- ~# j- V5 l5 C
四、 实验现象
     iCore3的双核心板上与ARM相连的三色LED(PCB上标示为ARM·LED),红色、绿色、蓝色每秒交替点亮。
五、 代码包下载链接

* g. p! \# ~& J, @
赞 收藏 评论3 发布时间:2018-3-6 14:53

举报

3个回答
zero99 回答时间:2018-3-7 09:18:31
大佬,这第一讲和第二讲怎么没找到啊  。。
kkhkbb 回答时间:2018-3-7 15:26:29
zero99 发表于 2018-3-7 09:18& u+ d9 A) O3 _' w
大佬,这第一讲和第二讲怎么没找到啊  。。

, d! a" P0 \/ A# x3 t你直接搜索【零基础学习STM32】可以找到我们所有的帖子。。
zero99 回答时间:2018-3-8 10:37:48
kkhkbb 发表于 2018-3-7 15:265 d, t  c9 e% Y7 I! R
你直接搜索【零基础学习STM32】可以找到我们所有的帖子。。

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