【ufun使用】普通的延时和使用SysTick(系统定时器)延时

上次点了一个灯之后,总觉得没有什么意思,因为LED一直亮的也没什么意思,所以就得让它闪动起来,学过C语言的同学都知道一个空的循环函数就可以使CPU在那里空转,以达到延时的目的,所以这是我们的第一个延时的代码

void delay(unsigned int t)
{
	while(t --);
}

但是,如果这样就结束了,那就太没意思了,这可是stm32单片机啊,一个普普通通的延时就可以搞出花儿来。学过51的都知道,51有一个定时器的东西,stm32也有一个叫定时器的东西,当然stm32不只有一个定时器,它有一堆定时器,但是我现在主要说的是它的SysTick(系统定时器),人们常说的是滴答定时器,它属于Cortex-M3内核的一个外设,内嵌早NVIC(嵌套中断向量)中。系统定时器是一个24bit的向下递减的计数器,计数器每记数一次的时间是1/系统时钟,注意:系统时钟是八分频的,看图

如果是72M,经过分频之后是9M, 所以系统定时器定时一次是1/9M。那么我们计九次就是1us。当重装载数值寄存器的值递减到0时,系统定时器就产生一次中断,以此循环往复。
因为SysTick属于CM3内核的外设,所以所有基于CM3内核的单片机都具有这个系统定时器,这使得软件在CM3单片机中可以很容易移植。系统定时器在一般用于操作系统,用于产生时基,维持系统的心跳。在裸机中也常用作延时。
系统定时器有4个寄存器。使用SysTick产生定时的时候,只需要配置前三个寄存器,最后一个校准计时器不需要使用。
CTRL(控制及状态控制器) LOAD(重装载数值寄存器 )
VAL(当前数值寄存器) CALIB  校准寄存器

介绍如图

led系统定时器延时实验

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

uint32_t fac_us;
uint32_t fac_ms;

void GPIO_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct; //定义一个gpio结构体
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能时钟(为了节省功耗,时钟默认关)
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //设置为上拉推挽输出
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1 | GPIO_Pin_2; //定义0引脚
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //管脚速度
	GPIO_Init(GPIOA, &GPIO_InitStruct); //初始化gpio
}

#if 0
//普通的延时
//非常简单的延时,靠的是CPU的空转
//这种计时并不准确
void delay(unsigned int t)
{
	while(t --);
}

#else
/*这个是寄存器编程控制SysTick的寄存器有4个他们的名字是
CTRL(控制及状态控制器) LOAD(重装载数值寄存器 )
VAL(当前数值寄存器) CALIB  校准寄存器*/
void delay_init(uint8_t SYSCLK)  //系统时钟是72MHz,SYSCLK=72  
{  
    SysTick->CTRL &= 0xfffffffb ; //bit2清0,也就是配置选择外部时钟
								//在CTRL寄存器中CLKSOURCE是用来设置时钟源的
								//这个也可以不设置,因为默认的就是0 外部时钟源
    fac_us=SYSCLK / 8; //硬件8分频,分频至系统时钟一样的数字  
    fac_ms =(uint32_t)fac_us*1000;     
}  
void sysTick_delay_us(__IO uint32_t nus)
{
    uint32_t temp;  
    SysTick->LOAD = nus*fac_us;  //延时10us的话就是  10*9=90,装到load寄存器中 计9次是1us 
    SysTick->VAL=0x00;//当前计数器清0
    SysTick->CTRL = 0x01;//配置使异常生效,也就是计数器倒数到0时将发出异常通知  
    do  
    {  
       temp = SysTick->CTRL;  //时间到了之后,该位将被硬件置1,但被查询后自动清0  
    }  
    while(temp & 0x01 && !(temp &(1<<16))); //查询 ,如果计时时间到了,就停止 
    SysTick->CTRL = 0x00;  //关闭计数器  
    SysTick->VAL = 0x00;   //清空val  
	
}

void sysTick_delay_ms(__IO uint32_t ums)
{
    uint32_t temp;  
    SysTick->LOAD = ums*fac_ms; 
    SysTick->VAL=0x00;//计数器清0 
    SysTick->CTRL = 0x01;//配置使异常生效,也就是计数器倒数到0时将发出异常通知  
    do  
    {  
       temp = SysTick->CTRL;  //时间到了之后,该位将被硬件置1,但被查询后自动清0  
    }  
    while(temp & 0x01 && !(temp &(1<<16))); //查询  
    SysTick->CTRL = 0x00;  //关闭计数器  
    SysTick->VAL = 0x00;   //清空val  
}
#endif

int main(void)
{
	GPIO_init(); //初始化GPIO
	delay_init(72);
	while(1)
	{
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
		GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);
		GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_SET);
		sysTick_delay_ms(1000);
		GPIO_SetBits(GPIOB, GPIO_Pin_8);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
		GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);
		GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_SET);
		sysTick_delay_ms(1000);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
		GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);
		GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_RESET);
		sysTick_delay_ms(1000);
	}
}

发布了25 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/little_engineer/article/details/89011698