三 STM32F4使用Sys_Tick 实现微秒定时器和延时

news2024/10/5 19:18:38

更多细节参考这篇

1. 什么是时钟以及作用

1.1 什么是时钟

  1. 时钟是由电路产生的周期性的脉冲信号,相当于单片机的心脏

1.2 时钟对于STM32的作用

  1. 指令同步:cpu和内核外设使用时钟信号来进行指令同步
  2. 数据传输控制: 时钟信号控制数据在内部总线上的传输时机
  3. 外设操作:很多外设比如 GPIO USART ADC等需要时钟来控制频率和时序
  4. 节能管理: 调整时钟的频率,可以管理MCU的功耗,实现节能

2. 关于Sys_Tick 定时器

Sys_Tick 是 ARM Cortex-M4 内核的一部分, 他提供24位递减计数器, 可以用来生成周期性的中断,适合用来左滴答定时器或者提供时间基准

2.1 Sys_Tick 定时器配置步骤

  1. 首先初始化SysTick : 调用
    SysTick_Config(SystemCoreClock/1000 ) ;  //位与CMSIS 下的core_cm4.h 1760 行

函数来配置SysTick定时器的重载值
,该值基于系统时钟频率和中断频率所需的值来确定
我这里设置的是1ms中断一次(STM32F4 的系统时钟是100MHZ 一个时钟周期有 1 / 100 000 000 s 也就是10 ns ,实现1ms 需要 100 000 个 10ns )
2. 选择时钟源 : 选择SysTick的时钟源 , 一般选择系统时钟
2. 中断使能

extern volatile uint32_t SysTickUptime  ;
void SysTick_Handler(void)
{
  SysTickUptime++ ; 
}

2.2 使用 SysTick 实现毫秒级定时器以及延时

/* 毫秒级运行定时器 , 返回的是毫秒 
SysTickUptime 溢出时间大概49天 */
uint32_t millis(void) 
{
    return SysTickUptime ; 
}

/* 毫秒级延时函数  */
void delay_ms(uint32_t ms)  
{
    uint32_t now_time = millis();
    while(millis() - now_time  < ms) { }  
    
}

2.3 使用 SysTick 实现微秒级定时器以及延时

  1. 使用 SysTick 实现微秒级定时器以及延时 为什么不直接SysTick_Config(SystemCoreClock/1000000 ) ;来实现呢
  • 中断开销 : 如果SysTick定时设置成微妙产生一次中断 , 那么中断的频率会非常高,可能导致花大量的时间处理中断从而影响程序的执行效率。对于一个100MHz的系统时钟,这意味着每秒会有100万次中断,这对于任何系统来说都是不切实际的。
  • 中断优先级: 处理中断具有一定的优先级, 过高的中断频率可能会导致低优先级任务或者中断得不到及时的处理
  • 24位计数器限制: SysTick 是一个24位递减计数器, 这意味着最大的计数是2的24次方-1 , 如果系统时钟频率非常高,比如180MHz或更高,设置SysTick每微秒递减一次将导致它在很短的时间内溢出,限制了可以生成的最长定时周期。
  1. 读取当前SysTick 来计算微妙
  • 设置一个1us所需的滴答数
static uint32_t usTicks ;
// SystemCoreClock = 100 MHZ
usTicks = SystemCoreClock/1000000 ; //1us的滴答数 usTicks = 100 
  • 捕捉一致的读数
    循环读取SysTickUptime 和 SysTick-> VAL 的值, 直到他们在循环中两次读取之间保持一致。这是为了确保在读取的时候没有SysTick发生 ,以为如果读取 SysTick-> VAL 之后 , 而在 SysTick-> VAL 之前发生中断 , SysTickUptime 会递增, 而SysTick-> VAL 会重置
uint32_t  ms ,  cycle_cnt ;
    do{
        ms = SysTickUptime ; 
        cycle_cnt = SysTick->VAL ; 

    }while(ms != SysTickUptime ) ;
  • 计算微妙
 (ms * 1000 ) + ( ( (SystemCoreClock/1000)   - cycle_cnt )  / usTicks ) ;

1. 通过将ms(毫秒计数)* 1000 得到了系统启动以来的时间(以微妙为单位)
2. 计算 SystemCoreClock/1000 - cycle_cnt 得到自上次中断以来经过的时钟周期数 ,  SystemCoreClock/1000  是SysTick 定时器的重装值 , 表示1ms内的时钟周期数 , 从这个值减去 SysTick-> VAL 得到了自从上次中断以来经过的时钟周期数
3. 最后 将这个值除以 usTicks(每 微秒的时钟周期数) 将周期转换成微妙

最后 函数的返回值也就是自系统启动以来的总微秒

/* 微秒级计数函数  */
uint32_t  micros ( void )  
{
    uint32_t  ms ,  cycle_cnt ;
    do{
        ms = SysTickUptime ; 
        cycle_cnt = SysTick->VAL ; 

    }while(ms != SysTickUptime ) ;
    return (ms * 1000 ) + ( ( (SystemCoreClock/1000)   - cycle_cnt )  / usTicks ) ;
    
}

/* 微秒级延时函数  */
void delay_us(uint32_t us)  
{
    uint32_t now_time = micros();
    while(micros() - now_time  < us) { }     
}

这里的关键是SysTick是递减计数的 , 并在到达零时重置和触发中断 cycle_cnt 变量存储的时从前的计数器值到下一个零点的周期数 , 这个值要用 SysTick定时器的重载值减去 才是已经过去的时钟周期数

3. 完整代码

3.1 Delay.h

#ifndef DELAY_H
#define DELAY_H
#include "stm32f4xx.h"

void Delay_Init(void);

uint32_t millis(void)  ; //毫秒级运行定时器
uint32_t micros(void)  ; //微秒级运行定时器 


void delay_ms(uint32_t ms) ; //毫秒级延时函数 
void delay_us(uint32_t us) ; //毫秒级延时函数 


#endif

3.1 Delay.c

#include "stm32f4xx.h" 
#include "Delay.h"
#include "stm32f4xx_it.h"

static uint32_t usTicks ;
volatile uint32_t SysTickUptime  = 0  ; //systick 每1ms 中断一次 

void Delay_Init(void)
{ 
    SysTick_Config(SystemCoreClock/1000 ) ; 
    /*  
        这里的系统时钟是100mhz,一个时钟周期有 1 / 100 000 000 s   也就是一个时钟周期有 10ns 
        我们需要计数到1ms,也就是100 000个周期,也就是100 000个10ns
        所以 SystemCoreClock/1000 
        1ms 开启systick中断一次
    */
   usTicks = SystemCoreClock/1000000 ; //1us的滴答数 usTicks = 100 
}

/* 毫秒级运行定时器 , 返回的是毫秒 
SysTickUptime 溢出时间大概49天 */
uint32_t millis(void) 
{
    return SysTickUptime ; 
}

/* 毫秒级延时函数  */
void delay_ms(uint32_t ms)  
{
    uint32_t now_time = millis();
    while(millis() - now_time  < ms) { }  
    
}

/* 微秒级计数函数  */
uint32_t  micros ( void )  
{
    uint32_t  ms ,  cycle_cnt ;
    do{
        ms = SysTickUptime ; 
        cycle_cnt = SysTick->VAL ; 

    }while(ms != SysTickUptime ) ;
    return (ms * 1000 ) + ( ( (SystemCoreClock/1000)   - cycle_cnt )  / usTicks ) ;
    
}

/* 微秒级延时函数  */
void delay_us(uint32_t us)  
{
    uint32_t now_time = micros();
    while(micros() - now_time  < us) { }     
}

/*举个简单的例子理解一下 假如 我们这里选择 100mhz  
        此时SysTickUptime = 100 表示自系统启动以来已经过了100ms
        在某一时刻,我们调用micros函数,SysTick->VAL当前的值是50000
        (表示自上次SysTick中断以来已经过了50000个周期)

        那么此时是多少毫秒呢 
也就是计算 SysTickUptime * 1000 + (1000000 - SysTick->VAL) / usTicks
(1000000 - SysTick->VAL) / usTicks 表示走过的50000个周期 有少个usTicks 1个usTicks 也就是1us

*/

3.3 void SysTick_Handler(void)

位于
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1277123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS新手入门笔记整理:CSS图片样式

图片大小 语法 width:像素值; height:像素值; 图片边框&#xff1a;border 语法 边框&#xff1a;宽度值 样式值 颜色值&#xff1b; border:1px solid red; 图片对齐 水平对齐&#xff1a;text-align 语法 text-align:取值; 属性值 说明 left 左对齐(默认值) cent…

【Java Web学习笔记】 1 - HTML入门

项目代码 https://github.com/yinhai1114/JavaWeb_LearningCode/tree/main/html 零、网页的组成 HTML是网页内容的载体。内容就是网页制作者放在页面上想要让用户浏览的信息&#xff0c;可以包含文字、图片视频等。 CSS样式是表现。就像网页的外衣。比如&#xff0c;标题字体、…

go学习之goroutine和channel

文章目录 一、goroutine(协程)1.goroutine入门2.goroutine基本介绍-1.进程和线程说明-2.程序、进程和线程的关系示意图-3.Go协程和Go主线程 3.案例说明4.小结5.MPG模式基本介绍6.设置Golang运行的CPU数7.协程并发&#xff08;并行&#xff09;资源竞争的问题8.全局互斥锁解决资…

【渗透】记录阿里云CentOS一次ddos攻击

文章目录 发现防御 发现 防御 流量清洗 使用高防

acwing算法基础之动态规划--数位统计DP、状态压缩DP、树形DP和记忆化搜索

目录 1 基础知识2 模板3 工程化 1 基础知识 暂无。。。 2 模板 暂无。。。 3 工程化 题目1&#xff1a;求a~b中数字0、数字1、…、数字9出现的次数。 思路&#xff1a;先计算1~a中每位数字出现的次数&#xff0c;然后计算1~b-1中每位数字出现的次数&#xff0c;两个相减即…

YOLOv8优化策略:SENetV2,squeeze和excitation全面升级,效果优于SENet | 2023年11月最新成果

🚀🚀🚀本文改进: SENetV2,squeeze和excitation全面升级,作为注意力机制引入到YOLOv8,放入不同网络位置实现涨点 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1.SENetV2 论文:https://arxiv.org/…

java:springboot3集成swagger(springdoc-openapi-starter-webmvc-ui)

背景 网上集成 swagger 很多都是 Springfox 那个版本的&#xff0c;但是那个版本已经不更新了&#xff0c;springboot3 集成会报错 Typejavax.servlet.http.HttpServletRequest not present&#xff0c;我尝试了很多才知道现在用 Springdoc 了&#xff0c;今天我们来入门一下 …

2023-12-02 LeetCode每日一题(拼车)

2023-12-02每日一题 一、题目编号 1094. 拼车二、题目链接 点击跳转到题目位置 三、题目描述 车上最初有 capacity 个空座位。车 只能 向一个方向行驶&#xff08;也就是说&#xff0c;不允许掉头或改变方向&#xff09; 给定整数 capacity 和一个数组 trips , trip[i] …

国际语音群呼系统

随着海外电话营销的发展&#xff0c;越来越多的出海企业通过国际语音群呼系统打开出海营销之路。企业出海营销运营&#xff0c;选择一个安全、高效、便捷的国际语音群呼系统非常重要。 一、什么是国际语音群呼系统&#xff1f; 国际语音群呼是指通过语音的方式批量向海外用户传…

一进三出宿舍限电模块的改造升级

一进三出宿舍限电模块改造升级石家庄光大远通电气有限公司智能模块功能特点&#xff1a; 电能控制功能&#xff1a;可实施剩余电量管理&#xff0c;电量用完时将自动断电&#xff1b; 剩余电量可视报警提示功能&#xff1a;剩余电量可视&#xff0c;并当电量剩余5度时&#xff…

cpu版本的torch可以用清华镜像源安装

一、来到pytroch官网找到如下代码 官方提供的默认的安装cpu版本的torch的命令 pip3 install torch torchvision torchaudio二、使用清华镜像安装 pip3 install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple

力扣题:字符串的反转-11.24

力扣题-11.24 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;151. 翻转字符串里的单词 解题思想&#xff1a;保存字符串中的单词即可 class Solution(object):def reverseWords(self, s):""":type s: str:rtype: str"&quo…

项目实战-编写ssm整合配置文件

1、父工程pom.xml <properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>…

继承 和 多肽(超重点 ! ! !)

[本节目标] 1.继承 2.组合 3.多肽 1.继承 1.1 为什么要继承 Java中使用类对现实世界中实体来进行描述&#xff0c;类经过实例化之后的产物对象&#xff0c;则可以用来表示现实中的实体&#xff0c;但是现实世界错综复杂&#xff0c;事物之间可能会存在一些关联&#xff0…

计算机组成学习-计算机系统概述总结

1、计算机系统概述 日常见到的计算机有显示器、键盘、鼠标、音箱、主机箱等&#xff1b;主机箱中有&#xff1a;主板、CPU、硬盘、内存、显卡、声卡等&#xff1b; 1.1 计算机系统层次结构 1.2 计算机系统的基本组成 包括硬件系统和软件系统两部分。 1.2.1 计算机硬件 计算…

HarmonyOS 开发案例分享:万能卡片也能用来玩游戏

一、前言 作为一名开发爱好者&#xff0c;从大了讲&#xff0c;我学习并进行 HarmonyOS 相关开发是为了能为鸿蒙生态建设尽一份绵薄之力&#xff0c;从小了讲&#xff0c;就是为了自己的兴趣。而万能卡片是一个让我非常感兴趣的东西。 很多时候我跟别人解释什么是万能卡片&…

LLM:《第 3 部分》从数学角度评估封闭式LLM的泛化能力

一、说明 在 OpenAI 或 Anthropic 等封闭式大型语言模型 (LLM) 领域&#xff0c;对智能和多功能性的真正考验在于它们处理高特异性查询并在响应中表现出独特性的能力。在这篇博客中&#xff0c;我的目标是提供测试这些模型泛化能力的机制。 封闭式LLM意味着您不知道训练语料库的…

matlab操作方法(二)——基本作图

matlab提供很多灵活的二维作图功能函数。这些作图函数分为3类&#xff1a;图形处理、曲线和曲面图的创建、注释和图形特性。作图函数虽多&#xff0c;但语法大致相同 在 MATLAB 中&#xff0c;figure 函数用于创建或选择图形窗口。 matlab figure函数的用法_matlab中figure-C…

【数据结构】环形队列

环形队列 1. 定义 环形队列就是将队列在逻辑上看作环形结构、物理上仍是数组形式存储的一种数据结构。 其实现主要分为两种情况&#xff1a; 浪费空间法记录空间法 2. 实现 实现要考虑的是成员变量 2.1 记录空间法 使用used标识当前存储了多少元素&#xff0c;如果为空&a…

数据结构(三)——算法和算法分析

&#x1f600;前言 数据结构和算法是计算机科学领域中至关重要的概念。它们为解决实际问题提供了有效的方法和步骤。算法作为解决问题的方法和步骤&#xff0c;在计算机中以指令的有限序列的形式表达。本文将介绍算法的定义、描述和程序设计等方面的内容&#xff0c;帮助您深入…