系统滴答定时器

STM32中的定时器:

内核:SysTick 的系统定时器

定时器的工作原理

image-20201118224642372

如:想要:1ms的定时
时钟源: 72MHz
分频器:72分频
72MHz / 72 = 1MHz

1/1M s = 1us
1s = 1000ms = 1000 000 us
装载值:1000
1000 * 1 us = 1000 us = 1ms

系统定时器:

概述

处理器有一个24位的定时器:SysTick.它可以从装载值向下计数到0
24bit:计数器可以计数到 2的24次方-1
当向下计数到0时,会在下一个周期将重装载值 加载到 LOAD寄存器然后在下一个周期里重新向下计数

概述:

Systick定时器,是一个简单的定时器,对于CM3、CM4内核芯片,都有Systick定时器。Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。

使用介绍

本文介绍的滴答定时器主要是用于延时,下面我们通过两种方式来实现延时功能,一种是把滴答定时器当成普通的定时器来使用,另一种是模拟实时操作系统(RTOS),将滴答定时器作为心跳时钟,并采用时间摘取法来获得延时。

寄存器的介绍

   SysTick->CTRL,         --控制和状态寄存器
   SysTick->LOAD,         --重装载寄存器
   SysTick->VAL,          --当前值寄存器
   SysTick->CALIB,        --校准值寄存器 

SysTick control and status register (STK_CTRL) 控制和状态寄存器

image-20201118225635370 image-20201118225939353

SysTick reload value register (STK_LOAD) 重装载值寄存器

image-20201118230139306 image-20201118230231449

SysTick current value register (STK_VAL) 定时器当前值寄存器

image-20201118230627718 image-20201118230715714

定时器定时时间的计算:

实现1ms来一次的定时

时钟源:72MHz
分频 1分频
72MHz 1/72M s 1/72us
装载值给多少???
1ms (目标) / (1/72)us (时钟周期)
1000 /(1/72) = 72000 (计数次数)

系统定时器的配置

//调用函数
SysTick_Init(72000);
//系统定时器的配置,自己的函数
void SysTick_Init(uint32_t reload)
{
	SysTick->CTRL &= ~(0x1<<16);
	SysTick->CTRL |=  (0x1<<2);
	SysTick->CTRL |=  (0x1<<1);
	SysTick->LOAD = (reload & 0x00FFFFFF);
//SysTick->VAL  = (0x00);只有当VAL值为0时,计数器自动重载RELOAD。
	SysTick->VAL = 0;
	
	NVIC_SetPriority(SysTick_IRQn, 0);
	NVIC_EnableIRQ(SysTick_IRQn);
	SysTick->CTRL |=  (0x1<<0);
}
//系统时钟中断
vu32 System_Time = 0;
void SysTick_Handler(void)
{
	System_Time ++;
}
/**
\brief   System Tick Configuration
\details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
        Counter is in free running mode to generate periodic interrupts.
\param [in]  ticks  Number of ticks between two interrupts.
\return          0  Function succeeded.
\return          1  Function failed.
\note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
        function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
        must contain a vendor-specific implementation of this function.
*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
 return (1UL);                                                   /* Reload value impossible */
}

SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                SysTick_CTRL_TICKINT_Msk   |
                SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
return (0UL);                                                     /* Function successful */
}

定时器的使用

阻塞型的延时函数

image-20201118233259233
void Delay_ms(uint32_t time)
{
	uint32_t tick = System_Time + time;
    //阻塞型的延时
	while(System_Time < tick);	
    //在中断中Systerm_time的值会改变,中断返回还是回到这个断点,直到条件不成立,才能出去这个while循环
}

非阻塞型的延时---类似于时间片的分配

时间片分配的思想,使用非阻塞型的查询方式,来判断时间片是否满足要求,当时间片满足要求之后,将时间片的初值清零。

image-20201118233408377
vu32 System_Time = 0;
vu32 Led1_TaskTime[2] = {0, 500};
vu32 Led2_TaskTime[2] = {0, 300};
vu32 Key_TaskTime[2] = {0, 10};
void SysTick_Handler(void)
{
	System_Time ++;
	Led1_TaskTime[0] ++;
	Led2_TaskTime[0] ++;
	Key_TaskTime[0] ++;
}
//.h文件声明
extern vu32 Led1_TaskTime[2];
extern vu32 Led2_TaskTime[2];
extern vu32 Key_TaskTime[2];
//while(1)查询
if(Key_TaskTime[0] > Key_TaskTime[1])
{
    if(Get_KeyValue())
    {
        Beep_Toggle(BEEP_PORT, BEEP_PIN);
    }
    Key_TaskTime[0] = 0;
}

if(Led1_TaskTime[0] > Led1_TaskTime[1])
{
    Led_Toggle(LED1_PORT, LED1_PIN);
    Led1_TaskTime[0] = 0;
}

if(Led2_TaskTime[0] > Led2_TaskTime[1])
{
    Led_Toggle(LED2_PORT, LED2_PIN);
    Led2_TaskTime[0] = 0;
}
//按键获取键值
u8 Get_KeyValue(void)
{	
	u8 key_value = 0;
	static u8 count = 0;
	if((KEY_PORT->IDR & (0x1<<KEY_PIN)) == 0)
	{
		count++;
	}
	else if(count > 2)
	{
		key_value = 1;
		count = 0;
	}
	else
	{
		count = 0;
	}
	return key_value;
}
posted @ 2020-11-19 09:03  啊振不坏  阅读(960)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css