【STM32】定时器
一、 系统定时器
SysTick 叫做系统滴答时钟、 系统定时器, 属于 Cortex-M4 内核中的一个外设(外围设备), 它 24bit 向下递减
的计数 器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。
Systick中断的优先级也可以设置。
二、 系统定时器的中断使用方法
1.代码的初始化
//初始化系统定时器, 1S 内核触发 1000 次中断, 说白了定时 1ms
SysTick_Config(SystemCoreClock/1000);
-
中断服务函数的编写
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;
}
}
- 定时时间的计算
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计时器设置为某个值并等待直到其达到零的定时延迟:
- 配置系统定时器的时钟源
/**
* @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);
- 当 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
- 当 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 的时候, 5;
while((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 的时候, 5;
while ((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
}
}
作者:DS陈工