STM32菜鸟成长记录---系统滴答定时器(systick)应用

标签: delay任务测试reference编译器工作
2012-08-19 22:55 47395人阅读 评论(4) 收藏 举报
本文章已收录于:
分类:
嵌入式(53)

作者同类文章X

ARM(27)

作者同类文章X

版权声明:本文为博主原创文章,未经博主允许不得转载。

1.systick介绍

Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。滴答中断?这里来简单地解释一下。操作系统进行运转的时候,也会有“心跳”。它会根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。

知道systick在系统中的地位后,我们来了解systick的实现。这里只是举例说明systick的使用。它有四个寄存器,笔者把它列出来:

SysTick->CTRL,        --控制和状态寄存器

SysTick->LOAD,        --重装载寄存器

SysTick->VAL,          --当前值寄存器

SysTick->CALIB,        --校准值寄存器

下图有他们的分别描述:     下图引用地址:http://blog.csdn.NET/marike1314/article/details/5673684

2.systick编程

现在我们想通过Systick定时器做一个精确的延迟函数,比如让LED精确延迟1秒钟闪亮一次。

思路:利用systick定时器为递减计数器,设定初值并使能它后,它会每个1系统时钟周期计数器减,计数到 0时,SysTick计数器自动重装初值并继续计数,同时触发中断。

那么每次计数器减到0,时间经过了:系统时钟周期 *计数器初值。我们使用72M作为系统时钟,那么每次计数器减1所用的时间是1/72M,计数器的初值如果是72000,那么每次计数器减到0,时间经过(1/72M)*72000= 0.001,即1ms。(简单理解:用72M的时钟频率,即1s计数72M=72000000次,那1ms计数72000次,所以计数值为72000) 

首先,我们需要有一个72M的systick系统时钟,那么,使用下面这个时钟OK就 !

SystemInit();

这个函数可以让主频运行到72M。可以把它作为systick的时钟源。

接着开始配置systick,实际上配置systick的严格过程如下:

1、调用SysTick_CounterCmd()       --失能SysTick计数器

2、调用SysTick_ITConfig()          --失能SysTick中断

3、调用SysTick_CLKSourceConfig()  --设置SysTick时钟源。

4、调用SysTick_SetReload()         --设置SysTick重装载值。

5、调用SysTick_ITConfig()          --使能SysTick中断

6、调用SysTick_CounterCmd()       --开启SysTick计数器

这里大家一定要注意,必须使得当前寄存器的值VAL等于0!

SysTick->VAL  = (0x00);只有当VAL值为0时,计数器自动重载RELOAD。

接下来就可以直接调用Delay();函数进行延迟了。延迟函数的实现中,要注意的是,全局变量TimingDelay必须使用volatile,否则可能会被编译器优化。

下面我们来做一下程序分析:

(1)系统时钟进配置

首先我们对系统时钟进行了配置并且SetSysClock(void)函数使用72M作为系统时钟;

为了方面看清代码我选择截图:

(2)先来看看主函数

[plain] view plaincopyprint?
  1. int main(void)
  2. {            unsigned char i=0;
  3. unsigned char a[] = "abncdee";
  4. SystemInit1();//系统初始化
  5. if (SysTick_Config(72000))  //1ms响应一次中断
  6. {
  7. /* Capture error */
  8. while (1);
  9. }
  10. /*解析:因为要求是每500ms往中位机发数据一件事,所以放在while语句中,
  11. *送据+延时可以完成相当于中断的效果;
  12. *若是多任务中,其中一个任务需要中断,这把这个任务放在中断函数中调用;
  13. */
  14. while (1)
  15. {
  16. //测试代码:测试定时器功能,通过延时来测试
  17. GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6
  18. Delay(50);
  19. GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6
  20. Delay(50);
  21. //功能1代码:每500ms发送数据
  22. /*
  23. UART2_TX485_Puts("123450");
  24. Delay(500);
  25. */
  26. //功能2代码:上位发特定指令,中位机执行相应操作
  27. //     RS485_Test();
  28. }
  29. }

int main(void){            unsigned char i=0;unsigned char a[] = "abncdee";SystemInit1();//系统初始化if (SysTick_Config(72000))  //1ms响应一次中断{ /* Capture error */while (1);} /*解析:因为要求是每500ms往中位机发数据一件事,所以放在while语句中,*送据+延时可以完成相当于中断的效果;*若是多任务中,其中一个任务需要中断,这把这个任务放在中断函数中调用;*/while (1){//测试代码:测试定时器功能,通过延时来测试GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6Delay(50);GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6Delay(50);//功能1代码:每500ms发送数据/*UART2_TX485_Puts("123450");Delay(500);*///功能2代码:上位发特定指令,中位机执行相应操作//     RS485_Test();}     }

(3)系统滴答定时器的配置--主角登场:

主函数中: SysTick_Config(72000) ;滴答定时器的参数是72000即计数72000

(因为我们使用72M的时钟频率,即1s计数72M=72000000次,那1ms计数72000次,所以计数值为72000) 

在文件Core_cm3.h中

SysTick_Config函数的具体实现如下:

[html] view plaincopyprint?
  1. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
  2. {
  3. if (ticks>SYSTICK_MAXCOUNT)
  4. return (1);      /* Reload value impossible */
  5. SysTick->LOAD = (ticks & SYSTICK_MAXCOUNT) - 1;//systick重装载值寄存器   /* set reload register */
  6. NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
  7. SysTick->VAL = (0x00);  //systick当前值寄存器
  8. /* Load the SysTick Counter Value */
  9. SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<<SYSTICK_ENABLE) | (1<<SYSTICK_TICKINT);//使能IRQ(普通中断)和系器         return(0);      /* Function successful */
  10. }

static __INLINE uint32_t SysTick_Config(uint32_t ticks){ if (ticks>SYSTICK_MAXCOUNT)  return (1);      /* Reload value impossible */SysTick->LOAD = (ticks & SYSTICK_MAXCOUNT) - 1;//systick重装载值寄存器   /* set reload register */NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */SysTick->VAL = (0x00);  //systick当前值寄存器                              /* Load the SysTick Counter Value */SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<<SYSTICK_ENABLE) | (1<<SYSTICK_TICKINT);//使能IRQ(普通中断)和系器         return(0);      /* Function successful */}                                       

我们来看一下这句代码:SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<<SYSTICK_ENABLE) | (1<<SYSTICK_TICKINT); 这是使能IRQ(普通中断)和系统定时器,为什么要使能中断和系统定时器呢?

下面我们来看一下stm32f10x_it.h文件中:

找到滴答定时器中断函数:SysTickHandler()

void SysTickHandler(void)

{

TimingDelay_Decrement();

}

从上文我们通过装载的计数值72000知道每1ms发生一次中断,在中断函数中调用一个函数TimingDelay_Decrement();-----即每1ms发生中断时就调用到此函数;

下面我们来看看TimingDelay_Decrement();在干些什么?

[html] view plaincopyprint?
  1. /*****************************************************************
  2. *函数名称:TimingDelay_Decrement
  3. *功能描述:中断里调用此函数,即没发生一次中断,此函数被调用,此函数里
  4. *          的变量TimingDelay 相当于减法计数器
  5. *
  6. *输入参数:无
  7. *返回值:无
  8. *其他说明:无
  9. *当前版本:v1.0
  10. *作    者: 梁尹宣
  11. *完成日期:2012年8月3日
  12. *修改日期      版本号      修改人      修改内容
  13. *-----------------------------------------------------------------
  14. *
  15. ******************************************************************/
  16. void TimingDelay_Decrement(void)
  17. {
  18. if (TimingDelay != 0x00)
  19. {
  20. TimingDelay--;
  21. }
  22. }
  23. 我们看了TimingDelay的定义,又看了还有哪些函数调用到这个变量,如下:
  24. /*****************************************************************
  25. *                                        全局变量
  26. ******************************************************************/
  27. static __IO uint32_t TimingDelay=0;
  28. /*****************************************************************
  29. *函数名称:    Delay
  30. *功能描述:    利用系统时钟计数器递减达到延时功能
  31. *
  32. *输入参数:nTime :需要延的时毫秒数
  33. *返回值:无
  34. *其他说明:无
  35. *当前版本:v1.0
  36. *作    者: 梁尹宣
  37. *完成日期:2012年8月3日
  38. *修改日期      版本号      修改人      修改内容
  39. *-----------------------------------------------------------------
  40. *
  41. ******************************************************************/
  42. void Delay(__IO uint32_t nTime)//delay被调用时,nTime=500
  43. {
  44. TimingDelay = nTime;
  45. while(TimingDelay != 0);
  46. }

/******************************************************************函数名称:TimingDelay_Decrement*功能描述:中断里调用此函数,即没发生一次中断,此函数被调用,此函数里     *          的变量TimingDelay 相当于减法计数器* *输入参数:无*返回值:无*其他说明:无*当前版本:v1.0*作    者: 梁尹宣*完成日期:2012年8月3日*修改日期      版本号      修改人      修改内容*-----------------------------------------------------------------*******************************************************************/void TimingDelay_Decrement(void)  {  if (TimingDelay != 0x00)  {   TimingDelay--;  }}  我们看了TimingDelay的定义,又看了还有哪些函数调用到这个变量,如下:/******************************************************************                                        全局变量******************************************************************/static __IO uint32_t TimingDelay=0;/******************************************************************函数名称:    Delay*功能描述:    利用系统时钟计数器递减达到延时功能* *输入参数:nTime :需要延的时毫秒数*返回值:无*其他说明:无*当前版本:v1.0*作    者: 梁尹宣*完成日期:2012年8月3日*修改日期      版本号      修改人      修改内容*-----------------------------------------------------------------*******************************************************************/void Delay(__IO uint32_t nTime)//delay被调用时,nTime=500{ TimingDelay = nTime;while(TimingDelay != 0);}

通过上面几个函数我们知道了,在调用Delay(500)即nTime=500;在后在Delay()函数中TimingDelay =nTime;(即TimingDelay=500是它的初始值),再TimingDelay_Decrement(void)函数的作用就是把TimingDelay- -;每毫秒进行递减直到减到0为止;这样就起到一个延时的作用;

现在我们做出来的Delay(1),就是1毫秒延迟。Delay(1000)就是1秒。

我们来画个图,方便这几个函数间关系的理解:

我们在返回到主函数main()中看这几条语句:红色标注de

[html] view plaincopyprint?
  1. while (1)
  2. {
  3. //测试代码:测试定时器功能,通过延时来测试
  4. GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6
  5. Delay(500);
  6. GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6
  7. Delay(500);
  8. //功能1代码:每500ms发送数据
  9. /*
  10. UART2_TX485_Puts("123450");
  11. Delay(500);
  12. */
  13. //功能2代码:上位发特定指令,中位机执行相应操作
  14. //     RS485_Test();
  15. }

while (1){//测试代码:测试定时器功能,通过延时来测试GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6 Delay(500);GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6 Delay(500);//功能1代码:每500ms发送数据/*UART2_TX485_Puts("123450");Delay(500);*///功能2代码:上位发特定指令,中位机执行相应操作//     RS485_Test();}

经过上面系统定时器的分析我们知道Delay(500);是延时500ms ;那么LED就是每隔500ms闪烁一次;

上面有关系统滴答定时器的应用讲解基本完毕!

有关SysTick编译后的源代码包,(其实客官细心的话一经发现上面代码含有485通讯代码,

只不过被暂时屏蔽掉了,下一节将讲到)我放在我的资源里:http://download.csdn.net/detail/yx_l128125/4511622

下面我们来看看一下参考资料的问题,一边对上面我写的博客有更深入的理解:

《Cortex-M3权威指南》

《Cortex-M3 Technical Reference Manual》

Q:什么是SYSTick定时器?

SysTick 是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。

Q:为什么要设置SysTick定时器?

(1)产生操作系统的时钟节拍

SysTick定时器被捆绑在NVIC用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

(2)便于不同处理器之间程序移植。

Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。

不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间对其处理都是相同的

(3)作为一个闹铃测量时间。

SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。

Q:Systick如何运行?

首先设置计数器时钟源,CTRL->CLKSOURCE(控制寄存器)。设置重载值(RELOAD寄存器),清空计数寄存器VAL(就是下图的CURRENT)。置CTRL->ENABLE位开始计时。

如果是中断则允许Systick中断,在中断例程中处理。如采用查询模式则不断读取控制寄存器的COUNTFLAG标志位,判断是否计时至零。或者采取下列一种方法

当SysTick定时器从1计到0时,它将把COUNTFLAG位置位;而下述方法可以清零之:

1. 读取SysTick控制及状态寄存器(STCSR)

2. 往SysTick当前值寄存器(STCVR)中写任何数据

只有当VAL值为0时,计数器自动重载RELOAD。

Q:如何使用SysTicks作为系统时钟?

SysTick 的最大使命,就是定期地产生异常请求,作为系统的时基。OS都需要这种“滴答”来推动任务和时间的管理。如欲使能SysTick异常,则把STCSR.TICKINT置位。另外,如果向量表被重定位到SRAM中,还需要为SysTick异常建立向量,提供其服务例程的入口地址。

stm32系统滴答定时器使用相关推荐

  1. STM32——系统滴答定时器

    STM32--系统滴答定时器 宗旨:技术的学习是有限的,分享的精神是无限的. 一.SysTick[内核中] [风格:先描述一下库对寄存器的封装,再举例实现某些功能] SysTick定时器被捆绑在NVI ...

  2. STM32系统滴答定时器(systick)应用

    一:系统滴答定时器(systick) 1.systick介绍 Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断).滴答中断?这里来 ...

  3. stm32系统滴答定时器

    SysTick定时器(系统滴答定时器)是一个倒计时定时器,被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15).在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系 ...

  4. stm32滴答计时器_STM32——系统滴答定时器

    STM32--系统滴答定时器 一.SysTick[内核中] [风格:先描述一下库对寄存器的封装,再举例实现某些功能] SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号: 15 ...

  5. stm32滴答计时器_stm32中的系统滴答定时器使用

    系统滴答定时器对于stm32的初学者来说还是非常重要的,因为随着你学习的深入编程过程中肯定会调用延时函数,比如我之前的一些gpio相关的实验中.那么延时函数的编写也是几种方法的,一般开始接触都是让系统 ...

  6. 【STM32】HAL库-系统滴答定时器SysTick

    SysTick定时器被捆绑在NVIC中,是一个简单的定时器,对于CM3.CM4内核芯片,都有Systick定时器.Systick定时器常用来做延时,或者实时系统的心跳时钟.这样可以节省MCU资源,不用 ...

  7. 【STM32】STM32之系统滴答定时器

    本篇博文最后修改时间:2016年12月29日,01:06. 一.简介 本文介绍如何使用STM32的系统滴答定时器,以延时1S.10S为例. 二.实验平台 库版本:STM32F10x_StdPeriph ...

  8. stm32滴答计时器_STM32之系统滴答定时器

    一.SysTick(系统滴答定时器)概述 操作系统需要一个滴答定时器周期性产生中断,以产生系统运行的节拍.在中断服务程序里,基于优先级调度的操作系统会根据进程优先级切换任务,基于时间片轮转系统会根据时 ...

  9. stm32滴答计时器_STM32 的系统滴答定时器( Systick) 彻底研究解读

    作者:王健 前言 SysTick 比起那些 TIM 定时器可以说简单多啦~~~~~哥的心情也好了不少, 嘎嘎!! ARM Cortex-M3 内核的处理器内部包含了一个 SysTick 定时器,它是一 ...

最新文章

  1. 2022-2028年中国增光膜行业市场研究及未来发展潜力报告
  2. win7 安装PyTorch
  3. python类对象赋值_Python对象赋值、浅拷贝、深拷贝
  4. 一段树状无限制级代码
  5. [渝粤教育] 西南科技大学 电子产品制造工艺 在线考试复习资料
  6. 手把手教你|拦截系统调用
  7. 还是畅通工程1233
  8. 云际阔,总相连——Let's Connect!
  9. 河南省某炮旅的RAID5恢复
  10. Redis 6.0 新特性概览
  11. C#教程第四课:循环控制语句
  12. 理解数据库中的undo日志、redo日志、检查点
  13. 等级保护三级基本要求
  14. [JSMind]使用JSMind操作生成的思维导图
  15. spring使用freemarker生成word文档包含表格、图片(循环插入)
  16. Log4j for C++ 实用指南
  17. saiku 升级备份恢复
  18. 基于OpenCv的视频流处理方法
  19. 【vue】avue-crud配置大全-持续更新
  20. vue3项目源码汇集

热门文章

  1. 【转】简述TCP的三次握手过程
  2. UNITY中使用不安全代码的相关设置
  3. linux下安装navicat并生成桌面图标
  4. Color Tint
  5. JavaSE之ClassLoader
  6. 微电子所在阻变存储器研究领域取得新进展
  7. 使用powershell一次性创建用户,OU及组
  8. Linux 下Oracle Client JAVA JDBC 集成点滴
  9. hdu 3033(分组背包)
  10. poj 1451(Trie)