使用systick函数进行准确延时

[复制链接]
 楼主| sunmeat 发表于 2014-11-4 17:29 | 显示全部楼层 |阅读模式
在程序中,一般的延时,就是加个for循环,实现延时,但是这样的延时是不精确的,比如如下:
  1. void Delay_Ms(__IO uint32_t nCount)
  2. {

  3. u32 i,j;
  4. for(i=0;i<nCount;i++)
  5.         for(j=0;j<12060;j++)
  6.         ;
  7. }
这样的延时,或许在某个频率下是准确的,频率一变,延时的误差就加大了,因此,我们可以用系统滴答定时器systick来实现延时。
 楼主| sunmeat 发表于 2014-11-4 19:04 | 显示全部楼层
STM32内核中有一个系统定时器,它是一个24位递减计数器。工作原理是系统时基定时器设定初值并使能后,每经过1个系统时钟周期,计数值就减,当计数值减到0时,系统定时器会重新自动重装初值,并继续下一次计数,同时内部的COUNTFLAG标志位会置位。触发中断。
 楼主| sunmeat 发表于 2014-11-4 19:05 | 显示全部楼层
在很早的固件库中,提供了很多函数,来对SysTick进行设置,但是到了3.5版本的标准固件库中,移除了相关驱动函数,用户必须调用CMSIS 定义的函数,其中CMSIS只提供了一个Systick设置的函数,替代了STM32原来有的所有的驱动函数,这样做的目的,可能是简化Systick 的设置,可是降低了用户对SysTick的可控性。
 楼主| sunmeat 发表于 2014-11-4 19:17 | 显示全部楼层
在CMSIS中提供的函数是  SysTick_Config(uint32_t ticks); 该函数设置了自动重载入计数器(LOAD)的值,SysTick IRQ的优先级,复位了计数器(VAL)的值,开始计数并打开SysTick IRQ中断。SysTick时钟默认使用系统时钟。
 楼主| sunmeat 发表于 2014-11-4 19:18 | 显示全部楼层
其中这个函数定义在Core_cm3.h中 ,源代码如下所示:
  1. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
  2. {
  3.    if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);                                                                                               
  4.    SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;              /* 设置初值*/
  5.    NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);         /* 设置中断优先级*/
  6.    SysTick->VAL   = 0;                                                 /* Load the SysTick Counter Value */
  7.    SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
  8.                     SysTick_CTRL_TICKINT_Msk   |
  9.                     SysTick_CTRL_ENABLE_Msk;                           /* 使能Systick中断,和Systick 定时器*/
  10.    return (0);                                               

  11. }
 楼主| sunmeat 发表于 2014-11-4 19:19 | 显示全部楼层
从上面的函数中可以看出,这个函数把Systick的初值,中断优先级,使能中断,开启定时器都完成了。大大简化了程序。
其中ticks 代表的是初值。例如系统时钟是72Mhz 那么要产生1ms的时基,那么我们可以这样去写。
  1. SysTick_Config(SystemCoreClock/1000);  当然也可以写成:SysTick_Config(72000);
 楼主| sunmeat 发表于 2014-11-4 19:21 | 显示全部楼层
下面介绍下详细的修改过程:
1.新建一个Delay.c和Delay.h文件,用来放延时函数。
 楼主| sunmeat 发表于 2014-11-4 19:23 | 显示全部楼层
1>定义一个全局的计时递减变量,在systick中断中递减,Delay.c中代码如下:
  1. #include "Delay.h"

  2. __IO uint32_t TimingDelay;//定义一个全局变量,作为延时的参数

  3. void Delay_Ms(__IO uint32_t nTime)
  4. {
  5.         TimingDelay = nTime;
  6.         while(TimingDelay != 0); //减,直到为0
  7. }
 楼主| sunmeat 发表于 2014-11-4 19:24 | 显示全部楼层
2>Delay.h中的代码如下:
  1. #ifndef __DELAY_H_
  2. #define __DELAY_H_

  3. #include "stm32f10x_conf.h"

  4. extern  __IO uint32_t TimingDelay;//定义一个可以引用的外部全局变量,__IO是防止被优化,这个值是设定的延时时间
  5. extern void Delay_Ms(__IO uint32_t nTime);

  6. #endif
 楼主| sunmeat 发表于 2014-11-4 19:30 | 显示全部楼层
2.新建一个GD32_Config.c和GD32_Config.h
 楼主| sunmeat 发表于 2014-11-4 19:35 | 显示全部楼层
1>GD32_Config.c中存放的是GD32中外设的初始化函数,systick的初始化函数如下
  1. #include "GD32_Config.h"

  2. void SysTick_Init(void)
  3. {
  4.         if(SysTick_Config(72000000 / 1000)) //注意:3.5库中 SystemFrequency 被 SystemCoreClock 取代。
  5.         while(1);
  6. }
 楼主| sunmeat 发表于 2014-11-4 19:36 | 显示全部楼层
2>GD32_config.h中的代码如下:
  1. #ifndef __GD32_INIT_H_
  2. #define __GD32_INIT_H

  3. #include "stm32f10x_conf.h"

  4. void GPIO_Config(void);
  5. void SysTick_Init(void);
  6. #endif
 楼主| sunmeat 发表于 2014-11-4 19:38 | 显示全部楼层
3>stm32f10x_conf.h中必须加入core_cm3.h,因为SysTick_Config函数在这个文件中
  1. #include "core_cm3.h"//systick函数就在这里面
 楼主| sunmeat 发表于 2014-11-4 19:39 | 显示全部楼层
3.修改systick的中断函数,在stm32f10x_it.c中
 楼主| sunmeat 发表于 2014-11-4 19:54 | 显示全部楼层
1>SysTick中断服务函数代码如下:
  1. void SysTick_Handler(void)
  2. {
  3.         if (TimingDelay != 0x00)
  4.         {
  5.         TimingDelay--;
  6.         }
  7. }
 楼主| sunmeat 发表于 2014-11-4 19:55 | 显示全部楼层
2>stm32f10x_it.h必须包含Delay.h,因为全局变量TimingDelay在Delay.c中定义
crwang 发表于 2014-11-5 09:45 | 显示全部楼层
建议延时最好不要用systick去实现
 楼主| sunmeat 发表于 2014-11-5 10:08 | 显示全部楼层
crwang 发表于 2014-11-5 09:45
建议延时最好不要用systick去实现

我还说以后就用这个延时呢,为什么不能用呢?
crwang 发表于 2014-11-5 10:21 | 显示全部楼层
般Systick是作为多任务的系统的时基(好像uCos就是用是Systick作为时基的)这样的话就不能用Systick来延迟了,任何比SysTick优先级高的中断不能调用SysTick_delay
crwang 发表于 2014-11-5 10:22 | 显示全部楼层
任何比SysTick优先级高的中断不能调用SysTick_delay,这种情况下systick延时就不能用
您需要登录后才可以回帖 登录 | 注册

本版积分规则

208

主题

2132

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部