HAL库下的systick 底层配置 HAL_Delay实现原理 微秒级延时(非中断)以及一些重写延时的小坑 关于HAL_Delay的使用问题

2023-11-09

systick HAL_Delay实现原理 微秒级延时(非中断)以及一些重写延时的小坑 关于HAL_Delay的使用问题

HAL_Delay实现原理

HAL_Delay 底层是配置systick进行1ms进行一次中断,每进入一次,全局变量 uwTick 就加1
上面这个函数就是systick的中断差处理函数
下面就是 计数的函数

void SysTick_Handler(void)
{
  HAL_IncTick();
}

__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}

上面的函数返回当前计数值
下面的函数获取初始计数值,并在之后不断的获取计数值与初始计数值的差值来与需要延时时间比较。

__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while ((HAL_GetTick() - tickstart) < wait)
  {
  }
}
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

HAL库下的systick 底层配置

HAL_InitTick(uint32_t TickPriority)
这个函数在在下面两个函数中都有调用。
由HAL_Init()重置,
也可以HAL_RCC_ClockConfig()重新配置时钟,可以随时重置。
因为我没有修改systick的优先级,所以两次的优先级配置都是一样的,为第4组,最高优先级 0。(不懂得可以去了解一下stm32的中断机制)

HAL_Init();
SystemClock_Config();
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  return HAL_OK;
}

其中
HAL_SYSTICK_Config();就是配置定时器计数值
可以通过不断的查找定义发现
最终是配置SysTick->LOAD 也就是最底层的 systick的计数器的重载值 的寄存器

uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
   return SysTick_Config(TicksNumb);
}

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* 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 (0UL);                                                     /* Function successful */
}

实现微秒级的延时

方法一:软件延时,while循环递减。个人不推荐,不够准确
方法二:在上面HAL_SYSTICK_Config()这个函数中修改,将1ms中断一次改成 1us计数一次。缺点就是1us进入一次中断,浪费单片机资源
方法三:通过查询寄存器的值,从而实现不通过中断的方法计数。(在一般情况下,这是最好用的方法)
以下是介绍
从寄存器入手,通过上面了解到
SysTick->LOAD 就是systick计数器的重载值,
再介绍两个寄存器
SysTick->VAL 当前的计数值
SysTick->CTRL=1 使能,减到零是无动作,采用外部时钟源
在这里插入图片描述

void Delay_us( uint32_t cnt)
{
   uint32_t temp;
 SysTick->LOAD = 9* cnt;
 SysTick->VAL=0X00;//清空计数器
 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
 do
 {
  temp=SysTick->CTRL;//读取当前倒计数值
 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
     SysTick->CTRL=0x00; //关闭计数器
    SysTick->VAL =0X00; //清空计数器
}

void Delay_ms( uint32_t cnt)
{   uint32_t i=0; 
     for(i=0;i<cnt;i++)
	  Delay_us(1000);
}

重写延时的小坑

重写完基于systick的延时之后,hal库自带的HAL_Delay就没用了,如果有程序中还有HAL_Delay()函数,程序不会报错,但在单片机运行的时候会卡在这里。
请一定记住不要同时使用两者

关于HAL_Delay的使用问题

如果使用STM32cubemx默认的配置
所有的中断优先级都为第四组 ,抢占优先级0,即都为最高。
如果在其他中断中使用HAL_Delay()函数根据中断优先级机制,并不会执行,反而会卡在这一步。
要么提高systick的优先级(此时应为降低其他中断优先级),要么使用非中断方法(即上面的方法三或一(不推荐))。

码字不易,点赞,收藏支持一下吧。
哭泣。
2021.4.8

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HAL库下的systick 底层配置 HAL_Delay实现原理 微秒级延时(非中断)以及一些重写延时的小坑 关于HAL_Delay的使用问题 的相关文章

  • c项目makefile多重定义错误

    这个问题是一个对应于创建的repexthis问题 在我的嵌入式 C 项目中 我有两个独立的板 我想为每个板创建两个 c 文件 master c 和 Slave c 其中包含自己的特定main 功能 我使用 stm32cumbemx 生成带有
  • GCC - 如何停止链接 malloc?

    我正在努力将我的代码缩减到最小的骨架大小 我使用的是只有 32k 闪存的 STM32F0 需要很大一部分闪存用于数据存储 我的代码已经有大约 20k 闪存大小 其中一些是由于使用了 STM32 HAL 函数 我可以在以后需要时对其进行解释和
  • 如何让printf在STM32F103上工作?

    我是 STM32F103 世界的新手 我有一个STM32F103的演示代码 我正在使用arm none eabi来编译它 我尝试了在谷歌上可以找到的内容 但到目前为止没有任何效果 我已经花了三天时间来解决这个问题 任何人都可以给我一个运行良
  • CMSIS 库是否应该包含在版本控制中? [复制]

    这个问题在这里已经有答案了 通常 我曾经在版本控制中包含芯片供应商 ST 提供的设备特定标头和源以及 CMSIS Core 标头 数量不多 也没有更新的习惯 我使用STM32微控制器 但我不使用立方体框架 or the 标准外设库 最近 我
  • 140-基于stm32单片机智能晾衣杆控制系统Proteus仿真+源程序

    资料编号 140 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 ds1302时钟 光敏传感器 蜂鸣器 LED灯 制作一个基于stm32单片机智能晾衣杆控制系统Proteus仿真 2 通过光敏传感器
  • 138-基于stm32单片机汽车多功能仪表盘显示系统Proteus仿真+源程序

    资料编号 138 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 ds1302时钟 LED灯 蜂鸣器 电位器 制作一个基于stm32单片机汽车多功能仪表盘显示系统Proteus仿真 2 通过DHT1
  • 136-基于stm32单片机家庭温湿度防漏水系统设计Proteus仿真+源程序

    资料编号 136 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 蜂鸣器 制作一个基于stm32单片机家庭温湿度防漏水系统设计Proteus仿真 2 通过DHT11传感器检测当前温湿度 并且显示到L
  • rt-thread studio中新建5.0不能用

    文章目录 一 版本对比 二 文件和文件夹打斜杠 在使用RT Thread studio创建新工程5 0版本的时候 结果发现新建完成之后程序不能正常运行 但是创建4 10版本的时候却能运行 那肯定是新版本出现了BUG 一 版本对比 首先对比了
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • 匹配 STM32F0 和 zlib 中的 CRC32

    我正在研究运行 Linux 的计算机和 STM32F0 之间的通信链路 我想对我的数据包使用某种错误检测 并且由于 STM32F0 有 CRC32 硬件 并且我在 Linux 上有带有 CRC32 的 zlib 所以我认为在我的项目中使用
  • STM32F103概要

    The STM32F103x4 STM32F103x6 STM32F103xC STM32F103xD and STM32F103xE are a drop in replacement for STM32F103x8 B medium d
  • SHT10温湿度传感器——STM32驱动

    实验效果 硬件外观 接线 3 3V供电 IIC通讯 代码获取 查看下方 END
  • [MM32硬件]搭建灵动微MM32G0001A6T的简易开发环境

    作为学习单片机的经典 自然是通过GPIO点亮LED 或者是响应按钮的外部中断例程 这我们看看SOP8封装的芯片MM32G0001A6T得引脚 除了VDD和GND固定外 我们可以使用PA14 PA1 PA13 PA15 PA2 PA3这六个G
  • 硬件基础-电容

    电容 本质 电容两端电压不能激变 所以可以起到稳定电压作用 充放电 电容量的大小 想使电容容量大 使用介电常数高的介质 增大极板间的面积 减小极板间的距离 品牌 国外 村田 muRata 松下 PANASONIC 三星 SAMSUNG 太诱
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • STM32F207 I2C 测试失败

    我正在使用 STM32F207 微控制器在 STM3220G EVAL 板上学习嵌入式开发 我尝试通过连接同一芯片上的两个 I2C2 和 I2C3 模块并发送 接收字符来测试 I2C 接口 这是我当前编写的代码 使用 mdk arm 5 i
  • 从没有中断引脚并且在测量准备好之前需要一些时间的传感器读取数据的最佳方法

    我正在尝试将压力传感器 MS5803 14BA 与我的板 NUCLEO STM32L073RZ 连接 根据 第 3 页 压力传感器需要几毫秒才能准备好读取测量值 对于我的项目 我对需要大约 10 毫秒来转换原始数据的最高分辨率感兴趣 不幸的
  • STM32F0、ST-link v2、OpenOCD 0.9.0:打开失败

    我在用着发射台 http www ti com ww en launchpad about htmlgcc arm none eabi 4 9 2015q2 为 STM32F0 进行编译 现在我想使用该集合中的 arm none eabi
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt

随机推荐

  • Java 数据库中文变成问号???解决办法

    在连接的URL地址后面加上 url jdbc mysql localhost 3306 test useUnicode true characterEncoding utf8 于是在正式项目里面还发现一个 用于批处理的 还是加上吧 免得以后
  • CRC校验详解(附代码示例)

    目录 1 CRC校验原理 2 生成多项式 3 以CRC 16校验为例讲解编程实现 3 3 1 完全按照CRC原理实现校验 3 3 2 工程中常用CRC校验过程 3 3 3 改进的CRC校验过程 4 以CRC 8校验为例讲解查表法 5 以CR
  • IO和NIO

    什么是I O模型 通常情况下I O操作是比较耗时的 所以为了高效的使用硬件 应用程序可以专门设置一个线程进行I O操作 而另外一个线程则利用CPU的空闲去做其他计算 这种为提高应用执行效率而采用的I O操作方法称为I O模型 当然了 在网络
  • 哪种程序员最挣钱?平均月薪30.8K,网友说这是掌握世界的技术

    20出头 工作没有方向 人生迷茫 这是很多同学都会遇到的情况 播妞经常收到男生粉丝的私信问我 到底学什么技术好啊 确实 男生没一门扎实的技能在手 生活和工作的压力都会很大 虽说条条大路通罗马 但是行业之间的差距还是很大的 如何选择一门高薪且
  • 文件md5验证生成器(java版)

    import java applet import java io import java security public class HashFile public static char hexChar 0 1 2 3 4 5 6 7
  • msvcp140.dll丢失的解决方法?三个常见修复解决方法

    msvcp140 dll是Microsoft Visual C Redistributable的一部分 它是一个Windows操作系统中的动态链接库文件 这个文件是由Microsoft开发的 用于提供运行C 程序所需的函数和库 它通常用于许
  • 从源码角度看Linux进程组和线程组

    1 进程ID 线程组ID 设置了CLONE THREAD flag创建的进程 线程 同属于同一个线程组 拥有同一个线程组ID TGID pthread create创建线程的时候 底层通过clone函数实现就指定了CLONE THREAD参
  • WPF中TreeView的使用

    WPF中对树控件的使用主要有两种方法 方法一 对TreeView进行静态搭建 对应的XAML文件代码如下
  • 知识中台,驱动产业智能化升级

    随着人工智能技术的进步 智能化成为产业转型升级的关键抓手 但企业在提升数字化和智能化水平的实践过程中 面临多种挑战 如 移动应用的普及 带来异构数据呈几何级数增长 企业需要深度挖掘数据价值以赋能业务 以及传统 IT 系统缺乏智能化的技术手段
  • MinIO的使用

    MinIO is a high performance object storage solution that provides an Amazon Web Services S3 compatible API and supports
  • sm.ms 图床api使用

    API文档 https sm ms doc API使用样例
  • Git http url的网络连接改进

    通过作者一天的验证 以下方法治标不治本 最终转为ssh上传 请认真甄别 1 修改hosts文件 140 82 113 4 图1的IP Address github com 199 232 69 194 图2的IP Address githu
  • MIT License探讨

    MIT License是一种非常宽松的协议 它本身的条款非常简单明了 在OSI的网站上有其标准模板 https opensource org licenses MIT 直接复制如下 The MIT License MIT Copyright
  • Linux系统的目录结构

    目录 一 Linux系统使用注意 1 Linux严格区分大小写 2 Linux文件 扩展名 3 Linux中所有内容以文件形式保存 4 Linux中存储设备都必须在挂载之后才能使用 二 目录结构 1 Linux分区与Windows分区 2
  • 读论文《Crossformer:利用跨维度依赖进行多变量时间序列预测的Transform》

    原文标题 CROSSFORMER TRANSFORMER UTILIZING CROSSDIMENSION DEPENDENCY FOR MULTIVARIATE TIME SERIES FORECASTING 动机 基于Transform
  • 一文明白IO模型和常问多路复用机制

    1 IO模型 Socket的输入操作有两步 wait for data 等待网络传输数据到达 到达后复制到内核缓冲区 copy data from kernel to user 把数据从内核缓冲区复制到应用进程缓冲区 涉及到两个对象 pro
  • 清理windows缓存bat脚本

    清理windows缓存bat脚本 1 脚本功能 清理windows缓存文件 2 脚本内容 rem 关闭Windows外壳程序explorer taskkill f im explorer exe rem 清理系统图标缓存数据库 attrib
  • 关于博客和github

    关于博客和github github其实很久之前已经在慢慢弄了 但是每次增加了啥东西就要git弄一次确实麻烦 但是如果不这样的久了就忘了 所以github也咕了 最近花了点时间把本地没push的东西都扔上了github 之后学的东西应该也都
  • 网络请求方式(GET和POST)

    在浏览器的URL中写入地址 点击回车 访问 浏览器会发送数据过去 本质上发送的是字符串 GET explor http1 1 r nhost r nuser agent r n r n r n 浏览器会发送数据过去 本质上发送的是字符串 P
  • HAL库下的systick 底层配置 HAL_Delay实现原理 微秒级延时(非中断)以及一些重写延时的小坑 关于HAL_Delay的使用问题

    systick HAL Delay实现原理 微秒级延时 非中断 以及一些重写延时的小坑 关于HAL Delay的使用问题 HAL Delay实现原理 HAL库下的systick 底层配置 实现微秒级的延时 重写延时的小坑 关于HAL Del