三、精准计时:滴答定时器探秘与应用

文章目录

  1. 滴答定时器简介

    • 滴答定时器(SysTick)是Cortex - M4内核中的一个24位的倒计数定时器。它的主要作用是为操作系统或其他需要定时功能的应用提供一个简单的定时基准。它具有以下特点:
      • 简单易用,集成在处理器内核中,不需要额外的外部硬件。
      • 可以产生周期性的中断,方便用于任务调度等操作。
      • 其时钟源可以是处理器的内部时钟或者外部时钟,通过配置可以灵活选择。
  2. 滴答定时器寄存器

    • 控制和状态寄存器(SysTick_CTRL)
      • 位0(ENABLE):用于使能或禁用SysTick定时器。当该位为1时,定时器开始计数;为0时,定时器停止计数。
      • 位1(TICKINT):用于使能SysTick定时器中断。当该位为1时,定时器计数到0时会产生中断请求;为0时,不会产生中断。
      • 位2(CLKSOURCE):用于选择时钟源。为0时,选择外部时钟源(一般是处理器的AHB时钟除以8);为1时,选择处理器的核心时钟。
      • 位16(COUNTFLAG):这是一个状态位,当定时器计数到0时,该位会被置1,读取该位后会自动清零。
    • 重装载值寄存器(SysTick_LOAD):这是一个24位的寄存器,用于设置定时器的初始计数值。当定时器启动后,会从这个设置的值开始向下计数。例如,如果要设置定时器每1000个时钟周期产生一次中断(假设时钟频率为1kHz,即1ms的定时周期),则可以将此寄存器的值设置为999(因为是从设置的值开始计数,到0结束,总共是1000个周期)。
    • 当前值寄存器(SysTick_VAL):这是一个24位的寄存器,用于读取当前定时器的计数值。在定时器运行过程中,可以通过读取这个寄存器来获取定时器的当前状态。不过,读取这个寄存器可能会影响定时器的正常计数,因为它是一个硬件计数器。
  3. 滴答定时器函数(以GD32F450ZG标准库为例)

    • 通常会有初始化函数来设置定时器的参数,如SysTick_Config()函数。这个函数会自动完成SysTick定时器的基本配置,包括设置重装载值、选择时钟源、使能定时器和中断等。其函数原型大概如下:
    c 复制代码
    static __INLINE uint32_t SysTick_Config(uint32_t ticks)
    {
        if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
        SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
        NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
        SysTick->VAL   = 0; /* Load the SysTick Counter Value */
        SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                         SysTick_CTRL_TICKINT_Msk   |
                         SysTick_CTRL_ENABLE_Msk;   /* Enable SysTick IRQ and SysTick Timer */
        return (0); /* Function successful */
    }
    • 中断服务函数,当SysTick定时器计数到0并且使能了中断时,会进入中断服务函数。用户需要在中断服务函数中编写自己的定时任务代码。在GD32F450ZG中,中断服务函数的名称通常是SysTick_Handler()
  4. 配置滴答定时器

    • 步骤如下:

      • 首先确定定时周期。假设系统时钟频率为SystemCoreClock,要实现1s的定时周期,需要计算出SysTick定时器的重装载值。如果选择内部时钟源(即SysTick_CTRL_CLKSOURCE_Msk位为1),计算公式为:重装载值=(SystemCoreClock/1000)-1(这里假设要实现1ms的定时周期,1s需要1000个这样的周期)。
      • 然后调用SysTick_Config()函数来配置定时器。例如:
      c 复制代码
      #define TICK_PER_SECOND 1000
      uint32_t sysTickCounter = 0;
      void SysTick_Configuration(void)
      {
          if (SysTick_Config(SystemCoreClock/TICK_PER_SECOND - 1))
          {
              // 配置出错处理
              while (1);
          }
      }
  5. 使用滴答定时器

    • GD32 官方也给我们写好了延时 1ms 的函数,void delay_1ms(uint32_t count),有一个参数 count,这个就是我们要延时的时间的 ms 数,延时 1ms 就是 delay_1ms(1),延时 1s 就是 delay_1ms(1000)。需要注意的是这个延时是阻塞延时,在延时的时间里一直在等待,比较浪费系统资源,慎用。
c 复制代码
/*
  \brief    delay a time in milliseconds
  \param[in]  count: count in milliseconds
  \param[out] none
  \retval     none
*/
void delay_1ms(uint32_t count)
{
  delay = count;

  while(0U != delay) {
  }
}
  1. 完整的实验代码示例(包含必要的头文件和初始化部分)
    • 首先包含必要的头文件:
c 复制代码
#include "gd32f4xx.h"
#include "systick.h"
#include "gd32f4xx_gpio.h"
#include "gd32f4xx_rcu.h"
  • 然后进行GPIO和SysTick的初始化:
c 复制代码
void GPIO_Configuration(void)
{
    rcu_periph_clock_enable(RCU_GPIOD);
    gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
}

int main(void)
{
    GPIO_Configuration();
    SysTick_Config();
    while (1)
    {
 gpio_bit_toggle(LED2,GPIO_PIN_7);
 delay_1ms(1000);//间隔1s
    }
}

上述代码初始化了PD7引脚为输出模式,在main函数中,通过一个无限循环来等待定时器中断的发生并执行相应的操作。注意,实际应用中可能需要根据具体的开发环境和芯片库版本进行适当的调整。

相关推荐
电子元器件选型哥27 分钟前
一文讲清LLC谐振电路工作原理
单片机·嵌入式硬件·硬件工程师·电子元器件·器件选型
HUI-4741 小时前
EG1162|SOP‑16 高压同步整流降压控制器,最高 600V 输入,大电流 5V 输出优选
嵌入式硬件·硬件工程
POMAGTOR1 小时前
【5G 通讯 POGOPIN 弹簧顶针连接器解决方案】
网络·嵌入式硬件·5g
ZLG_zhiyuan2 小时前
测试方案 | 从“000”到“111”,高效完成100BASE-TX以太网眼图测试
单片机·嵌入式硬件
恒锐丰科技林技术员2 小时前
EG1198:120V 宽压内置 MOS 降压 DC‑DC 电源芯片解析
经验分享·嵌入式硬件·硬件工程
数字新视界3 小时前
能耗管理系统的综合方案与优化实战解析
嵌入式硬件·物联网·数据中心·数据中心基础设施管理·dcim管理系统
深圳市恒锐丰科技杨生3 小时前
EG3525S 推挽 / 半桥 PWM 控制器|屹晶 EGmicro
嵌入式硬件·硬件工程
H_oRIZoN_3 小时前
Linux入门DAY39(51 单片机入门笔记|最小系统、位运算、处理器、数码管基础梳理)
单片机·嵌入式硬件
12.=0.3 小时前
【电学基础】
单片机·嵌入式硬件
开发笔记-阿牛3 小时前
嵌入式蓝牙开发:AC2005B 芯片技术解析 —— 省晶振设计、13dBm 射频与 Auracast 广播音响开发指南
人工智能·单片机·音视频