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
#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);
}
//以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);
}
}