在前面的CLKSOURCE寄存器位也明确指明SysTick的时钟源为HCLK和HCLK / 8可选,然而在时钟树上却并没有体现时钟源可选这个关键信息,可见这是数据手册的漏洞,功能实现以寄存器的说明为主而非时钟树:SysTick的时钟源并非限定在HCLK / 8
将SysTick的时钟源设置为72MHZ,那么计数器减1间隔的时间为: (1 / 72MHz)s
SysTick系统定时器的重装载寄存器数值
使用标准外设库编程的时候我们只需要调用SysTick_Config(uint32_t ticks)函数即可 ,形参ticks用来设置重装载寄存器的值,最大不可超过2的24次方,当重装载寄存器的值递减到0的时候产生中断,然后重装载寄存器的值又重新装载往下递减计数,以此循环。
设置ticks的值等价于设置计时时间,中间有一个简单的换算过程:SysTick每递减1需要(1/72MHZ)s,那么定时1s则将ticks取值为72000000,定时1ms则ticks取值为72000,定时10us则ticks取值为720,定时1us则ticks取值为72,总归:
SysTick时钟源 / 1000 => 定时1ms
SysTick时钟源 / 100000 => 定时10us
SysTick时钟源 / 1000000 => 定时1us
视频中:
时钟源为72HZ说明1us中有72个脉冲。若想延迟10us,则systick就要设置为72*10=720
阐述了以上知识点,下来就是编程练习了:利用SysTick系统定时器,实现精准延时,这个在实际工程项目中十分常用。
硬件平台正点原子MiniSTM32,实现的功能是精准延时让板载的两个LED灯闪烁。编程的要点是调用SysTick_Config()函数设置计数器的重装载值。
新建文件main.c和systick_test.h分别用于实现主体功能和函数声明:
systick_test.h
#ifndef __SYSTICK_TEST_H__
#define __SYSTICK_TEST_H__
#include "stm32f10x_conf.h"
void Led_CfgInit(void);
void SysTick_Delay_Us(__IO uint32_t us);
void SysTick_Delay_Ms(__IO uint32_t ms);
#endif /* __SYSTICK_TEST_H__ */
main.c
#define ALL_LED_ON GPIO_ResetBits(GPIOA,GPIO_Pin_8);\
GPIO_ResetBits(GPIOD,GPIO_Pin_2)
#define ALL_LED_OFF GPIO_SetBits(GPIOA,GPIO_Pin_8);\
GPIO_SetBits(GPIOD,GPIO_Pin_2)
//PA8-->LED0,PD2-->LED1
void Led_CfgInit(void)
{
GPIO_InitTypeDef GPIO_InitTypeStu;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitTypeStu.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_8;
GPIO_InitTypeStu.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitTypeStu);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitTypeStu);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
}
//配置SysTick的计数器计数的时间是1us,每间隔1us,CTRL的BIT[16]由0刷新为1
void SysTick_Delay_Us(__IO uint32_t us)
{
uint32_t i;
SysTick_Config(72);
for (i = 0; i < us; i++)
{
while (!((SysTick->CTRL >> 16) & 0x01));
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
//配置SysTick的计数器计数的时间是1ms,每间隔1us,CTRL的BIT[16]由0刷新为1
void SysTick_Delay_Ms(__IO uint32_t ms)
{
uint32_t i;
SysTick_Config(72000);
for (i = 0; i < ms; i++)
{
//while (!(SysTick->CTRL & (1 << 16)));
while (!((SysTick->CTRL >> 16) & 0x01));
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
int main(void)
{
SysTick_Delay_Us(10);
Led_CfgInit();
while (1)
{
ALL_LED_ON;
SysTick_Delay_Ms(1000);
ALL_LED_OFF;
SysTick_Delay_Ms(5000);
}
}
SysTick_Delay_Ms()和SysTick_Delay_Us()分别实现n个1Ms定时和n个1Us定时的功能。
以SysTick_Delay_Ms()为例,其中的SysTick_Config(72000)定义了每间隔1ms触发一次SysTick中断,当然,同时CTRL的BIT[16]会由0变为1,随后计数器又会从重装载器中取出72000开始递减,此时TRL的BIT[16]会由1变为0,如此循环。基于这个特点,这里采用轮询CTRL的BIT[16]的方法以达到延时的目的,这里中断处理函数未使用。
下来采用中断处理函数的方法:
--------------------- 本文来自 bright261 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/qq_29344757/article/details/75090137?utm_source=copy