【STM32】定时器

发布于:2024-10-12 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、 系统定时器
SysTick 叫做系统滴答时钟、 系统定时器, 属于 Cortex-M4 内核中的一个外设(外围设备), 它 24bit 向下递减
的计数 器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。

SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。

Systick中断的优先级也可以设置。
在这里插入图片描述

在这里插入图片描述

二、 系统定时器的中断使用方法
1.代码的初始化

在这里插入图片描述

在这里插入图片描述

//初始化系统定时器, 1S 内核触发 1000 次中断, 说白了定时 1ms
SysTick_Config(SystemCoreClock/1000);
  1. 中断服务函数的编写

    void SysTick_Handler(void)
    {
        static uint32_t cnt=0;
        cnt++;
        //到达 500ms 的定时
        if(cnt >= 500)
        {
            cnt=0;
            PFout(9)^=1;
        }
    }
    


    : 如果发现中断服务函数定时不准确, 请检查
    1) SysTick_Config 函数是否填写参数正确
    2) 检查 PLL 的配置是否准确

练习 1:

使用系统定时器实现 LED 不同的闪烁时间。

LE0 500ms

LED1 1500ms

#include "led.h"
#include "beep.h"
#include "sys.h"


int main()
{
	init_led();
	
	// 配置滴答定时器
	// SystemCoreClock = 168M
	// 1s触发1000此中断,1ms触发一次中断
	SysTick_Config(SystemCoreClock / 1000);

	while(1)
	{
		
	
	}
}

// 1ms会触发一次此函数
void SysTick_Handler(void)
{
	static uint32_t i,j,k;
	i++;
	j++;
	k++;
	if(i == 1000) // 1s
	{
		//PFout(9) ^= 1;
		i = 0;
	}
	if(j == 500) // 500ms
	{
		PFout(10) ^= 1;
		j = 0;
	}
	if(k == 1500) // 1500ms
	{
		PFout(9) ^= 1;
		k = 0;
	}
}

  1. 定时时间的计算

SysTick_Config(SystemCoreClock/频率);

在这里插入图片描述

思考题, 让系统定时器触发 1 秒中断是否可以? 如果不可以, 最大的定时时间又是什么?
答:

不可以,因为最大定时时间是99.86ms

在这里插入图片描述

测试结果:

//初始化系统定时器, 1S 内核触发 1000 次中断, 说白了定时 1ms, 能够成功
//SysTick_Config(SystemCoreClock/1000);
//初始化系统定时器, 1S 内核触发 10 次中断, 说白了定时 100ms,现象失败
SysTick_Config(SystemCoreClock/10);
//初始化系统定时器, 1S 内核触发 11 次中断, 说白了定时 90.90ms,能够成功
SysTick_Config(SystemCoreClock/11);  
三、 系统定时器的用途

两个方面:
没有操作系统: 只用于延时
有操作系统(ucos2 ucos3 freertos…) :为操作系统提供精准的定时中断(1ms~50ms)

四、 使用系统定时器用于延时的用途

If you want to use the SysTick timer in polling mode, you can use the count flag in the SysTick Control
and Status Register (SysTick->CTRL) to determine when the timer reaches zero. For example, you can create
a timed delay by setting the SysTick timer to a certain value and waiting until it reaches zero:
如果要在轮询模式下使用SysTick计时器,可以使用SysTik控件中的计数标志
和状态寄存器(SysTick->CTRL),以确定计时器何时达到零。例如,您可以创建
通过将SysTick计时器设置为某个值并等待直到其达到零的定时延迟:
  1. 配置系统定时器的时钟源

/**
* @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;
}
}

在这里插入图片描述

2.系统定时器寄存器

4个Systick寄存器

CTRL SysTick 控制和状态寄存器 LOAD

SysTick 自动重装载值寄存器
VAL SysTick 当前值寄存器 CALIB

SysTick 校准值寄存器

在这里插入图片描述

在这里插入图片描述

滴答定时器相关函数

   //Systick时钟源选择  misc.c文件中
   SysTick_CLKSourceConfig()    
   //初始化systick,时钟为HCLK,并开启中断
   //core_cm3.h/core_cm4.h文件中
   SysTick_Config(uint32_t ticks)

  //Systick中断服务函数:
  void SysTick_Handler(void);
                                                  
  1. 当 SysTick 使用 168MHz 系统时钟频率时, 代码编写如下:
void delay_us(uint32_t nus)
{
    SysTick->CTRL = 0; // Disable SysTick
    SysTick->LOAD = (SystemCoreClock/1000000)*nus; // 计数值
    SysTick->VAL = 0; // 清除当前值和计数标志
    SysTick->CTRL = 5; // 启动定时器
    while ((SysTick->CTRL & 0x00010000)==0);// 等待计数完成
    SysTick->CTRL = 0; // 关闭定时器
} 
void delay_ms(uint32_t nms)
{
    SysTick->CTRL = 0; // Disable SysTick
    SysTick->LOAD = (SystemCoreClock/1000)*nms; // 计数值
    SysTick->VAL = 0; // Clear current value as well as count flag
    SysTick->CTRL = 5; // Enable SysTick timer with processor clock
    while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
    SysTick->CTRL = 0; // Disable SysTick
}

最大的延时为 99.86ms

  1. 当 SysTick 使用 168MHz 系统时钟频率并进行 8 分频时, 代码编写如下:
void delay_us(uint32_t nus)
{
    SysTick->CTRL = 0; // Disable SysTick
    SysTick->LOAD = (SystemCoreClock/8/1000000)*nus; // 计数值
    SysTick->VAL = 0; // Clear current value as well as count flag
    SysTick->CTRL = 1; // Enable SysTick timer with processor clock
    while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
    SysTick->CTRL = 0; // Disable SysTick
} 
void delay_ms(uint32_t nms)
{
    SysTick->CTRL = 0; // Disable SysTick
    SysTick->LOAD = (SystemCoreClock/8/1000)*nms; // 计数值
    SysTick->VAL = 0; // Clear current value as well as count flag
    SysTick->CTRL = 1; // Enable SysTick timer with processor clock
    while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
    SysTick->CTRL = 0; // Disable SysTick
}

思考题, 当前最大的延时时间是多少? 如何优化代码, 支持秒级别或更长时间的延时?
最大的延时时间 = 2^24 / 21000000 ≈ 798.91ms

void delay_ms(uint32_t nms)
{
    uint32_t m,n;
    m = nms/500;
    n = nms %500;
    //m 个 500ms 的延时
    while(m--)
    {
        SysTick->CTRL = 0; // Disable SysTick
        SysTick->LOAD = (SystemCoreClock/8/1000)*500; // 计数值
        SysTick->VAL = 0; // Clear current value as well as count flag
        SysTick->CTRL = 1; // Enable SysTick timer with processor clock, 当使用
        21MHz 的时候, 1; 当使用 168MHz 的时候, 5while((SysTick->CTRL & 0x00010000)==0);
        SysTick->CTRL = 0; // Disable SysTick
    }
    //不足 500ms 的延时
    if(n)
    {
        SysTick->CTRL = 0; // Disable SysTick
        SysTick->LOAD = (SystemCoreClock/8/1000)*n; // 计数值
        SysTick->VAL = 0; // Clear current value as well as count flag
        SysTick->CTRL = 1; // Enable SysTick timer with processor clock, 当使用
        21MHz 的时候, 1; 当使用 168MHz 的时候, 5while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
        SysTick->CTRL = 0; // Disable SysTick
    }
}    
// 或者
void delay_ms(uint32_t t)
{
	while(t--)
	{
		SysTick->CTRL = 0;		// Disable SysTick
		SysTick->LOAD = SystemCoreClock/1000; 	// 1ms
		SysTick->VAL = 0; 	// Clear current value as well as count flag
		SysTick->CTRL = 5; 	// Enable SysTick timer with processor clock
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
		SysTick->CTRL = 0; 						// Disable SysTick
	
	}
}

k->LOAD = SystemCoreClock/1000; // 1ms
SysTick->VAL = 0; // Clear current value as well as count flag
SysTick->CTRL = 5; // Enable SysTick timer with processor clock
while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
SysTick->CTRL = 0; // Disable SysTick

}

}