打印

使用systick函数进行准确延时

[复制链接]
6928|29
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sunmeat|  楼主 | 2014-11-4 17:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在程序中,一般的延时,就是加个for循环,实现延时,但是这样的延时是不精确的,比如如下:
void Delay_Ms(__IO uint32_t nCount)
{

u32 i,j;
for(i=0;i<nCount;i++)
        for(j=0;j<12060;j++)
        ;
}
这样的延时,或许在某个频率下是准确的,频率一变,延时的误差就加大了,因此,我们可以用系统滴答定时器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时钟默认使用系统时钟。

使用特权

评论回复
5
sunmeat|  楼主 | 2014-11-4 19:18 | 只看该作者
其中这个函数定义在Core_cm3.h中 ,源代码如下所示:
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
   if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);                                                                                               
   SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;              /* 设置初值*/
   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);         /* 设置中断优先级*/
   SysTick->VAL   = 0;                                                 /* Load the SysTick Counter Value */
   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                    SysTick_CTRL_TICKINT_Msk   |
                    SysTick_CTRL_ENABLE_Msk;                           /* 使能Systick中断,和Systick 定时器*/
   return (0);                                               

}

使用特权

评论回复
6
sunmeat|  楼主 | 2014-11-4 19:19 | 只看该作者
从上面的函数中可以看出,这个函数把Systick的初值,中断优先级,使能中断,开启定时器都完成了。大大简化了程序。
其中ticks 代表的是初值。例如系统时钟是72Mhz 那么要产生1ms的时基,那么我们可以这样去写。
SysTick_Config(SystemCoreClock/1000);  当然也可以写成:SysTick_Config(72000);

使用特权

评论回复
7
sunmeat|  楼主 | 2014-11-4 19:21 | 只看该作者
下面介绍下详细的修改过程:
1.新建一个Delay.c和Delay.h文件,用来放延时函数。

使用特权

评论回复
8
sunmeat|  楼主 | 2014-11-4 19:23 | 只看该作者
1>定义一个全局的计时递减变量,在systick中断中递减,Delay.c中代码如下:
#include "Delay.h"

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

void Delay_Ms(__IO uint32_t nTime)
{
        TimingDelay = nTime;
        while(TimingDelay != 0); //减,直到为0
}

使用特权

评论回复
9
sunmeat|  楼主 | 2014-11-4 19:24 | 只看该作者
2>Delay.h中的代码如下:
#ifndef __DELAY_H_
#define __DELAY_H_

#include "stm32f10x_conf.h"

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

#endif

使用特权

评论回复
10
sunmeat|  楼主 | 2014-11-4 19:30 | 只看该作者
2.新建一个GD32_Config.c和GD32_Config.h

使用特权

评论回复
11
sunmeat|  楼主 | 2014-11-4 19:35 | 只看该作者
1>GD32_Config.c中存放的是GD32中外设的初始化函数,systick的初始化函数如下
#include "GD32_Config.h"

void SysTick_Init(void)
{
        if(SysTick_Config(72000000 / 1000)) //注意:3.5库中 SystemFrequency 被 SystemCoreClock 取代。
        while(1);
}

使用特权

评论回复
12
sunmeat|  楼主 | 2014-11-4 19:36 | 只看该作者
2>GD32_config.h中的代码如下:
#ifndef __GD32_INIT_H_
#define __GD32_INIT_H

#include "stm32f10x_conf.h"

void GPIO_Config(void);
void SysTick_Init(void);
#endif

使用特权

评论回复
13
sunmeat|  楼主 | 2014-11-4 19:38 | 只看该作者
3>stm32f10x_conf.h中必须加入core_cm3.h,因为SysTick_Config函数在这个文件中
 #include "core_cm3.h"//systick函数就在这里面

使用特权

评论回复
14
sunmeat|  楼主 | 2014-11-4 19:39 | 只看该作者
3.修改systick的中断函数,在stm32f10x_it.c中

使用特权

评论回复
15
sunmeat|  楼主 | 2014-11-4 19:54 | 只看该作者
1>SysTick中断服务函数代码如下:
void SysTick_Handler(void)
{
        if (TimingDelay != 0x00)
        {
        TimingDelay--;
        }
}

使用特权

评论回复
16
sunmeat|  楼主 | 2014-11-4 19:55 | 只看该作者
2>stm32f10x_it.h必须包含Delay.h,因为全局变量TimingDelay在Delay.c中定义

使用特权

评论回复
17
crwang| | 2014-11-5 09:45 | 只看该作者
建议延时最好不要用systick去实现

使用特权

评论回复
18
sunmeat|  楼主 | 2014-11-5 10:08 | 只看该作者
crwang 发表于 2014-11-5 09:45
建议延时最好不要用systick去实现

我还说以后就用这个延时呢,为什么不能用呢?

使用特权

评论回复
19
crwang| | 2014-11-5 10:21 | 只看该作者
般Systick是作为多任务的系统的时基(好像uCos就是用是Systick作为时基的)这样的话就不能用Systick来延迟了,任何比SysTick优先级高的中断不能调用SysTick_delay

使用特权

评论回复
20
crwang| | 2014-11-5 10:22 | 只看该作者
任何比SysTick优先级高的中断不能调用SysTick_delay,这种情况下systick延时就不能用

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

208

主题

2132

帖子

13

粉丝