利用系统滴答定时器,实现单片机的精确延时。在ARM Cortex-M3和M4内核中有一个Systick定时器,它是一个24位的向下计数定时器,当计数到0时,它就会从Load寄存器中自动重装定时初值,只要不把CTRL寄存器中的ENABLE清0,它就永不停。
Systick定时器常用来做精确延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。
精确延时的意义:在很多传感器中,延时需要精确到us,用来做一个启动信号,如果说延时不精确,很难捕捉到启动信号。
相关寄存器
代码实现:
delay.h
#ifndef _DELAY_H_
#define _DELAY_H_
#include "stm32f4xx.h"
void delay_ms(uint32_t nms);
void delay_us(uint32_t nus);
#endif
delay.c
#include "delay.h"
//延时函数:毫秒级别
void delay_ms(uint32_t nms)
{
uint32_t tmp;
while(nms--)
{
SysTick->LOAD = 168000000/8/1000; //计数初值,延时1ms
SysTick->VAL = 0; //清空当前值
SysTick->CTRL |= 0x1; //开始计数
do
{
tmp = SysTick->CTRL; //获取CTRL状态
}while((tmp&0x1) && !(0x1<<16));
SysTick->VAL = 0; //清空当前值
SysTick->CTRL &= 0; //关闭计数
}
}
//延时函数:微秒级别
void delay_us(uint32_t nus)
{
uint32_t tmp;
while(nus--)
{
SysTick->LOAD = 168000000/8/1000000; //计数初值,延时1us
SysTick->VAL = 0; //清空当前值
SysTick->CTRL |= 0x1; //开始计数
do
{
tmp = SysTick->CTRL; //获取CTRL状态
}while((tmp&0x1) && !(0x1<<16));
SysTick->VAL = 0; //清空当前值
SysTick->CTRL &= 0; //关闭计数
}
}
main.c
#include <stm32f4xx.h> //stm32标准头文件
#include "sys.h"
#include "delay.h"
//初始化led
void init_led(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//开启GPIOF的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
//模式选择:输入、输出、复用、模拟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出模式
//类型选择:推挽、开漏
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽模式
//速度选择:低速、中速、快速、高速
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //高速模式
//上下拉选择:无上下拉、上拉、下拉
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉
//初始化GPIOF
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_SetBits(GPIOF,GPIO_Pin_9);//初始状态设置为高电平,熄灭
}
int main(void)
{
//设置嘀嗒定时器时钟源
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//用于配置延时函数
init_led();
while(1)
{
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //将引脚设置为低电平(点亮)
delay_ms(500); //延时一会
GPIO_SetBits(GPIOF,GPIO_Pin_9); //将引脚设置为高电平(熄灭)
delay_ms(500);
}
}
主函数中对于时钟源的配置说明:
/**
* @brief Configures the SysTick clock source.
* @param SysTick_CLKSource: specifies the SysTick clock source.
* This parameter can be one of the following values:
* @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
* @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
* @retval None
*/
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
/* Check the parameters */
assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
{
SysTick->CTRL |= SysTick_CLKSource_HCLK;
}
else
{
SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
}
}
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
参数选择:
SysTick _ clk source _ HCLK _ div 8:AHB时钟除以8,选择作为systick时钟源。
SysTick_CLKSource_HCLK:选择AHB时钟作为SysTick时钟源。
SysTick_CLKSource_HCLK_Div8:AHB时钟/8=168MHz/8=21MHz(推荐)
SysTick_CLKSource_HCLK:AHB时钟=168MHz
最大延时时间分别是多久:
SysTick_CLKSource_HCLK_Div8:(2^24 - 1)/2100000 = 798.915ms
SysTick_CLKSource_HCLK:(2^24 - 1)/168000000 = 99.864375ms