STM32 寄存器操作 systick 滴答定时器 与中断

一、什么是 SysTick

SysTick---系统定时器是属于CM3内核中的一个外设,内嵌在NVIC中。系统定时器是一个24bit的向下递减的计数器, 计数器每计数一次的时间为1/SYSCLK,一般我们设置系统时钟SYSCLK等于72M。当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。

因为SysTick是属于CM3内核的外设,所以所有基于CM3内核的单片机都具有这个系统定时器,使得软件在CM3单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。

当然更常用的还是在裸机环境下作为延迟函数使用,本篇不介绍rtos相关的 SysTick 使用。

二、SysTick 寄存器描述

SysTick->CTRL, --控制和状态寄存器

SysTick->LOAD, --重装载寄存器

SysTick->VAL, --当前值寄存器

SysTick->CALIB, --校准值寄存器 (不常用 不做介绍)

2.1 SysTick->CTRL

2.2 SysTick->LOAD

2.3 SysTick->VAL

2.4 SysTick->CALIB

三、如何使用滴答定时器?

3.1 初始化滴答定时器

通过设置 SysTick->CTRL 的第二位寄存器,我们可以配置滴答定时器使用外部时钟 (STCLK) 或者是 Cortex 内核时钟 (FCLK)。

所谓 Cortex 内核时钟就是如下图所示,AHB 八分频后的时钟。

在此我们配置为使用 Cortex 内核时钟,对 CTRL 第二位置 1 即可。

cpp 复制代码
SysTick->CTRL&=~(1<<2);    //使用 Cortex 内核时钟

SystemCoreClock 是定义了系统时钟 (SYSCLK)频率的宏,即等于AHB 的时钟频率。笔者使用的是STM32F103x系列mcu,SystemCoreClock 被系统库配置成 72Mhz。

因为我们使了 Cortex 内核时钟。所以同样需要除 8 来当作八分频使用。

下面的代码则代表每1秒钟,SysTick会有 72000000/8= 9000000 次的计数周期。

cpp 复制代码
fac_s = SystemCoreClock/8;      //为系统时钟的1/8 代表每个s完成的systick时钟数

之后我们依次配置每秒,每毫秒,每微秒的滴答定时器周期。

cpp 复制代码
//1s=1000ms=1000000=us
static u32 fac_s=0;     //一秒的滴答定时器计数周期数量
static u32 fac_ms=0;    //一毫秒的滴答定时器计数周期数量
static u32 fac_us=0;    //一微秒的滴答定时器计数周期数量

void delay_init(){
    SysTick->CTRL&=~(1<<2);         //使用 Cortex 内核时钟
	fac_s = SystemCoreClock/8;      //为系统时钟的1/8 代表每个s完成的systick时钟数
	fac_ms = fac_s/1000;            //代表每个ms完成的systick时钟数
    fac_us = fac_ms/1000;           //代表每个us完成的systick时钟数
}

3.2 实现 delay_us() 函数

细看注释配合之前的寄存器描述即可看懂。

cpp 复制代码
void delay_us(u32 nus)
{
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 					//时间加载	  		 
	SysTick->VAL=0x00;        					//清空计数器
	SysTick->CTRL|=1 ;	    //使能计数器  ENABLE位置1
	do
	{
		temp=SysTick->CTRL;
    //检查CTRL的ENABLE位和COUNTFLAG位
    //如果ENABLE位为0或者COUNTFLAG位为1则判断为计数结束 等待时间到达   
	}while((temp&0x01)&&!(temp&(1<<16)));
	SysTick->CTRL&=~1;	    //关闭计数器     ENABLE位置0
	SysTick->VAL =0X00;     //清空计数器	 
}

三、使用 SysTick 的中断

根据 SysTick->CTRL 寄存器表的提示,我们只需要把第一位置高即可开启 SysTick 异常中断。

3.1 使用库函数

在这里我们不再从头写寄存器,而是使用core_cm3.h 的库函数,并且解析其中的原理。

cpp 复制代码
#include "stm32f10x.h"

int main(void)
{	

    if (SysTick_Config(SystemCoreClock / 1000))	// ST3.5.0库版本
	{
		while (1);
	}

	for(;;)
	{
        __NOP();
	}
}


void SysTick_Handler(void)
{
    //每1ms中断一次
}

在下列代码中,我们的程序可以每隔 1ms 调用一次滴答定时器回调函数。

3.2 源码解析

cpp 复制代码
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* 值超过0xFFFFFF直接退出 */
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* 设置重载寄存器 与运算防止越界 */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* 设置Cortex-M0系统中断的优先级 */
  SysTick->VAL   = 0;                                          /* 加载SysTick计数器值 */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* 使能 SysTick IRQ 和 SysTick Timer */
  return (0);                                                  /* 函数成功 */
}

方便阅读代码,我将下边的几个宏定义也粘贴过来:

cpp 复制代码
#define SysTick_CTRL_CLKSOURCE_Pos          2                                             /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk         (1ul << SysTick_CTRL_CLKSOURCE_Pos)            /*!< SysTick CTRL: CLKSOURCE Mask */

#define SysTick_CTRL_TICKINT_Pos            1                                             /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk           (1ul << SysTick_CTRL_TICKINT_Pos)              /*!< SysTick CTRL: TICKINT Mask */

#define SysTick_CTRL_ENABLE_Pos             0                                             /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk            (1ul << SysTick_CTRL_ENABLE_Pos)               /*!< SysTick CTRL: ENABLE Mask */

/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos             0                                             /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos)        /*!< SysTick LOAD: RELOAD Mask */
相关推荐
小A1592 分钟前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
Rorsion7 分钟前
各种电机原理介绍
单片机·嵌入式硬件
善 .3 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件
超级码农ProMax3 小时前
STM32——“SPI Flash”
stm32·单片机·嵌入式硬件
Asa3194 小时前
stm32点灯Hal库
stm32·单片机·嵌入式硬件
end_SJ5 小时前
初学stm32 --- 外部中断
stm32·单片机·嵌入式硬件
gantengsheng6 小时前
基于51单片机和OLED12864的小游戏《贪吃蛇》
单片机·嵌入式硬件·游戏·51单片机
嵌入式小强工作室7 小时前
stm32 查找进硬件错误方法
stm32·单片机·嵌入式硬件
委员8 小时前
基于NodeMCU的物联网窗帘控制系统设计
单片机·mcu·物联网·智能家居·iot
wenchm8 小时前
细说STM32F407单片机DMA方式读写SPI FLASH W25Q16BV
stm32·单片机·嵌入式硬件