STM32F407ZGT6用滴答定时器实现精确延时(寄存器版)

时间:2021-10-20 00:23:55

1.滴答定时器介绍

SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

滴答定时器是ARM公司设计架构是已经集成到内核中,也就是说只要采用ARM公司设计芯片滴答定时器是通用的,写好的滴答定时器在其他的采用ARM公司设计的芯片直接可以拿来使用。

滴答定时器的时钟频率是21MHZ,采用的是递减计数的计数方式,一次定时的最长时间=1/21000000   *(2^24-1) = 799ms

2.编写滴答定时器驱动程序的思路:

①选择时钟源
选择外部的时钟源 21MHZ
通过SysTick控制及状态寄存器 第2位控制
②写入自动重装载值
写入到自动重装载寄存器中(计数器的初值) 
③清空当前数值寄存器
直接对该寄存器写入0
④使能定时器
通过控制和状态寄存器的第0位实现  写1使能
⑤等待计数时间到达
隐含条件 当前数值寄存器里的值从 1--->0 这一瞬间
控制及状态寄存器的第16位就会立即变为1 读取该寄存器的
16 位清空当前的标志位
while((SysTick->CTRL & (1<<16))==0);
⑥关闭定时器

通过控制和状态寄存器的第0位实现 写0关闭

3.驱动程序头文件

#ifndef  _DELAY_H

#define  _DELAY_H

#include "stm32f4xx.h"

//宏定义

//函数声明
void delay_ms(u16 ms);
void delay_us(u32 us);

void delay_xms(u32 xms);

#endif


4.驱动程序源文件

#include "delay.h"

/********************
函数名:    delay_ms
函数参数:  u16 ms :需要延时时间 以ms为单位
函数返回值:无
函数功能:  实现滴答定时器的ms级别的延时
函数描述:
*********************/

void delay_ms(u16 ms)
{
//选择时钟(外部的时钟)
SysTick->CTRL &=~(0x1<<2);
//写入自动重装载值
SysTick->LOAD = 21000*ms;
//清空当前数值寄存器
SysTick->VAL=0;
//打开定时器开始递减计数
SysTick->CTRL |=(0x1<<0);
//等待当前数值计数器递减到0
while((SysTick->CTRL & (1<<16))==0);
//等待完成以后一次滴答计时结束关闭定时器
SysTick->CTRL &=(0x1<<0);
}

/********************
函数名:    delay_us
函数参数:  u32 us :需要延时时间 以us为单位
函数返回值:无
函数功能:  实现滴答定时器的us级别的延时
函数描述:
*********************/

void delay_us(u32 us)
{
//选择时钟(外部的时钟)
SysTick->CTRL &=~(0x1<<2);
//写入自动重装载值
SysTick->LOAD = 21*us;  /*    21/21000000 = 1us   */
//清空当前数值寄存器
SysTick->VAL=0;
//打开定时器开始递减计数
SysTick->CTRL |=(0x1<<0);
//等待当前数值计数器递减到0
while((SysTick->CTRL & (1<<16))==0);
//等待完成以后一次滴答计时结束关闭定时器
SysTick->CTRL &=(0x1<<0);
}


//实现任意ms级别的延时

//以500ms的延时为基准延时

void delay_xms(u32 xms)
{
u16 i =0;//延时的倍数循环变量
//计算整数个基准延时
for(i=0; i<xms/500; i++)
{
delay_ms(500);
}
//如果不是整数倍 有剩余的延时
if(xms%500!=0)  //有余数
{
delay_ms(xms%500);
}

}