STM32——系统滴答定时器(SysTick寄存器详解)

文章目录

1.SysTick简介

Cortex-M处理器内集成了一个小型的名为SysTick(系统节拍)的定时器,它属于NVIC的一部分,且可以产生 SysTick异常(异常类型#15)。SysTick为简单的向下计数的24位计数器,可以使用处理器时钟或外部参考时钟(通常是片上时钟源)。

2.工作原理

SysTick定时器的工作原理非常简单。它有一个内置的计数器,计数器从一个初始值开始递减,当计数器的值达到零时,它会触发一个中断并重新加载初始值。SysTick定时器一般会与系统时钟频率(通常是CPU时钟)同步工作,可以用来创建精确的时间延迟。

主要特性
定时器计数 :SysTick定时器的计数器在每个时钟周期递减,直到它的值为零时会触发一个中断。
中断功能 :当计数器到达零时,SysTick会触发一个中断,通常用于处理系统的定时任务(如操作系统的时钟中断)。
自动重载 :SysTick有一个自动重载功能,计数器会从预定的值重新加载并继续计数。
可配置的时钟源:SysTick可以选择不同的时钟源,通常选择处理器的系统时钟,或者是外部的低速时钟源

3.SysTick寄存器

4.代码延时逻辑

  1. 选择时钟源

    根据CTRL寄存器的第2位和第0位,来选择时钟源和是否使能定时器
    其中位0的意思是:位0=0 失能 关闭定时器
    位0=1 使能 开启定时器
c 复制代码
SysTuck->CTRL&=(1<<2);//第二位为1.选择高速内部时钟
  1. 关闭计数器
c 复制代码
SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器
  1. delay_us(num)

    定时器计数为0时候,重装载值为倍乘数系统时钟,我这里用的F4,系统分频的是21Mhz,那么应该是21 1/21Mhz,
    周期=1/频率=1/168000000约等于0.00592us;这是系统时钟的周期,
    最大延时取决于分频的频率
    分频的频率为21Mhz,1个周期的时间为1/21000000s,大概为1/21us,所以倍乘数应该是21.

    写入任何值将清零当前数值
c 复制代码
SysTick->LOAD=num*value_us;//设置重装在制,其中num是系统时钟的频率,value_us是倍乘数,若num=42Mhz,则value_us=421,21Mhz,value_us=21,8M则value_us=8,原因看标签5的解释
SysTick->VAL=0;//计数器当前值清零
SysTuck->CTRL|=(1<<0);//第0 位为0,关闭定时器
  1. 等待计数完毕
    判断CTRL寄存器的第16位是否为1--》计数到0
    CTRL=1 &(1<<16)=1 while (!1)
    CTRL=0 &(1<<16)=0 while(!0)
c 复制代码
while(!(SysTick->CTRL(&1<<16)))
  1. 清空当前值
c 复制代码
SysTick->VAL=0;
  1. 关闭计数器
c 复制代码
SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器

5.附上整体代码

c 复制代码
//仿原子延时,不进入systic中断
void delay_us(u32 nus)
{
 u32 temp;
 SysTick->LOAD = 21*nus;
 SysTick->VAL=0;//计数器当前值清零
 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
 do
 {
  temp=SysTick->CTRL;//读取当前倒计数值
 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达while(!(SysTick->CTRL(&1<<16)))
     SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器
     SysTick->VAL=0;//计数器当前值清零
}
void delay_ms(u16 nms)
{
 u32 temp;
 SysTick->LOAD = 21000*nms;
 SysTick->VAL=0;//计数器当前值清零
 SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器
 do
 {
  temp=SysTick->CTRL;//读取当前倒计数值
 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
   SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器
   SysTick->VAL=0;//计数器当前值清零
}

借鉴链接https://blog.csdn.net/weibo1230123/article/details/81136564?spm=1001.2014.3001.5506

以及还有一个之前的找不到了。。。

6.一些重要解释

  1. 为什么频率是21M时候,value_us=21,才是1us

    因为当时钟源选择21M的时候,1s时间计数为21M次

    T=1/f(时间是频率的倒数)

    当21M时,计数1次所产生的时间为1/21000000s,是1/21000ms,1/21us,所以*21是1us

  2. 最大延时

    当最大延时为21M时,24位计数器最大值为16777215

    16777215/21=798915us=798.915ms。

由上两点可以计算出若外部时钟源选择是8M时,则value_us=8,valua_ms=8000,最大延时为167.77215/8=2097152us=2097.152ms

  1. HAL_Init()会提前配置好HAL_delay的参数
    ①FLASH读取指令缓存、数据缓存
    ②设置中断组优先级
    ③设置SysTick作为基准时间源、配置1ms tick,复位后默认时钟源为HSI(内部高速时钟源)
    ④初始化底层硬件
    附上原始HAL_Init()函数源码,可看可不看
c 复制代码
HAL_StatusTypeDef HAL_Init(void)
{
  /* Configure Flash prefetch, Instruction cache, Data cache */ 
#if (INSTRUCTION_CACHE_ENABLE != 0)
   __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
#endif /* INSTRUCTION_CACHE_ENABLE */

#if (DATA_CACHE_ENABLE != 0)
   __HAL_FLASH_DATA_CACHE_ENABLE();
#endif /* DATA_CACHE_ENABLE */

#if (PREFETCH_ENABLE != 0)
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//中断优先级分组4

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  HAL_InitTick(TICK_INT_PRIORITY);
  
  /* Init the low level hardware */
  HAL_MspInit();
  
  /* Return function status */
  return HAL_OK;
}

以上资料部分来自于《清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 (Joseph Yiu、吴常玉、曹孟娟、王丽红。) (Z-Library)》

书籍已上传到博客

相关推荐
楼台的春风3 分钟前
【MCU驱动开发概述】
c语言·驱动开发·单片机·嵌入式硬件·mcu·自动驾驶·嵌入式
Moonnnn.7 分钟前
51单片机学习——动态数码管显示
笔记·嵌入式硬件·学习·51单片机
LS_learner1 小时前
小智机器人CMakeLists编译文件解析
嵌入式硬件·机器人
小鸡岛保安2 小时前
学习笔记-8MQTT-韦东山
stm32·物联网
暗碳2 小时前
stm32 74hc238流水灯
stm32·单片机·嵌入式硬件
1101 11013 小时前
STM32-温湿度上传OneNET项目
stm32·单片机·嵌入式硬件
余衫马3 小时前
ESP32-S3 实战指南:BOOT-KEY 按键驱动开发全解析
驱动开发·单片机·嵌入式硬件
文军的烹饪实验室6 小时前
处理器架构、单片机、芯片、光刻机之间的关系
单片机·嵌入式硬件·架构
Leiditech__7 小时前
人工智能时代电子机器人静电问题及电路设计防范措施
人工智能·嵌入式硬件·机器人·硬件工程
jmlinux7 小时前
STM32 HAL库USART串口DMA IDLE中断编程:避坑指南
stm32·单片机·嵌入式硬件