一、系统定时器
SysTick叫做系统滴答时钟、系统定时器,属于Cortex-M4内核中的一个外设,它24bit向下递减的计数器
二、系统定时器的中断使用方法
1.代码的初始化
//初始化系统定时器,1S内核触发1000次中断,说白了定时1ms SysTick_Config(SystemCoreClock/1000);
2. 中断服务函数的编写
void SysTick_Handler(void) { static uint32_t cnt=0; cnt++; //到达500ms的定时 if(cnt >= 500) { cnt=0; PFout(9)^=1; } }
#include <stdio.h> #include "stm32f4xx.h" #include "sys.h" GPIO_InitTypeDef GPIO_InitStructure; int main(void) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); /* 配置PF9引脚为输出模式 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //设置输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽模式,增加驱动电流 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置IO的速度为100MHz,频率越高性能越好,频率越低,功耗越低 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不需要上拉电阻 GPIO_Init(GPIOF, &GPIO_InitStructure); //初始化系统定时器,1S内核触发1000次中断,说白了定时1ms //SysTick_Config(SystemCoreClock/1000);// 168000000 //初始化系统定时器,1S内核触发10次中断,说白了定时100ms,现象失败 SysTick_Config(SystemCoreClock/10); //初始化系统定时器,1S内核触发11次中断,说白了定时90.90ms,能够成功 SysTick_Config(SystemCoreClock/11); PFout(9)=1; while(1) { } } void SysTick_Handler(void) { static uint32_t cnt=0; cnt++; //到达500ms的定时 if(cnt >= 5) { cnt=0; PFout(9)^=1; } }
3. 定时时间的计算
SysTick_Config(SystemCoreClock/频率);
让系统定时器触发1秒中断是否可以?如果不可以,最大的定时时间又是什么?
不能触发1秒中断。
在额定频率情况下,最大定时时间 = 2^24 /168000000 ≈ 99.86ms
在超频的频率(216MHz)下,最大定时时间 = 2^24 /216000000≈77.67ms
测试结果:
//初始化系统定时器,1S内核触发1000次中断,说白了定时1ms,能够成功 //SysTick_Config(SystemCoreClock/1000); //初始化系统定时器,1S内核触发10次中断,说白了定时100ms,现象失败 最大只能99.86ms 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->CTRL = 0; // Disable SysTick SysTick->LOAD = 0xFF; // Count from 255 to 0 (256 cycles) 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
1. 配置系统定时器的时钟源
SysTick_Config初始化定时器会触发中断,不需要中断时,用SysTick_CLKSourceConfig来配置
/** * @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,系统定时器寄存器
1. 当SysTick使用168MHz系统时钟频率时,代码编写如下:
void delay_us(uint32_t nus) { SysTick->CTRL = 0; // Disable SysTick SysTick->LOAD = (SystemCoreClock/1000000)*nus; // 计数值 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 } 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
2. 当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);// Wait until count flag is set 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 } }
#include <stdio.h> #include "stm32f4xx.h" #include "sys.h" GPIO_InitTypeDef GPIO_InitStructure; 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,当使用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 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);// Wait until count flag is set 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 } } int main(void) { //配置系统定时器时钟源,当前是使用168MHz //SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); //配置系统定时器时钟源,当前是使用168MHz/8=21MHz SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); /* 配置PF9引脚为输出模式 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //设置输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽模式,增加驱动电流 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置IO的速度为100MHz,频率越高性能越好,频率越低,功耗越低 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不需要上拉电阻 GPIO_Init(GPIOF, &GPIO_InitStructure); while(1) { #if 0 delay_ms(90);delay_ms(90);delay_ms(90);delay_ms(90);delay_ms(90);delay_ms(90); PFout(9)=0; delay_ms(90);delay_ms(90);delay_ms(90);delay_ms(90);delay_ms(90);delay_ms(90); PFout(9)=1; #else delay_ms(1000); PFout(9)=0; delay_ms(1000); PFout(9)=1; #endif } }