【普中STM32精灵开发攻略】--第 11 章 SysTick系统定时器

发布于:2025-08-08 ⋅ 阅读:(13) ⋅ 点赞:(0)

(1)实验平台:

普中STM32精灵开发板https://item.taobao.com/item.htm?id=739076227953(2)资料下载:普中科技-各型号产品资料下载链接


        在前面章节中我们使用到的延时是通过 CPU 循环等待产生的,这个延时是不精确的。本章就给大家介绍 STM32F1 内部 SysTick 系统定时器,通过一个简单的LED 流水灯程序来讲述如何配置 SysTick 系统定时器实现精确延时。学习本章可以参考《Cortex M3 权威指南(中文)》 chpt13 Cortex-M3 的其它特性章节或者参考库函数中 core_cm3.h 文件。若结合视频学习效果更佳。本章分为如下几部分内容:

 

11.1 SysTick 定时器介绍

11.2 SysTick 定时器操作

11.2.1 SysTick 定时器寄存器

11.2.2 SysTick 定时器操作步骤

11.3 软件设计

11.3.1 SysTick_Init()函数

11.3.2 delay_us()函数

11.3.3 delay_ms()函数

11.3.4 主函数

11.4 实验现象


11.1 SysTick 定时器介绍

        SysTick 定时器也叫 SysTick 滴答定时器,它是 Cortex-M3 内核的一个外设,被嵌入在 NVIC 中。它是一个 24 位向下递减的定时器,每计数一次所需时间为1/SYSTICK,SYSTICK 是系统定时器时钟,它可以直接取自系统时钟,还可以通过系统时钟 8 分频后获取,本套程序中我们采用后者,即每计数一次所需时间为1/(72/8)us,换句话说在 1us 的时间内会计数 9 次。当定时器计数到0 时,将从LOAD 寄存器中自动重装定时器初值,重新向下递减计数,如此循环往复。如果开启 SysTick 中断的话,当定时器计数到 0,将产生一个中断信号。因此只要知道计数的次数就可以准确得到它的延时时间。

        SysTick 定时器通常应用在操作系统中,为其提供时钟周期。

11.2 SysTick 定时器操作

        在 STM32F1 库函数中,并没有提供相应的 SysTick 定时器配置函数,我们要操作 SysTick 定时器就需要了解它的寄存器功能。其实SysTick 定时器寄存器很简单,只有 4 个,分别是 CTRL、LOAD、VAL、CALIB。这些寄存器都可以在《CortexM3 权威指南(中文)》 apdx D NVIC 寄存器小结章节或者库函数core_cm3.h文件中找到,里面有详细的介绍。

11.2.1 SysTick 定时器寄存器

(1)CTRL 寄存器

        CTRL 是 SysTick 定时器的控制及状态寄存器。其相应位功能如下:

位段 名称 类型 复位值 描述
16  COUNTFLAG R 0 如果在上次读取本寄存器后,Systick已经数到了0,则该位为1。如果读取该位,该位将自动清零
2 CLKSOURCE R/W 0

0=外部时钟源(STCLK)

1=内核时钟(FCLK)

1 TICKINT R/W 0

1=Systick 倒数到0时产生Systick异常请求

0=数到0时无动作

0 ENABLE R/W 0 Systick定时器的使能位

        注:CLKSOUTCE 位是用于选择 SysTick 定时器时钟来源,如果该位为1,表示其时钟是由系统时钟直接提供即 72M。如果为 0,表示其时钟是由系统时钟八分频后提供即 72/8=9M。

(2)LOAD 寄存器

        LOAD 是 SysTick 定时器的重装载数值寄存器。其相应位功能如下:

位段 名称 类型 复位值 描述
23:0 RELOAD R/W 0 当倒数至0时,将被重装载的值

        因为 STM32F1 的 SysTick 定时器是一个 24 位递减计数器,因此重装载寄存器中只使用到了低 24 位,即 bit0-bit23。当系统复位时,其值为0。

(3)VAL 寄存器

        VAL 是 SysTick 定时器的当前数值寄存器。其相应位功能如下:

位段 名称 类型 复位值 描述
23:0 CURRENT R/Wc 0 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在 Systick 控制及状态寄存器中的COUNTFLAG标志

        同样只有 bit0-bit24 有效,复位时值为 0。

(4)CALIB 寄存器

        CALIB 是 SysTick 定时器的校准数值寄存器。其相应位功能如下:

位段 名称 类型 复位值 描述
31 NOREF R -

1=没有外部参考时钟(STCLK不可用)

0=外部参考时钟可用

30 SKEW R -

1=校准值不是准确的 10ms

0=校准值是准确的 10ms

23:0 TENMS R/W 0

10ms 的时间内倒计数的格数。芯片设计者应该通过 Cortex-M3 的输入信号提供该数值。若该值读回零,则表示无法使用校准功能

        此寄存器在定时实验中不需要使用,可以不用了解。

11.2.2 SysTick 定时器操作步骤

        SysTick 定时器的操作可以分为 4 步:

        (1)设置 SysTick 定时器的时钟源。

        (2)设置 SysTick 定时器的重装初始值(如果要使用中断的话,就将中断使能打开)。

        (3)清零 SysTick 定时器当前计数器的值。

        (4)打开 SysTick 定时器。

11.3 软件设计

        从这章开始,软件设计部分我们就不再讲述怎么复制工程、新建文件以及添加对应的头文件路径,我们直接打开实验例程内的工程进行讲解。同样SysTick定时器延时函数在任何一个 STM32F1 应用程序中都用得上,因此将其驱动文件放在 Public 文件夹内。这里我们打开“\4--实验程序\1--基础实验\5-SysTick系统定时器实验”工程,从工程 Public 组中可以看到,引进了一个新的SysTick.c源文件,此文件内的函数就是按照操作步骤完成,有对us 的延时和ms 的延时。将其打开,这里我们主要介绍关键代码。

11.3.1 SysTick_Init()函数

        SysTick_Init 函数代码如下:

//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void SysTick_Init(u8 SYSCLK)
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	fac_us=SYSCLK/8;					
	fac_ms=(u16)fac_us*1000;				   
}								    

        SysTick_Init 函数形参 SYSCLK 表示的系统时钟大小,默认配置我们使用的系统时钟是 72M,所以调用这个函数时,形参值即为 72。函数内部调用了一个库函数 SysTick_CLKSourceConfig,此函数用来对 SysTick 定时器时钟的选择,我们使用的 SysTick 定时器时钟是系统时钟的 8 分频,所以参数是SysTick_CLKSource_HCLK_Div8。如果使用系统时钟作为SysTick 定时器时钟,那么参数即为 SysTick_CLKSource_HCLK。这个函数在misc.c 库文件内,如何查找我们前面介绍过方法。

        下面的一条语句是用来求取 SysTick 定时器在 1us 时间内和1ms 时间内的计数次数。

11.3.2 delay_us()函数

        delay_us 函数代码如下:

/*******************************************************************************
* 函 数 名         : delay_us
* 函数功能		   : us延时,
* 输    入         : nus:要延时的us数
					注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)
* 输    出         : 无
*******************************************************************************/		    								   
void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 					//时间加载	  		 
	SysTick->VAL=0x00;        					//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数	  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;      					 //清空计数器	 
}

        ①将需要延时多少 us 的计数值加载到 SysTick 的LOAD 寄存器中,fac_us值是延时 1us 所需的计数值。

        ②清空当前计数值寄存器 VAL。

        ③打开 SysTick 定时器,定时器开始向下递减计数。

        ④CTRL 寄存器的第 16 位是 SysTick 递减到 0 的标志位,如果递减到0,此为置 1,通过读取该位来判断延时是否完成,从而退出while 循环。

        ⑤关闭 SysTick 定时器。

        ⑥清空当前计数值寄存器 VAL。

11.3.3 delay_ms()函数

        delay_ms 函数代码如下:

/*******************************************************************************
* 函 数 名         : delay_ms
* 函数功能		   : ms延时,
* 输    入         : nms:要延时的ms数
					注意:nms的值,SysTick->LOAD为24位寄存器,
					不要大于0xffffff*8*1000/SYSCLK
					对72M条件下,nms<=1864ms 
* 输    出         : 无
*******************************************************************************/
void delay_ms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;				//时间加载(SysTick->LOAD为24bit)
	SysTick->VAL =0x00;							//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;       					//清空计数器	  	    
} 

        此函数功能与 delay_us 基本一样,只不过这里是延时ms。要注意的是,SysTick 定时器是 24 位的,其计数最大值为 0xffffff,时间为nms<=0xffffff*8*1000/SYSCLK,SYSCLK 是系统时钟为72M,所以最大延时为1864ms。如果需要延时大于 1.864S,可以调用多个 delay_ms 函数即可。

11.3.4 主函数

        在 main.c 文件中前面引入了工程中所需的头文件,可以打开工程查看,这里我们主要看下 main 函数,代码如下:

#include "system.h"
#include "SysTick.h"
#include "led.h"



int main()
{
	SysTick_Init(72);
	LED_Init();
	while(1)
	{
		LED0=!LED0;
		delay_ms(500);  //精确延时500ms
	}
}

        主函数实现的功能比较简单,首先对 SysTick 定时器进行初始化配置,选择系统时钟作为 SysTick 的时钟,然后初始化 LED,这个初始化过程前面已经介绍过,大家也可以进入这个函数内查看。最后进入 while 循环语句,对LED 管脚进行位操作,里面也调用了 delay_ms 延时函数,这时候的延时是非常精确的。

11.4 实验现象

        将工程程序编译下载到开发板内,可以看到核心板上的LED 指示灯闪烁。


网站公告

今日签到

点亮在社区的每一天
去签到