精华内容
下载资源
问答
  • STM32HAL库微秒延时函数的实现---DWT和SysTick
    千次阅读
    2020-03-05 08:59:30

    STM32 HAL库微秒延时函数的实现

    天下苦STM32 HAL库微秒延时久已。不占用其他定时器资源不使用循环的方式就不能实现微秒延时函数了吗?答案是否定的,我们还有方式实现,且还不止一种方法。详情且看下文分解:

    以下两种延时方式来源:Arduino_Core_STM32源码delayMicroseconds(uint32_t us)函数的实现。

    利用SysTick再实现微秒延时函数

    虽然SysTick已经被配置为1ms中断一次的模式,但每个1ms之间SysTick的当前值寄存器是一直在计数的(每计一个数的时间是1/SytemCoreClock)我们便可以利用该机制实现微秒延时函数。

    void delayMicroseconds(uint32_t us)
    {
        __IO uint32_t currentTicks = SysTick->VAL;
      /* Number of ticks per millisecond */
      const uint32_t tickPerMs = SysTick->LOAD + 1;
      /* Number of ticks to count */
      const uint32_t nbTicks = ((us - ((us > 0) ? 1 : 0)) * tickPerMs) / 1000;
      /* Number of elapsed ticks */
      uint32_t elapsedTicks = 0;
      __IO uint32_t oldTicks = currentTicks;
      do {
        currentTicks = SysTick->VAL;
        elapsedTicks += (oldTicks < currentTicks) ? tickPerMs + oldTicks - currentTicks :
                        oldTicks - currentTicks;
        oldTicks = currentTicks;
      } while (nbTicks > elapsedTicks);
    }

    以上函数可以直接复制到工程中使用,不需要额外的任何配置。

    在这里插入图片描述


    Note

    虽然函数参数usuint32_t类型,但是延时数不能过大,原因自己分析。建议超过1ms的延时时间使用HAL_Delay()


    利用DWT(数据观测点)实现微秒延时函数

    对于DWT大家可以搜索具体了解,这里我也不是很了解,就直说实现方法好了。

    dwt.h文件

    /**
      ******************************************************************************
      * @file    dwt.h
      * @author  Frederic Pillon
      * @brief   Header for dwt.c module
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2019, STMicroelectronics
      * All rights reserved.
      *
      * This software component is licensed by ST under BSD 3-Clause license,
      * the "License"; You may not use this file except in compliance with the
      * License. You may obtain a copy of the License at:
      *                        opensource.org/licenses/BSD-3-Clause
      *
      ******************************************************************************
      */
    
    /* Define to prevent recursive inclusion -------------------------------------*/
    #ifndef _DWT_H_
    #define _DWT_H_
    
    #include "stm32f4xx.h"
    #include <stdbool.h>
    
    #ifndef UNUSED
    #define UNUSED(x) (void)x
    #endif
    
    #ifdef DWT_BASE
    uint32_t dwt_init(void);
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    //uint32_t dwt_init(void);
    void dwt_access(bool ena);
    
    static inline uint32_t dwt_max_sec(void)
    {
      return (UINT32_MAX / SystemCoreClock);
    };
    
    static inline uint32_t dwt_max_msec(void)
    {
      return (UINT32_MAX / (SystemCoreClock / 1000));
    };
    
    static inline uint32_t dwt_max_usec(void)
    {
      return (UINT32_MAX / (SystemCoreClock / 1000000));
    };
    
    static inline uint32_t dwt_getCycles(void)
    {
      return (DWT->CYCCNT);
    };
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif /* DWT_BASE */
    #endif /* _DWT_H_ */
    

    dwt.c文件

    /**
      ******************************************************************************
      * @file    dwt.c
      * @author  Frederic Pillon
      * @brief   Provide Data Watchpoint and Trace services
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2019, STMicroelectronics
      * All rights reserved.
      *
      * This software component is licensed by ST under BSD 3-Clause license,
      * the "License"; You may not use this file except in compliance with the
      * License. You may obtain a copy of the License at:
      *                        opensource.org/licenses/BSD-3-Clause
      *
      ******************************************************************************
      */
    
    #include "dwt.h"
    
    #ifdef DWT_BASE
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    
    uint32_t dwt_init(void)
    {
    
      /* Enable use of DWT */
      if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {
        CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
      }
    
      /* Unlock */
      dwt_access(true);
    
      /* Reset the clock cycle counter value */
      DWT->CYCCNT = 0;
    
      /* Enable  clock cycle counter */
      DWT->CTRL |=  DWT_CTRL_CYCCNTENA_Msk;
    
      /* 3 NO OPERATION instructions */
      __asm volatile(" nop      \n\t"
                     " nop      \n\t"
                     " nop      \n\t");
    
      /* Check if clock cycle counter has started */
      return (DWT->CYCCNT) ? 0 : 1;
    }
    
    void dwt_access(bool ena)
    {
    #if (__CORTEX_M == 0x07U)
      /*
       * Define DWT LSR mask which is (currentuly) not defined by the CMSIS.
       * Same as ITM LSR one.
       */
    #if !defined DWT_LSR_Present_Msk
    #define DWT_LSR_Present_Msk ITM_LSR_Present_Msk
    #endif
    #if !defined DWT_LSR_Access_Msk
    #define DWT_LSR_Access_Msk ITM_LSR_Access_Msk
    #endif
      uint32_t lsr = DWT->LSR;
    
      if ((lsr & DWT_LSR_Present_Msk) != 0) {
        if (ena) {
          if ((lsr & DWT_LSR_Access_Msk) != 0) { //locked
            DWT->LAR = 0xC5ACCE55;
          }
        } else {
          if ((lsr & DWT_LSR_Access_Msk) == 0) { //unlocked
            DWT->LAR = 0;
          }
        }
      }
    #else /* __CORTEX_M */
      UNUSED(ena);
    #endif /* __CORTEX_M */
    }
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    

    delayMicroseconds()函数

    void delayMicroseconds(uint32_t us)
    {
    #if defined(DWT_BASE) && !defined(DWT_DELAY_DISABLED)
      int32_t start  = dwt_getCycles();
      int32_t cycles = us * (SystemCoreClock / 1000000);
    
      while ((int32_t)dwt_getCycles() - start < cycles);
    #endif
    }

    在这里插入图片描述


    Note:

    在使用DWT实现的延时函数时,程序下载到单片机中不能直接运行,需要按一下复位键才能正常运行(使用keil-MDK环境,ST-Link下载)。


    结论

    对比上面两种方式的延时效果:DWT实现的延时精度更高,SysTick的使用更加简单,大家可针对自己的需求选择。

    更多相关内容
  • STM32CubeMX | STM32 HAL库方式的微秒延时函数

    万次阅读 多人点赞 2019-11-06 10:22:15
    STM32CUBEMX系列教程之HAL库方式的微秒延时函数 标准一般是使用系统嘀嗒定时器来进行微妙级别的延时,而HAL库官方使用SysTick的地方非常多,改代码容易引起错乱。网上的代码使用定时器进行微秒级别延时(不知道该...

    STM32CUBEMX系列教程之HAL库方式的微秒延时函数


    标准库一般是使用系统嘀嗒定时器来进行微妙级别的延时,而HAL库将SysTick定时器用做了库函数的超时定时器,使用的地方非常多,自己修改代码使用嘀嗒定时器的话就会引起错乱。所以此时就需要自己实现一个微秒级别延时函数。


    扫描以下二维码,关注公众号雍正不秃头获取更多STM32资源及干货!
    在这里插入图片描述


    方式一:系统滴答定时器

    优点:全系列通用,只需要将宏定义CPU_FREQUENCY_MHZ根据时钟主频修改即可。
    缺点:系统滴答定时器是HAL库初始化的,且必须有HAL库初始化。

    #define CPU_FREQUENCY_MHZ    72		// STM32时钟主频
    void delay_us(__IO uint32_t delay)
    {
        int last, curr, val;
        int temp;
    
        while (delay != 0)
        {
            temp = delay > 900 ? 900 : delay;
            last = SysTick->VAL;
            curr = last - CPU_FREQUENCY_MHZ * temp;
            if (curr >= 0)
            {
                do
                {
                    val = SysTick->VAL;
                }
                while ((val < last) && (val >= curr));
            }
            else
            {
                curr += CPU_FREQUENCY_MHZ * 1000;
                do
                {
                    val = SysTick->VAL;
                }
                while ((val <= last) || (val > curr));
            }
            delay -= temp;
        }
    }
    
    

    方式二:简单延时

    优点: 实现简单,如果是F1系列,HAL_RCC_GetHCLKFreq()获取的值是72000000,此方式经过测试还是比较准的,如果不考虑通用性,F1系列建议使用此种方式。

    缺点: 只适用F1系列72M主频。

    void delay_us(uint32_t us)
    {
        uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
        while (delay--)
    	{
    		;
    	}
    }
    

    方式三:普通定时器

    优点: STM32全系列通用
    缺点: 占用一个定时器

    该方法的思路是将定时器设置为1MHZ的计数频率,定时器计一个数就是1us,实现如下:

    【F1系列】
    在这里插入图片描述

    #define DLY_TIM_Handle (&htim4)
    void delay_us(uint16_t nus)
    {
    	__HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
    	__HAL_TIM_ENABLE(DLY_TIM_Handle);
    	while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
    	{
    	}
    	__HAL_TIM_DISABLE(DLY_TIM_Handle);
    }
    
    

    【F4系列】
    在这里插入图片描述

    #define DLY_TIM_Handle  (&htim7)
    
    void delay_us(uint16_t nus)
    {
    	__HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
    	__HAL_TIM_ENABLE(DLY_TIM_Handle);
    	while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
    	{
    	}
    	__HAL_TIM_DISABLE(DLY_TIM_Handle);
    }
    
    

    展开全文
  • STM32 HAL库实现US微秒延时函数

    千次阅读 2021-04-28 14:31:43
    现代的ST主推HAL库,但是这么强大的HAL库,居然没有一个微秒级别的延时函数???? 在HAL库中有毫秒级延时HAL_Delay(),原理是使用Systick作为延时计数器来实现的。如果需要增加精确的微秒级别延时,一般都是直接...

    STM32之CubeL4定时器控制实现微秒延时

    现代的ST主推HAL库,但是这么强大的HAL库,居然没有一个微秒级别的延时函数????


    在HAL库中有毫秒级延时HAL_Delay(),原理是使用Systick作为延时计数器来实现的。如果需要增加精确的微秒级别延时,一般都是直接更改Systick配置参数,但HAL固件很多的地方都使用了HAL_Delay()函数,因此不建议修改系统自动配置的Systick参数。

    一、定时器微秒实现原理

    CK_INT 80M时钟输入定时器,80分频后1Mhz = 1us,也就是计数器CNT每加一次就是1us。

    在这里插入图片描述
    STM32L4x1 参考手册P780

    我是用到是TIM2,首先需要知道TIM2的时钟,查看手册得知TIM2在APB1总线上
    在这里插入图片描述
    STM32L431xx 参考手册P16

    知道时钟输入后直接在CubeMX中配置定时器。

    定时器计数配置

    首先配置系统时钟
    在这里插入图片描述
    接下来配置定时器
    在这里插入图片描述
    编写思路

    设置CNT的值为0 --> (开始计数) --> 比较CNT值 --> (到达CNT值) --> 停止计数

    具体代码实现

    // Core\Src\delay.c
    void HAL_Delay_US(uint32_t Delay_us) 
    {
    
    		__HAL_TIM_SetCounter(&htim2, 0);
    
    		__HAL_TIM_ENABLE(&htim2);
    
    		while(__HAL_TIM_GetCounter(&htim2) < Delay_us);
    		/* Disable the Peripheral */
    		__HAL_TIM_DISABLE(&htim2);
    
    
    }
    
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
        
    		GPIOA->BSRR = GPIO_PIN_2;	// PA2 = 1 	
    		HAL_Delay_US(10);
    		GPIOA->BSRR = (uint32_t)GPIO_PIN_2<< 16U; // PA2 = 0 	
    		HAL_Delay_US(10);
      
      }
      /* USER CODE END 3 */
    }
    

    2us
    在这里插入图片描述
    5us
    在这里插入图片描述

    10us

    在这里插入图片描述

    50us

    在这里插入图片描述

    500us

    在这里插入图片描述

    展开全文
  • HAL 有提供延时函数,只不过它只能实现简单的毫秒级别延时,没有实现 us 级别延时。 下面我们列出HAL 实现延时相关的函数。首先是功能配置函数: //调用 HAL_SYSTICK_Config 函数配置每隔 1ms 中断一次 __weak ...
  • STM32HAL库微秒延时(μs)

    千次阅读 2020-12-13 22:44:25
    STM32HAL库微秒(μs)延时

    STM32HAL库微秒延时(μs)

    单片机:STM32F407ZET6
    软件版本:STM32CubeMX 4.20.1
    单片机固件包:STM32Cube FW_F4 V1.15.0

    本代码是我于2019年8月参加全国大学生电子设计竞赛前做赛前准备时参考网络上博客的程序代码编写,仅用于学习和交流。希望能给各位读者些许帮助。

    本博客对于STM32单片机实现微秒(μs)延时采用的是定时器计数的方法。以STM32F407ZET6型号单片机的TIM4为例来进行代码展示。

    先设置TIM4的时钟源:
    在这里插入图片描述
    STM32F407ZET6的TIM4的时钟为APB1的两倍即84MHz。
    在这里插入图片描述
    设置TIM4参数:
    在这里插入图片描述
    因为是微秒延时,所以计数频率应为f=1/1μs=1MHz。所以预分频Prescaler应为(84/f)-1=83,理论上来说计数周期Counter Period的设置将影响中断时长,而微秒延时只是计数并不需要开启定时器的中断。但是在实际开发过程中我将Counter Period设置为0结果延时时间变成随机时长,因此建议Counter Period不要设置为0。

    微秒延时函数:

    void Delay_us(uint16_t myus)//基于TIM4定时器的μs延时函数
    {
     uint16_t differ = 0xffff-myus-5;
     HAL_TIM_Base_Start(&htim4);
     __HAL_TIM_SetCounter(&htim4,differ);
     while(differ < 0xffff-5)
     {
      differ = __HAL_TIM_GetCounter(&htim4);
     }
     HAL_TIM_Base_Stop(&htim4);
    }
    

    因为我是使用STMCubeMX搭建的工程,因此需要将这段延时函数加进tim.c中的 /* USER CODE BEGIN 1 / 和 / USER CODE END 1 / 中,并在tim.h中的 / USER CODE BEGIN Prototypes / 和 / USER CODE END Prototypes */ 中加上 void Delay_us(uint16_t ); 做函数声明。
    接下来,我对这个微秒延时函数做一些解释说明:

    1. 函数功能解释:
      HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim) 启动定时器;
      HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim) 关闭定时器;
      __HAL_TIM_SetCounter和__HAL_TIM_GetCounter可在头文件stm32_hal_legacy.h中找到定义:
      在这里插入图片描述
      __HAL_TIM_SET_COUNTER 设定计数初值,默认是0;
      __HAL_TIM_GET_COUNTER 获取当前计数值。
    2. STM32单片机的定时器基本都是16位计数器每次记到0xffff就会重载arr值。因此给定时器应至少赋予初值为0xffff-myus。
    3. 为什么我在定时器基本初值的基础上还要再“-5”呢?
      这是为了防止因中断打断延时,造成计数错误。
      以延时1μs为例:延时1us因而应从0xfffe开始计数,但假设在这过程产生中断。由于被中断打断(此时计数器仍在计数),本因计数至0xffff便停止计数,但由于错过计数值,并重载arr值,将会导致实际延时(0xffff+1)us。
    展开全文
  • STM32CUBEMX系列教程之HAL库方式的微秒延时函数 标准一般是使用系统嘀嗒定时器来进行微妙级别的延时,而HAL库将SysTick定时器用做了库函数的超时定时器,使用的地方非常多,自己修改代码使用嘀嗒定时器的话就会...
  • 延时函数就可以了。(这个函数每隔1ms就会产生一次中断) 但是,要实现微秒的话。。。貌似就没有现成的方法了。 所以我这边通过基础定时器Timer6,通过轮询的方式实现微秒级延时。(对于微秒级延时,如果通过中断...
  • SysTick是stm32系列单片机基本都有的外设,它是一个24位的倒计数定时器,标准的滴答定时器可以有毫秒、微妙延时,但是HAL库只有 HAL_Delay();是一个毫秒延时。下面记录一下我的移植过程。 根据标准的滴答...
  • STM32CubeIDE HAL库微秒us的延时Delay实现

    万次阅读 多人点赞 2020-01-28 22:06:45
    HAL库和LL都没有自带的微秒级延时,但是修改SysTick的...一、利用定时器实现微秒延时 1.MX配置 2. <tim.c> /* USER CODE BEGIN 1 */ void delayXus(uint32_t us) { (&htim3)->Instance->...
  • STM32hal库实现微秒延迟

    千次阅读 2022-02-11 16:35:39
    许多人初次使用hal库,不知道HAL_Delay的实现原理。 大致来说,它的实现步骤如下: 1.用变量获得系统时钟源计数器的值 2.获得要延迟时间的参数值 3.比较两者大小,若时钟计数器的值大于要实现延迟的值,就会困在...
  • STM32CubeMX HAL库自定义延时函数 ms和us

    千次阅读 2020-02-18 11:05:40
    1. stm32 HAL库 确定定时器时钟 确定定时器为哪个时钟? 找到初始化函数 MX_TIM1_Init(); 进入函数,找到 HAL_TIM_Base_Init(&htim1) 进入函数,找到 HAL_TIM_Base_MspInit(htim); 进入函数,依次找到定时器...
  • STM32 HAL库实现微秒级别延时

    万次阅读 2019-04-16 10:51:10
    参考了 http://www.stm32cube.com/article/176 http://www.stm32cube.com/question/434 https://blog.csdn.net/qq_22252423/article/details/76468161
  • STM32 HAL us delay(微秒延时)的指令延时实现方式及优化 STM32的HAL库,直接提供了1ms延时的实现函数HAL_Delay()。其原理是系统在上电后时钟配置阶段,配置了1ms产生一次中断,然后对一个32位寄存器uwTick逐次加1...
  • 【STM32】标准HAL库对照学习教程四--延时函数详解一、前言二、前期准备三、SysTick定时器介绍1、SysTick定时器简介2、SysTick定时器寄存器介绍(1) CTRL寄存器(2)LOAD寄存器(3)VAL寄存器(4)CALIB寄存器3...
  • 现在ST已经把HAL库推向了主流,但是令我不解的是,HAL那么强大,居然没有一个微秒级别的延时函数?!黑人问号脸。好了,废话不多,直接上代码。#include "delay_us.h"/********************************************...
  • ​ 在使用 DHT11 的时候,时序通信需要微秒来操作,STM32CubeMX 自带一个系统时钟,但是实现的是毫秒级别的。因此就自己用通用计时器实现一个。 文章目录概述1.配置定时器时钟2.计数器时钟频率及计数模式预分频系数...
  • 通过HAL实现初始化5us初始化,后面在延时函数中可以再设置延时值。 1. 定时器实现1us延时 中断Enable不打钩 复制必要文件,.c/.h单独一个文件,设置好。 生成代码如下: /* TIM3 init function */ void MX_TIM...
  • 在实际应用中,经常用到延时函数,而HAL库延时函数是毫秒级的,虽然可以自行修改,但该函数使用的地方较多,修改不慎可能会引起其他问题,所以本文使用一个定时器,实现微秒级精确延时,不影响其他使用。...
  • 问题遇到的现象和发生背景 我想要将您PS2手柄HAL库版本的代码移植到自己创建的STM32FI03C6开发板程序中,但是将您的文件移植过去后无法实现改功能,具体表现为t_s、t_ms、t_us三个值不发生改变 问题相关代码,请勿...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 410
精华内容 164
关键字:

hal库微秒延时函数