• STM32F4之系统滴答定时器


    一、系统滴答定时器概述

    传统定时器:如手机闹钟,闹钟等就是一个简单地计数器

    定时器概念:由时钟源+计数器+计数值组成的计数单元。

    系统嘀嗒定时器首先是存在于内核里,系统嘀嗒时钟假如用的是同一个内核那么里面相关的配置,可能不同的就是主频。

    定时器概述

    平时数数的时候,每次数的时间不一致

    定时器:可以帮助我们进行有规律的计数

    可以知道每数一次的时间都是固定的

    定时器的本质 = 数一次的时间 * 数多少次

    系统滴答定时器的概述

    SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。

    例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问,以维持操作系统“心跳”的节律。

    后面用到操作系统的时候就可以使用系统嘀嗒作为时基单元(5ms)

    SysTick(系统滴答)器原理:SysTick本质就是一个定时器。每来一个时钟脉冲计数一次,从规定数值递减到零时,表示定时时间到。

    SysTick作用

    1为搭载操作系统的芯片提供心跳节拍:由于芯片搭载操作系统便于维护程序,很多产品都会搭载操作系统,操作系统需要一个心跳节拍。

    2如果是裸机使用系统滴答定时器时,可以将系统滴答定时器当做普通定时器使用。

    二、系统滴答定时器框架

    因为SysTick是属于内核的一部分,被捆绑在NVIC中,用于产生SYSTICK异常。

    滴答定时器介绍:

    SysTick 定时器是一个简单的递减 24 位定时器,可以在处理器时钟频率或参考时钟频率上运行

    (1)递减:定时器的计数器是向下递减的。1000-》0

    (2) 定时器是24位:计数器的计数范围。

    (3) 定时器时钟来源:处理器时钟频率(168MHZ)或参考时钟频率(168/8 =21MHZ)

    有上图得知滴答定时器是作为内核中NVIC的一部分的一部分,

    定时时间计算问题:

    • 24位递减计数器最大值224 = 16777216  = 798,915us
    • 选择21M参考时钟AHB经过8分频得到 最大计数时间ms = 16777216/21*000(1毫秒计数个数) = 799ms

    三、系统滴答定时器相关寄存器

    SysTick的控制与状态寄存器

    SysTick重载值寄存器

    SysTick当前值寄存器

     SysTick校准值寄存器

    该寄存器用于校准滴答定时器,所以必须要有一个参考时钟,写入TENMS中。

    注意点:如果使用参考时钟,必须写入一校准值(厂家在芯片出场的时候已经写入);

    作为查询方式的配置步骤:(作为延时函数)

    属于内核的没有时钟使能

    1. 选择时钟源
    2. 清空递减计数值
    3. 写入重载值
    4. 开启递减计数器
    5. 等待标志位
    6. 关闭递减计数器

    作为中断(搭载操作系统)的配置流程

    Void SysTick_IRQ_Init(void)

    {

      ①时钟源选择

      ②配置自动重装载寄存器 

      ③清除当前计数器的值

      ④使能中断(模块级中断打开就行,核心机中断不用,SYStickz在内核里面不用使能,NVIC必须响应)

      ⑤设置中断优先级

      ⑥打开定时器

    }

    1. u32 fac_us = 0;
    2. u32 fac_ms = 0;
    3. //#ifdef SYSINter
    4. /************************************
    5. 函数功能:系统嘀嗒定时器初始化
    6. 函数形参:u32 nms
    7. 函数返回值:void
    8. 函数说明:
    9. 选择21M的时钟源
    10. 总的计数时间=记一次数的时间*LOAD的值
    11. 1/21*21*1000*nms
    12. 作者:
    13. 日期:
    14. ************************************/
    15. void Systick_Interrupt_Init(u32 nms,char nus)
    16. {
    17. //1. 先选择时钟源(一般选择STCLK -- 21M)-- 选择好了记一次数的时间,1/21M s
    18. SysTick->CTRL &= ~(0x1 << 2);
    19. //2. 往重装载寄存器写值(记多少次)
    20. SysTick->LOAD = 21 * pow(1000,nus) * nms;
    21. //3. 对VAL寄存器执行写操作(就可以把重装载值加载到计数器里)
    22. SysTick->VAL = 0;
    23. //4. 使能对应的中断标志
    24. SysTick->CTRL |= 0x1 << 1;
    25. //5. 配置中断优先级
    26. NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority(7-2,2,2));
    27. //6. 使能计数器
    28. SysTick->CTRL |= 0x1 << 0;
    29. }
    30. //7. 编写中断服务函数
    31. void SysTick_Handler(void)
    32. {
    33. //清除标志位
    34. if((SysTick->CTRL & 0x1 << 16))
    35. {
    36. if(fac_us>0)
    37. fac_us--;
    38. if(fac_ms>0)
    39. fac_ms--;
    40. // printf("123456\r\n");
    41. }
    42. }
    43. //#else
    44. /************************************
    45. 函数功能:延时ms
    46. 函数形参:u32 nms
    47. 函数返回值:void
    48. 函数说明:
    49. 选择21M的时钟源
    50. 总的计数时间=记一次数的时间*LOAD的值
    51. 1/21*21*1000*nms
    52. 作者:
    53. 日期:
    54. ************************************/
    55. void Delay_Ms(u32 nms,u32 nus)
    56. {
    57. //1. 先选择时钟源(一般选择STCLK -- 21M)-- 选择好了记一次数的时间,1/21M s
    58. SysTick->CTRL &= ~(0x1 << 2);
    59. //2. 往重装载寄存器写值(记多少次)
    60. SysTick->LOAD = 21 * 1000 * nms;
    61. //3. 对VAL寄存器执行写操作(就可以把重装载值加载到计数器里)
    62. SysTick->VAL = 0;
    63. //4. 使能计数器
    64. SysTick->CTRL |= 0x1 << 0;
    65. //5. 等待计数时间到达
    66. while(!(SysTick->CTRL & (0x1 << 16)))
    67. {
    68. }
    69. //5. 关闭计数器
    70. SysTick->CTRL &= ~(0x1 << 16);
    71. }
    72. /************************************
    73. 函数功能:延时ms
    74. 函数形参:u32 nms
    75. 函数返回值:void
    76. 函数说明:
    77. 选择21M的时钟源
    78. 总的计数时间=记一次数的时间*LOAD的值
    79. 1/21*21*1000*nms
    80. 作者:
    81. 日期:
    82. ************************************/
    83. void DElay_US(u32 nms, u32 nus)
    84. {
    85. if(nus<=500)
    86. {
    87. fac_us=1;
    88. Systick_Interrupt_Init(nms,nus);
    89. }
    90. else
    91. {
    92. fac_us = nus;
    93. Systick_Interrupt_Init(1,nus);
    94. }
    95. SysTick->CTRL &= ~(0x1 << 16);
    96. }
    97. /************************************
    98. 函数功能:延时ms
    99. 函数形参:u32 nms
    100. 函数返回值:void
    101. 函数说明:
    102. 选择21M的时钟源
    103. 总的计数时间=记一次数的时间*LOAD的值
    104. 1/21*21*1000*nms
    105. 作者:
    106. 日期:
    107. ************************************/
    108. void DElay_MS(u32 nms, u32 nus)
    109. {
    110. if(nms<=500)
    111. {
    112. u32 fac_ms = 0;
    113. Systick_Interrupt_Init(nms,1);
    114. }
    115. else
    116. {
    117. fac_ms = nms;
    118. Systick_Interrupt_Init(nms,1);
    119. }
    120. while(fac_ms !=0);
    121. SysTick->CTRL &= ~(0x1 << 16);
    122. }

  • 相关阅读:
    详解 Go 语言中的 init () 函数
    浏览器面试题
    xshell部署前端代码
    LeetCode50天刷题计划(Day 43 —子集(20)单词搜索(40)
    Java FileWriter.flush()具有什么功能呢?
    AntScheduler
    全球第4大操作系统(鸿蒙)的软件后缀.hap
    文盘Rust -- struct 中的生命周期
    多线程案例(1) - 单例模式
    Istio 自动注入 sidecar 失败导致无法访问webhook服务
  • 原文地址:https://blog.csdn.net/weixin_52483742/article/details/133962841