SysTick定时器

今天讲解的是stm32的系统定时器——SysTick定时器。

一、SysTick定时器简介

《Cortex-M3权威指南》中对SysTick的描述,SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。它是一个24位的递减定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。大多数操作系统需要一个硬件定时器来产生滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有提供各种定时功能,都与滴答定时器有关。因此,需要一个定时器产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统的“心跳”的节奏。该定时器的时钟源可以是内部时钟(FCLK),或者是外部时钟(CM3处理器上的STCLK信号)。SysTick定时器能产生中断,异常中断。使用内核的SysTick定时器来实现延时,可以不占用系统定时器,由于和MCU外设无关,所以代码的移植,在不同厂家的Cortex-M内核MCU之间,可以很方便的实现。

二、SysTick相关寄存器介绍

SysTick一共有4个寄存器,在core_cm3.h这个头文件里定义了以这4个寄存器为成员的结构体指针。

typedef struct
{
  __IO uint32_t CTRL;                         /*!< Offset: 0x00  SysTick Control and Status Register */
  __IO uint32_t LOAD;                         /*!< Offset: 0x04  SysTick Reload Value Register       */
  __IO uint32_t VAL;                          /*!< Offset: 0x08  SysTick Current Value Register      */
  __I  uint32_t CALIB;                        /*!< Offset: 0x0C  SysTick Calibration Register        */
} SysTick_Type;

各个寄存器功能如下

1、SysTick控制及状态寄存器

2、SysTick重装载数值寄存器

3、SysTick当前数值寄存器

4、SysTick校准数值寄存器

通常只需要用到前3个寄存器,第四个寄存器在定时实验中不需要用到,有关各个位的描述在英文文档里比较晦涩难懂,这个寄存器的用途有待研究。

了解了它的定时器作用之后,接下来是如何通过编程得到准确的延时。

三、SysTick定时器配置步骤

SysTick定时器的操作可以分为 4 步:

(1)设置SysTick定时器的时钟源。

(2)设置SysTick定时器的重装初始值(如果要使用中断的话,就将中断使能打开)。

(3)清零SysTick定时器当前计数器的值。

(4)打开SysTick定时器。

代码实现

void SysTick_Init(u8 SYSCLK)
{
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //9M
    fac_us=SYSCLK/8;                    
    fac_ms=(u16)fac_us*1000;                   
}                
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;                          //清空计数器     
}            
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;                         //清空计数器         
}     

上面有几个地方需要注意

①SysTick的时钟来源可以是AHB时钟或者是AHB时钟除以8。具体可以参照stm32固件库说明。

②在访问结构体成员时,(.)和(->)的区别。访问结构成员的运算符有两种,一种是结构成员运算符“·”,也称为“圆点运算符”,另一种是结构指针运算符“->”,也称“箭头运算符”。

点是用于结构体变量访问成员,箭头是用于结构体指针访问成员。

补充说明:圆点运算符是比较古老的写法,不能访问结构体指针变量成员,现在都推荐使用箭头运算符,即(->)。

③计数值的计算

计数值=计数总时间/每次计数所需时间。

每次计数所需时间=1/SYSCLK。

所以

计数值=计数总时间*SYSCLK。

同时还要注意单位的统一性。比如假设需要计时的时间为500us,定时器时钟源为系统时钟72MHz,那么计数值为500*72。

当定时单位为ms时,与kHz相乘才能将单位消掉,因此,假设定时500ms,定时器时钟源为9MHz,那么计数值为500*9*1000。

这就是为什么上面定义fac_ms=fac_us*1000的原因。

编写好上面两个延时函数之后就可以方便的调用了。调用时要注意不能超过它的最大值。

比如调用void delay_us(u32 nus),假设时钟源选用72MHz,

那么nus的最大值为0xFFFFFF/72=233016us。

比如调用void delay_ms(u32 nms),假设时钟源选用9MHz,

那么mus的最大值为0xFFFFFF/9000=1864ms。

总结:

SysTick定时器主要是要知道如何通过它得到准确定时,并且编写延时函数,另外也可以在定时结束时产生的中断里面编写中断响应函数。配置上也比较简单,基本上就是配置时钟来源,装载计数值。

另外,在一些编译器里,有时不能调用库函数SysTick_SetReload(),大概是因为官方库函数在不断更新,需要下载更高版本的库函数。在上面的程序中,直接操作了结构体,所以没有这个问题。

有了精确延时函数,那么使用通用GPIO软件模拟一些通信协议,如IIC、SPI等串行协议,就可以驱动很多硬件设备了,如EEPROM、温湿度传感器、显示屏等等。

*部分资料来源于网络,如有侵权请联系删除

本文分享自微信公众号 - 电子技术研习社(zjf18770701843),作者:小小飞飞哥

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • HC05蓝牙模块通信(附源码)

    实现的目标是利用蓝牙模块,实现手机与单片机通信,在手机上点击按钮,点亮单片机上面的小灯。

    飞哥
  • C++ | 面向对象之“封装”简述

    众所周知,C++是一门面向对象的语言,相对于面向过程的C语言,面向对象有时候有自己的优势,今天就讲一下面向对象的三大特性之一——封装。

    飞哥
  • 单片机通信之串口通信

    单片机常用的通信方式有串口通信,I2C,SPI,UART等等,在这里说一下基于8051单片机串口通信的基本原理。简要介绍单片机与PC机之间的通信。

    飞哥
  • 使用系统定时器SysTick实现精确延时微秒和毫秒函数

    SysTick定时器是存在于系统内核的一个滴答定时器,只要是ARM Cortex-M0/M3/M4/M7内核的MCU都包含这个定时器,它是一个24位的递减定时器...

    单片机点灯小能手
  • 程序员50+Java面试题

    大家好!最近,我一直在分享很多Java面试问题和讨论,我的许多读者都要求将它们组合在一起,以便他们可以将它们放在同一页面中并做好准备,这篇文章就是整理的结果。

    银河1号
  • ARM coretex M4 系统定时器

    系统定时器SysTick简介 今天我们来讲讲ARM cortex M4核系统定时器system Timer,处理器核有一个24位的系统定时器SysTick,可以...

    用户1605515
  • 对 Dbshop 的一次代码审计过程

    从官网介绍得知,dbshop 是一个基于 ZendFramework 2 开发的。很是蛋疼,这个框架,没用过,草草的找了 本文档边看边审计:

    信安之路
  • mobi电子书中删除多余的空格

      过年放假,还是在宅家里看书,结果发现,有些电子书网上整理的并不好,有很多没有用的空格,十分影响阅读效率,于是打算看看能不能解决一下。步骤也很简单,首先下载一...

    钱塘小甲子
  • 错误笔记-----今天在敲代码的时候,出现了一个问题!

     if(x!=Father(x))         //这条代码-----其实我定义的是个数组,然而我却用错了括号【】我用了(), //D:\Microsoft...

    Gxjun
  • MEC – 我们越来越近了吗?!

    多接入边缘计算(MEC)或之前的移动边缘计算在过去几年中一直是很流行的术语,尤其是去年5G技术进入了商业阶段。MEC通常用于描述将服务推向网络边缘的概念,与雾计...

    SDNLAB

扫码关注云+社区

领取腾讯云代金券