STM32-Project19:SysTick系统定时器外设介绍;用软件查询实现定时实验;

一 SysTick 简介 

     SysTick —系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器
是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK ,一般我们设置
系统时钟 SYSCLK 等于 72M 。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产
生一次中断,以此循环往复。
SysTick 寄存器介绍
SysTick —系统定时器有 4 个寄存器,简要介绍如下。在使用 SysTick 产生定时的时候,
只需要配置前三个寄存器,最后一个校准寄存器不需要使用。
CTRL    SysTick 控制及状态寄存器
LOAD    SysTick 重装载数值寄存器
VAL       SysTick 当前数值寄存器
CALIB   SysTick 校准数值寄存器

 

 

 

SysTick 属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件
core_cm3.h 中。
SysTick 配置库函数
1 __STATIC_INLINE uint32_t SysTick_Config( uint32_t ticks)
2 {
3 // 不可能的重装载值,超出范围
4 if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) {
5 return (1UL);
6 }
7
8 // 设置重装载寄存器
9 SysTick->LOAD = ( uint32_t )(ticks - 1UL);
10
11 // 设置中断优先级
12 NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
13
14 // 设置当前数值寄存器
15 SysTick->VAL = 0UL;
16
17 // 设置系统定时器的时钟源为 AHBCLK=72M
18 // 使能系统定时器中断
19 // 使能定时器
20 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
21 SysTick_CTRL_TICKINT_Msk |
22 SysTick_CTRL_ENABLE_Msk;
23 return (0UL);
24 }
用固件库编程的时候我们只需要调用库函数 SysTick_Config() 即可,形参 ticks 用来设
置重装载寄存器的值,最大不能超过重装载寄存器的值 ,当重装载寄存器的值递减到 0
的时候产生中断,然后重装载寄存器的值又重新装载往下递减计数,以此循环往复。紧随
其后设置好中断优先级,最后配置系统定时器的时钟等于 AHBCLK=72M ,使能定时器和
定时器中断,这样系统定时器就配置好了,一个库函数搞定。
SysTick_Config() 库函数主要配置了 SysTick 中的三个寄存器: LOAD VAL CTRL
其中
SysTick_Config() 库函数还调用了固件库函数 NVIC_SetPriority() 来配置系统定时器
的中断优先级,该库函数也在 core_m3.h 中定义,原型如下:
1 __STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
2 {
3 if (( int32_t )IRQn < 0) {
4 SCB->SHP[((( uint32_t )( int32_t )IRQn) & 0xFUL)-4UL] =
5 ( uint8_t )((priority << (8 - __NVIC_PRIO_BITS)) & ( uint32_t )0xFFUL);
6 } else {
7 NVIC->IP[(( uint32_t )( int32_t )IRQn)] =
8 ( uint8_t )((priority << (8 - __NVIC_PRIO_BITS)) & ( uint32_t )0xFFUL);
9 }
10 }
函数首先先判断形参 IRQn 的大小,如果是小于 0 ,则表示这个是系统异常,系统异常
的优先级由内核外设 SCB 的寄存器 SHPRx 控制,如果大于 0 则是外部中断,外部中断的
优先级由内核外设 NVIC 中的 IPx 寄存器控制。
因为 SysTick 属于内核外设,跟普通外设的中断优先级有些区别,并没有抢占优先级
和子优先级的说法。在 STM32F103 中,内核外设的中断优先级由内核 SCB 这个外设的寄
存器: SHPRx x=1.2.3 )来配置。有关 SHPRx 寄存器的详细描述可参考《 Cortex-M3 内核
编程手册》 4.4.8 章节。下面我们简单介绍下这个寄存器。
SPRH1-SPRH3 是一个 32 位的寄存器,但是只能通过字节访问,每 8 个字段控制着一
个内核外设的中断优先级的配置。在 STM32F103 中,只有位 7:3 这高四位有效,低四位没
有用到,所以内核外设的中断优先级可编程为: 0~15 ,只有 16 个可编程优先级,数值越小,
优先级越高。如果软件优先级配置相同,那就根据他们在中断向量表里面的位置编号来决
定优先级大小,编号越小,优先级越高。

 

在系统定时器中,配置优先级为 (1UL << __NVIC_PRIO_BITS) - 1UL) ,其中宏
__NVIC_PRIO_BITS 4 ,那计算结果就等于 15 ,可以看出系统定时器此时设置的优先级
在内核外设中是最低的,如果要修改优先级则修改这个值即可,范围为: 0~15
1 // 设置系统定时器中断优先级
2 NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
但是,问题来了,刚刚我们只是学习了内核的外设的优先级配置。如果我同时使用了
systick 和片上外设呢?而且片上外设也刚好需要使用中断,那 systick 的中断优先级跟外设
的中断优先级怎么设置?会不会因为 systick 是内核里面的外设,所以它的中断优先级就一
定比内核之外的外设的优先级高?
从《 STM32 中断应用概览》这章我们知道,外设在设置中断优先级的时候,首先要分
组,然后设置抢占优先级和子优先级。而 systick 这类内核的外设在配置的时候,只需要配
置一个寄存器即可,取值范围为 0~15 。既然配置方法不同,那如何区分两者的优先级?下
面举例说明。
比如配置一个外设的中断优先级分组为 2 ,抢占优先级为 1 ,子优先级也为 1 systick
的优先级为固件库默认配置的 15 。当我们比较内核外设和片上外设的中断优先级的时候,
我们只需要抓住 NVIC 的中断优先级分组不仅对片上外设有效,同样对内核的外设也有效。
我们把 systick 的优先级 15 转换成二进制值就是 1111(0b) ,又因为 NVIC 的优先级分组 2
那么前两位的 11(0b) 就是 3 ,后两位的 11(0b) 也是 3 。无论从抢占还是子优先级都比我们设
定的外设的优先级低。如果当两个的软件优先级都配置成一样,那么就比较他们在中断向
量表中的硬件编号,编号越小,优先级越高。

二 编程实现

一种更简洁的定时编程
如果我们是使用了中断,而且经过多个函数的调用,还使用了全局变量,理
解起来挺费劲的,其实还有另外一种更简洁的写法。我们知道, systick counter reload
值往下递减到 0 的时候, CTRL 寄存器的位 16:countflag 会置 1 ,且读取该位的值可清 0
所有我们可以使用软件查询的方法来实现延时。
#include "systick.h"

//通过查询标志位来完成定时功能,没有采用中断
void Systick_Delay_us(uint32_t us){
	 uint32_t i = 0;
	 SysTick_Config(72);//重载值72,1us计数到72
	 for(i = 0;i<us;i++){
		 // 当计数器的值减小到 0 的时候,CRTL 寄存器的位 16 会置 1 同时清零操作
	 while(!((SysTick->CTRL) & (1<<16)));//计数满标志位
	 }		 
	 SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;//定时器使能位:让失能  SysTick_CTRL_ENABLE_Msk == 1<<0
}

void Systick_Delay_ms(uint32_t ms){
	 uint32_t i = 0;
	 SysTick_Config(72000);
	 for(i = 0;i<ms;i++){
	 while(!((SysTick->CTRL) & (1<<16)));
	 }		 
	 SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
#include "stm32f10x.h"  
#include "led.h" 
#include "key.h"
#include "rcc.h"
#include "exti.h"
#include "systick.h"

//systick系统定时器定时1s,灯反转一次。

void delay(uint32_t count){
	for(;count!=0;count--);
}


int main(void)
{
	 LED0_GPIO_Config();
	
	while (1){
	  Systick_Delay_ms(1000);
		LED0_TOGGLE;
	}
	
}



在这两个微秒和毫秒级别的延时函数中,我们还是调用了 SysTick_Config 这个固件库
函 数 , 有 关 这 个 函 数 的 说 明 具 体 见 代 码
// 这个 固件库函数 在 core_cm3.h
2 static __INLINE uint32_t SysTick_Config( uint32_t ticks)
3 {
4 // reload 寄存器为 24bit ,最大值为 2^24
5 if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
6
7 // 配置 reload 寄存器的初始值
8 SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
9
10 // 配置中断优先级为 1<<4 -1 = 15 ,优先级为最低
11 NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
12
13 // 配置 counter 计数器的值
14 SysTick->VAL = 0;
15
16 // 配置 systick 的时钟为 72M
17 // 使能中断
18 // 使能 systick
19 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
20 SysTick_CTRL_TICKINT_Msk |
21 SysTick_CTRL_ENABLE_Msk;
22 return (0);
23 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dpq666dpq666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值