STM32 学习(系统滴答定时器)

一、Systick介绍

STM32 学习(系统滴答定时器)_第1张图片

Systick 的信号来源于系统时钟,不分频为168MHz,8 分频为 21MHz,从下图的时钟树就可以看出来。 ---这是F4的,,F1的位72MHz的

STM32 学习(系统滴答定时器)_第2张图片

F10系列的滴答时钟---72Mhz

STM32 学习(系统滴答定时器)_第3张图片

二、4个寄存器控制SysTick定时器

♈控制及状态寄存器(CTRL)

因为是查询式,所以我们不用第1位

  • 0位(打开滴答时钟)
  • 2位(选择时钟源,我们一般选择外部时钟源)
  • 16位(查看是否数到了零)

STM32 学习(系统滴答定时器)_第4张图片

♈重装载数值寄存器(LOAD)

        这个寄存器就比较简单了,这个就是重新向滴答时钟里加载计时次数,可以看到总共有24位可设置,所以重新加载值最大不能超过24位。

♈当前数字寄存器(VAL)

这个寄存器作用在读取的时候返回当前计数值,在写入的时候就是计数器清零,同时还清除掉了SysTick->CTRL第16位的标志。

STM32 学习(系统滴答定时器)_第5张图片

♈校准数值寄存器(CALIB)

STM32 学习(系统滴答定时器)_第6张图片

以上四种寄存器,我们常用的有:

  • SysTick->CTRL(控制和状态寄存器)
  • SysTick->RELOAD(重装载数值寄存器)
  • SysTick->VAL(当前数值寄存器)

 三、Systick 延迟思路解析及实现(库函数版)

实现思路:

利用 systick定时器为递减计数器,设定初值并使能它后,它会每过一个系统时钟周期计数器进行减,直到计数到 0时,SysTick计数器会自动重装初值并继续计数,同时触发中断。

在时钟树里可以看到,对于Cortex时钟,有两种选择方法,

一、是选用经过八分频的外部时钟源,

二、是选用内核时钟,我们一般在设置的时候选用八分频后的外部时钟源,我们之前设置了系统时钟为168MHZ,经过八分频后变为了21MHZ,也就是说,滴答时钟的频率是21MHZ,那让滴答时钟计1次,时间过去了1/21μs,滴答时钟计21次,才是1μs,于是我们有了以下的设计:

  • 计1μs:我们向计数器里放入21
  • 计1ms:我们向计数器里放入21000
    1ms(毫秒)=1μs(微秒)
    配置滴答时钟步骤如下:
  • 1、清空计数器
  • 2、重新装载数值
  • 3、打开定时器
  • 4、等待计时器数到0
  • 5、关闭计数器
  • 6、清空计数器

/********************
4个Systick寄存器

CTRL: Systick控制和状态寄存器

RELOAD(LOAD): Systick自动重装载初值寄存器

VAL: Systick当前值寄存器

CALIB: Systick校准寄存器

1.选择时钟频率为 24MHz 的时钟,即周期为 1/24000000s---计21个数为1us
2.VAL中存放的数值在每一个Systick周期后减1,当减为0后,VAL就会从LOAD中加载初值,再进行倒计数。

    ******计US******
    //2^24 -1=16777215=0xffffff
    SysTick->VAL=0;//计数器清零
    SysTick->LOAD=num*24; //设置重装值
    SysTick->CTRL|=1;//使能计数器
    while(!(SysTick->CTRL &(1<<16)));//阻塞判断定时时间是否到达,判断SysTick->CTRL的位

    SysTick->CTRL =0; //失能滴答定时器
********************/

void delay_new_us(u32 num)
{

	
	u32 dealer;//商
	u32 rem;//余数
	u32 temp;
	dealer=(21*num/0xffffff);//2^24 -1=16777215=0xffffff
	rem=(21*num)%0xffffff;
	while(dealer)//商大于0时
	{
		SysTick->LOAD=(u32)0xffffff; //装载最大可装载值
		SysTick->VAL=0; //清空计数器
		SysTick->CTRL|=1;       //使能计数器,开始计数
		do
		{
			temp=SysTick->CTRL;
		}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
		dealer--;
		if(!dealer)//a为0,表示装载最大可装载值的次数用完
		{
			SysTick->CTRL&=0xfffffffe;//关闭计数器
		}
	}
	
	SysTick->LOAD=rem;//装载余数
	SysTick->VAL =0x00;	//清空计数器
	SysTick->CTRL|=1;       //重新使能计数器,开始计数
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0)) 
	
	SysTick->CTRL&=0xfffffffe;//关闭计数器
	SysTick->VAL =0X00;       //清空计数器
}

代码解析:

        通过个人改良,原本的滴答正常配置只能计2^23个数,就是798MS左右就爆了,但我通过取余的方式,将取最大数值的余数出来,再重装进去,重新定时,就可以实现超过一秒的定时,这样重复重装-------MS的延时同理,,*21000就行

注意:

        主函数必须进行滴答定时初始化函数的调用,不然使用不了

四、附上代码

封装成延时函数用就行,很精准

SysTick.c

#include "SysTick.h"

void SysTick_Init(void)
{	
	SysTick->CTRL &=~(1<<2);//选择时钟源为21MHZ--寄存器
	//SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //--库函数
	SysTick->VAL=0;//计数器清零
}


void delay_new_us(u32 num)
{

	
	u32 dealer;//商
	u32 rem;//余数
	u32 temp;
	dealer=(21*num/0xffffff);//2^24 -1=16777215=0xffffff
	rem=(21*num)%0xffffff;
	while(dealer)//商大于0时
	{
		SysTick->LOAD=(u32)0xffffff; //装载最大可装载值
		SysTick->VAL=0; //清空计数器
		SysTick->CTRL|=1;       //使能计数器,开始计数
		do
		{
			temp=SysTick->CTRL;
		}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
		dealer--;
		if(!dealer)//a为0,表示装载最大可装载值的次数用完
		{
			SysTick->CTRL&=0xfffffffe;//关闭计数器
		}
	}
	
	SysTick->LOAD=rem;//装载余数
	SysTick->VAL =0x00;	//清空计数器
	SysTick->CTRL|=1;       //重新使能计数器,开始计数
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0)) 
	
	SysTick->CTRL&=0xfffffffe;//关闭计数器
	SysTick->VAL =0X00;       //清空计数器
}

void delay_new_ms(u32 num)
{
	
	u32 a;//商
	u32 b;//余数
	u32 temp;
	a=(21000*num/0xffffff);//2^24 -1=16777215=0xffffff
	b=(21000*num)%0xffffff;
	while(a)//商大于0时
	{
		SysTick->LOAD=(u32)0xffffff; //装载最大可装载值
		SysTick->VAL=0; //清空计数器
		SysTick->CTRL|=1;       //使能计数器,开始计数
		do
		{
			temp=SysTick->CTRL;
		}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
		a--;
		if(!a)//a为0,表示装载最大可装载值的次数用完
		{
			SysTick->CTRL&=0xfffffffe;//关闭计数器
		}
	}
	
	SysTick->LOAD=b;//装载余数
	SysTick->VAL =0x00;	//清空计数器
	SysTick->CTRL|=1;       //重新使能计数器,开始计数
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0)) 
	
	SysTick->CTRL&=0xfffffffe;//关闭计数器
	SysTick->VAL =0X00;       //清空计数器	
}

SysTick.h

#ifndef __SYSTICK_H
#define __SYSTICK_H
#include "stm32f4xx.h"

void SysTick_Init(void);//初始化滴答时钟
void delay_new_us(u32 num);
void delay_new_ms(u32 num);

#endif

x形参就不用说了吧,这个给多少数值对应延时多少

你可能感兴趣的:(stm32,学习,单片机)