STM32之SysTick(系统定时器)

发布者:MusicLover123最新更新时间:2018-07-17 来源: eefocus关键字:STM32  SysTick  系统定时器 手机看文章 扫描二维码
随时随地手机看文章

SysTick定时器是被捆绑在NVIC中的,用于产生SysTick异常(异常号是15)。(同样,玩过51单片机的都知道定时器的作用了)

在STM32在内核部分是包含了一个简单的定时器–SysTick timer。因为在所有的Cortex-M3芯片上都有这个定时器,所以软件在不同芯片生产厂商的Cortex-M3器件间的一只工作就得以化简。 
该定时器的时钟源可以是内部时钟( FCLK, CM3 上的自由运行时钟),或者是外部时钟(CM3 处理器上的 STCLK 信号)。不过, STCLK 的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可 
能会大不相同。因此,需要阅读芯片的使用手册来确定选择什么作为时钟源。 
*(在 STM32 中 SysTick 以 HCLK(AHB 时钟)或 HCLK/8 作为运行时钟。) 
SysTick定时器能产生中断,Cortex-M3专门为它开出一个异常类型,并且在向量表中存在。所以他能使操作系统和其他系统软件在Cortex-M3器件间的移植变的更简单了,因为在所有Cortex-M3产品之间,SysTick的处理方式都是相同的。

SysTick timer工作分析:

SysTick 是一个 24 位的定时器,即一次最多可以计数 224 个时钟脉冲,这个脉冲计数值被保存到 当前计数值寄存器 STK_VAL (SysTick current valueregister) 中,只能向下计数,每接收到一个时钟脉冲 STK_VAL 的值就向下减1,直至 0,当 STK_VAL 的值被减至 0 时,由硬件自动把重载寄存器 
STK_LOAD( SysTick reload value register) 中保存的数据加载到 STK_VAL,重新向下计数。当 STK_VAL 的值被计数至 0 时,触发异常,就可以在中断服务函数中处理定时事件了。 
(要使 SysTick 进行工作必须要进行SysTick配置。它的控制配置很简单,只有三个控制位和一个标志位,都位于寄存器 STK_CTRL) 
这里写图片描述

Bit0: ENABLE: 
为 SysTick timer 的使能位,此位为 1 的时候使能 SysTick timer,此位为 0的时候关闭 SysTick timer。

Bit1: TICKINT: 
为异常触发使能位,此位为 1 的时候并且 STK_VAL 计数至 0 时会触发SysTick 异常,此位被配置为 0 的时候不触发异常

Bit2: CLKSOURCE: 
为 SysTick 的时钟选择位,此位为 1 的时候 SysTick 的时钟为 AHB 时钟,此位为 0 的时候 SysTick 时钟为 AHB/8( AHB 的八分频)。

Bit16: COUNTFLAG: 
为计数为 0 标志位,若 STK_VAL 计数至 0,此标志位会被置 1。 
(STK_CALIB 寄存器是用于校准的,不常用。可以在STM32数据手册中找到所有SysTick相关寄存器)

实例分析SysTick(延时流水灯)

主函数功能: 
int main() 

LED_GPIO_Config(); //LED GPIO初始化

SysTick_Init();    //配置SysTick




while(1)           //一个死循环的流水灯

{

    LED1(0);

    Delay_us(50000);

    LED1(1);


    LED2(0);

    Delay_us(50000);

    LED2(1);


    LED3(0);

    Delay_us(50000);

    LED3(1);

}


return 0;


}


SysTick_Init()分析


void SysTick_Init(void) 

{


/* SystemFrequency / 1000 1ms 中断一次 

SystemFrequency / 100000 10us 中断一次 

SystemFrequency / 1000000 1us 中断一次 */


// if (SysTick_Config(SystemFrequency / 100000)) // ST3.0.0 库版本 

if (SysTick_Config(SystemCoreClock / 100000)) // ST3.5.0 库版本 

while (1); 

}


SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;//关闭定时器


其实函数里面就调用了一个函数SysTick_Config(),这个函数是属于内核层的Cortex-M3的通用函数,位于Core_cm3.h中。函数工作很简单,就是若调用SysTick_Config()不成功,则进入死循环,当初始化SysTick成功后,先关闭定时器,需要用的时候再开启。(我们可以在keil环境下跟踪这个函数查看函数的定义) 

/* 

* @brief Initialize and start the SysTick counter and its interrupt. 

* @param ticks number of ticks between two interrupts 

* @return 1 = failed, 0 = successful 

* Initialise the system tick timer and its interrupt and start the 

* system tick timer / counter in free running mode to generate 

* periodical interrupts. 

*/ 

static __INLINE uint32_t SysTick_Config(uint32_t ticks) 

/* Reload value impossible */ 

if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); // 

/* set reload register */ 

SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; 

/* set Priority for Cortex-M0 System Interrupts */ 

NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); 

/* Load the SysTick Counter Value */ 

SysTick->VAL = 0;


SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | 

SysTick_CTRL_TICKINT_Msk | 

SysTick_CTRL_ENABLE_Msk; /* Enab 

le SysTick IRQ and SysTick Timer */ 

return (0); /* Func 

tion successful */ 

}


这个函数的主要功能:启动了SysTimer,并且把它配置为计数至0引起中断,输入的参数ticks为两次中断之间的脉冲数(既相隔ticks个时钟周期会引起一次中断),配置SysTick成功时返回0,出错返回1


以下为详细分析: 

if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); 

因为ticks这个参数是脉冲计数值,要被保存到重载寄存器 STK_LOAD 寄存器中,再由硬件把STK_LOAD值加载到当前计数值寄存器STK_VAL使用的,因为STK_LOAD和STK_VAL都是24位,所以在输入ticks大于可存储的最大值时,由这行代码检查出错误返回。


SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; 

当ticks的值没有错误后,就把ticks-1赋值到STK_LOAD寄存器中(注意是减1),当STK_VAL从ticks-1向下计数到0,则就经过了ticks个脉冲。 

(这里面用到的SysTick_LOAD_RELOAD_Msk宏(在keil环境下跟踪查看定义),这个宏是用来指示寄存器的“特定位置”或者是用来“位屏蔽”,所以叫位指示宏或位屏蔽宏,这个在操作寄存器代码中经常用到,通常都是用作控制寄存器某些位(“或”和“与”操作))


NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); 

调用了NVIC_SetPriority()函数配置了SysTick中断,所以我们就不需要再去手动配置。配置完后把STK_VAL寄存器重新赋值为0。


SysTick->CTRL配置 

向STK_CTRL写入SysTick timer的控制参数,配置为时钟,使能为计数至0引起中断,使能SysTick,接着SysTick就开始运行,做脉冲计数。 

(如果想使用AHB/8作为时钟,可以调用库函数SysTick_CLKSourceConfig()或者修改SysTick->CTRL的使能配置)


最后在调用完SysTick_Config()后,SysTick定时器被打开了,但是我们并不是需要这样,所以在调用完之后关闭定时器 

// 使能定时器 

SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; 

// 关闭定时器 

SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; 

(这里又用到位屏蔽宏,可见用的是十分广泛)


定时时间的计算: 

再调用完SysTick_Config()时,输入ticks为SystemCoreClock / 100000 SystemCoreClock 为定义了系统时钟(SYSCLK)频率的宏,即等于AHB的时钟频率,历程用到AHB都是72MHz,所以SystemCoreClock这个宏展开就是7200 0000. 

根据前面对 SysTick_Config()函数的介绍,它的输入参数为SysTick将要计的脉冲数,经过 ticks 个脉冲(经过 ticks 个时钟周期)后将触发中断,触发中断后又重新开始计数。


由此我们可以算出定时的时间,下面为计算公式: 

T=ticks*(1/f) 

T 为要定时的总时间。 

ticks 为 SysTick_Config()的输入参数。 

1/ f 即为 SysTick timer 使用的时钟源的时钟周期,f为该时钟源的时钟频率,当时钟源确定后为常数。 

例如本实例使用时钟源为 AHB 时钟,其频率被配置为 72MHz。调用函数时,把ticks赋值为 ticks=SystemFrequency / 10000 =720,表示720个时钟周期中断一次;( 1/f)是时钟周期的时间,此时(1/f =1/72us ),所以最终定时总时间 T=720*(1/72),为 720 个时钟周期,正好是 10us。 

SysTick 定时器的定时时间(配置为触发中断,即为中断周期),由ticks参数决定,最大定时周期不能超过 224个。以下是几种常用的中断周期配置,就是根据上面的公式计算出来的。


SystemFrequency / 1000 1ms 中断一次

SystemFrequency / 100000 10us 中断一次

SystemFrequency / 1000000 1us 中断一次 


中断服务函数: 

在main中,我们让LED工作在无限循环中,在开关之间调用了Delay_us(),一旦调用了之后,SysTick就会被开启,按照设定好的定时周期递减计数,当SysTick的计数值减到0时,就进入到中断,中断执行完后又重新计数


void Delay_us(__IO u32 nTime) 

TimingDelay = nTime;


SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //使能定时器

while(TimingDelay != 0);


使能了SysTick之后,就使用 while(TimingDelay != 0)语句等待TimingDelay变量变为 0,这个变量是在中断服务函数中被修改的。


/* 

* @brief This function handles SysTick Handler. 

* @param None 

* @retval : None 

*/ 

void SysTick_Handler(void) 

if (TimingDelay != 0x00) 

TimingDelay–; 

}


SysTick中断属于系统异常向量,在stm32f10x_it.c文件中已经默认有了它的中断服务函数SysTick_Handler(),但内容为空。所以我们要自己编写。 

每次进入 SysTick 中断就把全局变量TimingDelay自减一次。用户函数 Delay_us ()在TimingDelay被减至等于 0 时,才退出延时循环,即我们对 TimingDelay 赋的值为要中断的次数。


所以总的延时时间 T延时= T 中断周期 * TimingDelay 。


ps: 

定时器我们还可以用作计算程序执行时间: 

当我们开启 SysTick 定时器后,定时器开始工作,我们可以定义一个变量a来对中断次数进行记录,在定时器进入中断时,这个变量就a++,当我们关闭定时器后,将变量的数值乘与定时器的中断周期 就等于测量时间。特别是涉及到算法的程序,这对于优化算法是有非常大的帮助。假如你的算法的是 us 级别的,那么 SysTick 就应该设定为us 级中断,如果是 ms 级别的,就将 SysTick 设定为 ms 级中断。


关键字:STM32  SysTick  系统定时器 引用地址:STM32之SysTick(系统定时器)

上一篇:STM32之USART(串口通信)
下一篇:STM32学习笔记3——Systick

推荐阅读最新更新时间:2024-03-16 16:09

STM32固件IAP升级实战
硬件:stm32f103cbt6 软件:STM32F10x_StdPeriph_Lib_V3.5.0 1 预备知识 2 Bootloader 2.1 启动流程 2.2 校验跳转地址是否有效 2.3 Keil 工程 IAP 的相关设置 3 Application 3.1 启动流程 3.2 IAP 中的引导部分 3.3 关于 VTOR 3.4 Keil 工程设置 4 附件 1 预备知识 基于标准外设库(STM32F10x_StdPeriph_Lib_V3.5.0)的 IAP 升级相关资料可以参考 IAP ST 官方资料汇总。 STM32 升级的三种方式:IAP,ICP,ISP;具体有什么区别可以自行 Googl
[单片机]
STM32全球唯一ID读取方法
产品唯一的身份标识非常适合: ● 用来作为序列号(例如USB字符序列号或者其他的终端应用) ● 用来作为密码,在编写闪存时,将此唯一标识与软件加解密算法结合使用,提高代码在闪存存储器内的安全性。 ● 用来激活带安全机制的自举过程 96位的产品唯一身份标识所提供的参考号码对任意一个STM32微控制器,在任何情况下都是唯一的。用户在何种情况下,都不能修改这个身份标识。 这个96位的产品唯一身份标识,按照用户不同的用法,可以以字节(8位)为单位读取,也可以以半字(16位)或者全字(32位)读取。 基地址:0x1FFF F7E8 每个CPU 出厂的时候都 配置的一个ID,96 位的.这个唯一码可以利用作软件加密....... stat
[单片机]
9、STM32的PWM的原理与使用(内附代码)
1、PWM是什么? 是脉冲宽度调制,简称脉宽调制。利用微处理器数字输出对模拟电路进行控制的一种有效的技术,就是对脉冲宽度的控制。 这里说的脉冲,就是我们产生的方波。方波就是N个这样的周期连续的产生。 一个周期内高电平持续的时间就是脉冲宽度(脉宽),而PWM(脉冲宽度调制)就是控制一个周期内的高电平的持续时间。 2、简单的PWM的原理示意图 CNT:是当前值寄存器,计数寄存器。 ARR:是自动重载寄存器(初始化设定)。 CCRx:比较值寄存器(TIM_SetCompare1()设定修改占空比)。 假定定时器工作在向上计数PWM模式下: 当CNT CCRx时,引脚输出0,当CNT =CCRx时,引脚
[单片机]
9、<font color='red'>STM32</font>的PWM的原理与使用(内附代码)
stm32 spi 疑惑解疑 1
发送时 可以通过检测SPI_SR中的TXE位,当数据寄存器里有数据时,TXE位是0,当数据全部从数据寄存器的发送缓冲区传输到移位寄存器时TXE位被置1,这时候可以再往数据寄存器里写入数据。可以通过 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) 来检测。 SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE 是库函数可以检测SPI的一些状态位。 接收时 可以通过检测SPI_SR中的RXNE位,当数据寄存器里有数据时,RXNE位是0,当数据全部从数据寄存器的接收缓冲区传输到移位寄存器时RXNE位被置1,这时候可以从数
[单片机]
STM32—cubeMX+HAL库的SPI接口使用
本文主要介绍STM32的SPI接口、cubeMX软件配置SPI接口和分析SPI相关代码。 STM32之SPI简介: (1)SPI协议【Serial Peripheral Interface】 串行外围设备接口,是一种高速全双工的通信总线。主要用在MCU与FLASHADCLCD等模块之间的通信。 (2)SPI信号线 SPI 共包含 4 条总线。 SS(Slave Select):片选信号线,当有多个SPI 设备与 MCU 相连时,每个设备的这个片选信号线是与 MCU 单独的引脚相连的,而其他的 SCK、MOSI、MISO 线则为多个设备并联到相同的 SPI 总线上,低电平有效。 SCK (Serial C
[单片机]
<font color='red'>STM32</font>—cubeMX+HAL库的SPI接口使用
stm32驱动LCD
(1)头文件的编写方法 示例:// 头文件 file.h #ifndef FILE_H //FILE_H 可以随便写,只是一个标号是为了防止头文件重复定义 #define FILE_H //要和上面的这个一样, void fun(); void fun1(); void fun2(); void fun3(); .......... .......... #endif
[单片机]
STM32的四种输入方式
STM32的四种输入方式 1、上拉输入(GPIO_Mode_IPU) 上拉输入就是信号进入芯片后加了一个上拉电阻,再经过施密特触发器转换成0、1信号,读取此时的引脚电平为高电平; 2、下拉输入(GPIO_Mode_IPD) 下拉输入就是信号进入 芯片后加了一个下拉电阻,再经过施密特触发器转换成0、1信号,读取此时的引脚电平为低电平; 3、模拟输入(GPIO_Mode_AIN) 信号进入后不经过上拉电阻或者下拉电阻,关闭施密特触发器,经由另一线路把电压信号传送到片上外设模块。比如传送给ADC模块,由ADC采集电压信号。所以可以理解为模拟输入的信号是未经处理的信号,是原汁原味的信号。虽然我也知道这样表达不准确。 4、浮空输入(GPIO
[单片机]
IAR Systems发布最新开发工具 支持ST STM32系列微控制器
2007年7月31日,瑞典乌普萨拉市,IAR Systems发布最新的开发工具IAR Embedded Workbench 4.42,支持意法半导体(ST)最新的基于ARM Cortex-M3内核的STM32系列微控制器。STM32具有很好的性能,特别适用于有高性能、低功耗、低成本需求的嵌入式应用。IAR Systems公司与意法半导体紧密合作,即时发布相应的开发工具。 支持ARM Cortex-M3控制器的IAR Embedded Workbench是一个完全集成的开发环境,它包含C/C++编译器、项目管理器、编辑器、链接器以及C-SPY调试器。这款开发工具借鉴了 IAR Systems多年对ARM、Thumb 以及 Thumb
[新品]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved