【普中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 指示灯闪烁。

相关推荐
李夕4 小时前
掌握工程化固件烧录,开启你的技术进阶之路-FPGA ISE(xilinx)
嵌入式硬件·fpga·固件
Hello_Embed6 小时前
STM32HAL 快速入门(二):用 CubeMX 配置点灯程序 —— 从工程生成到 LED 闪烁
笔记·stm32·单片机·学习·嵌入式软件
JasmineX-16 小时前
STM32的SPI通信(软件读写W25Q64)
c语言·stm32·单片机·嵌入式硬件
HW-BASE11 小时前
《C语言》指针练习题--1
c语言·开发语言·单片机·算法·c
DIY机器人工房13 小时前
一个程序通过 HTTP 协议调用天气 API,解析 JSON 格式的天气数据,提取关键信息并格式化输出:日期、天气状况、温度范围、风向、湿度等核心气象数据。
嵌入式硬件·嵌入式·diy机器人工房
小杨爱搞嵌入式15 小时前
【STM32】GPIO的输入输出
c语言·笔记·stm32·单片机·学习
神仙别闹16 小时前
基于Python+Vue+Mysql实现(物联网)智能大棚
vue.js·物联网·mysql
不会先思考16 小时前
A3.0:防反接和防倒灌的物理意义
单片机·嵌入式硬件
科技风向标17 小时前
物联网架构全解析:华为“1+2+1”与格行随身WiFi,技术如何定义未来生活?
物联网·华为·架构