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

(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.1 SysTick 定时器介绍)

[11.2 SysTick 定时器操作](#11.2 SysTick 定时器操作)

[11.2.1 SysTick 定时器寄存器](#11.2.1 SysTick 定时器寄存器)

[11.2.2 SysTick 定时器操作步骤](#11.2.2 SysTick 定时器操作步骤)

[11.3 软件设计](#11.3 软件设计)

[11.3.1 SysTick_Init()函数](#11.3.1 SysTick_Init()函数)

[11.3.2 delay_us()函数](#11.3.2 delay_us()函数)

[11.3.3 delay_ms()函数](#11.3.3 delay_ms()函数)

[11.3.4 主函数](#11.3.4 主函数)

[11.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 函数代码如下:

cpp 复制代码
//初始化延迟函数
//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 函数代码如下:

cpp 复制代码
/*******************************************************************************
* 函 数 名         : 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 函数代码如下:

cpp 复制代码
/*******************************************************************************
* 函 数 名         : 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 函数,代码如下:

cpp 复制代码
#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 指示灯闪烁。

相关推荐
时空自由民.9 小时前
FOC开环控制代码解读
嵌入式硬件
贾亚超13 小时前
【STM32外设】ADC
stm32·单片机·嵌入式硬件
2006yu13 小时前
从零开始学习单片机18
单片机·嵌入式硬件·学习
意法半导体STM3215 小时前
STM32 USBx Device MSC standalone 移植示例 LAT1488
单片机·嵌入式硬件·device·msc·standalone·usbx
MThinker15 小时前
k230 按键拍照后,将摄像头拍照的1920*1080分辨率的图片以jpg文件格式,保存到板载TF存储卡的指定文件夹目录中
python·嵌入式硬件·智能硬件·micropython·canmv·k230
云望无线图传模块17 小时前
突破视界的边界:16公里远距离无人机图传模块全面解析
网络·物联网·无人机
清风66666617 小时前
基于STM32单片机的OneNet物联网云平台农业土壤湿度控制系统
stm32·单片机·物联网·毕业设计·课程设计
曼彻斯特的海边20 小时前
物联网(IoT)中常用的通信协议
物联网·iot
神一样的老师20 小时前
面向 6G 网络的 LLM 赋能物联网:架构、挑战与解决方案
网络·物联网·架构
学不动CV了20 小时前
嵌入式硬件电路分析---AD采集电路
arm开发·stm32·单片机·嵌入式硬件·51单片机