/**
******************************************************************
* file core_delay.c
* author fire
* version V1.0
* date 2018-xx-xx
* [url=home.php?mod=space&uid=247401]@brief[/url] 使用内核寄存器精确延时
******************************************************************
* @attention
*
* 实验平台:野火 STM32开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************
*/ #include "./delay/core_delay.h" /*
**********************************************************************
* 时间戳相关寄存器定义
**********************************************************************
*/
/*
在Cortex-M里面有一个外设叫DWT(Data Watchpoint and Trace),
该外设有一个32位的寄存器叫CYCCNT,它是一个向上的计数器,
记录的是内核时钟运行的个数,最长能记录的时间为:
10.74s=2的32次方/400000000
(假设内核频率为400M,内核跳一次的时间大概为1/400M=2.5ns)
当CYCCNT溢出之后,会清0重新开始向上计数。
使能CYCCNT计数的操作步骤:
1、先使能DWT外设,这个由另外内核调试寄存器DEMCR的位24控制,写1使能
2、使能CYCCNT寄存器之前,先清0
3、使能CYCCNT寄存器,这个由DWT_CTRL(代码上宏定义为DWT_CR)的位0控制,写1使能
*/
 
    #define  DWT_CR      *(__IO uint32_t *)0xE0001000 //< 0xE0001000 DWT_CTRL RW The Debug Watchpoint and Trace (DWT) unit
    #define  DWT_CYCCNT  *(__IO uint32_t *)0xE0001004 //< 0xE0001004 DWT_CYCCNT RW Cycle Count register, 
    #define  DEM_CR      *(__IO uint32_t *)0xE000EDFC //< 0xE000EDFC DEMCR RW Debug Exception and Monitor Control Register.

    #define  DEM_CR_TRCENA                   (1 << 24)  //DEMCR的DWT使能位
    #define  DWT_CR_CYCCNTENA                (1 <<  0)  //DWT的SYCCNT使能位
    /**
* @brief 初始化时间戳
* @param 无
* @retval 无
* [url=home.php?mod=space&uid=536309]@NOTE[/url] 使用延时函数前,必须调用本函数
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* 使能DWT外设 */
DEM_CR |= (uint32_t)DEM_CR_TRCENA; /* DWT CYCCNT寄存器计数清0 */
DWT_CYCCNT = (uint32_t)0u; /* 使能Cortex-M DWT CYCCNT寄存器 */
DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA; return HAL_OK;
} /**
* @brief 读取当前时间戳
* @param 无
* @retval 当前时间戳,即DWT_CYCCNT寄存器的值
*/
uint32_t CPU_TS_TmrRd(void)
{
return ((uint32_t)DWT_CYCCNT);
} /**
* @brief 读取当前时间戳
* @param 无
* @retval 当前时间戳,即DWT_CYCCNT寄存器的值
*/
uint32_t HAL_GetTick(void)
{
return ((uint32_t)DWT_CYCCNT/SysClockFreq*);
} /**
* @brief 采用CPU的内部计数实现精确延时,32位计数器
* @param us : 延迟长度,单位1 us
* @retval 无
* [url=home.php?mod=space&uid=536309]@NOTE[/url] 使用本函数前必须先调用CPU_TS_TmrInit函数使能计数器,
或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION
最大延时值为8秒,即8*1000*1000
*/
void CPU_TS_Tmr_Delay_US(uint32_t us)
{
uint32_t ticks;
uint32_t told,tnow,tcnt=; /* 在函数内部初始化时间戳寄存器, */
#if (CPU_TS_INIT_IN_DELAY_FUNCTION)
/* 初始化时间戳并清零 */
HAL_InitTick();
#endif ticks = us * (GET_CPU_ClkFreq() / ); /* 需要的节拍数 */
tcnt = ;
told = (uint32_t)CPU_TS_TmrRd(); /* 刚进入时的计数器值 */ while()
{
tnow = (uint32_t)CPU_TS_TmrRd();
if(tnow != told)
{
/* 32位计数器是递增计数器 */
if(tnow > told)
{
tcnt += tnow - told;
}
/* 重新装载 */
else
{
tcnt += UINT32_MAX - told + tnow;
} told = tnow; /*时间超过/等于要延迟的时间,则退出 */
if(tcnt >= ticks)break;
}
}
} /*********************************************END OF FILE**********************/
    #ifndef __CORE_DELAY_H
#define __CORE_DELAY_H #include "stm32h7xx.h" /* 获取内核时钟频率 */
#define GET_CPU_ClkFreq() HAL_RCC_GetSysClockFreq()
#define SysClockFreq (218000000)
/* 为方便使用,在延时函数内部调用CPU_TS_TmrInit函数初始化时间戳寄存器,
这样每次调用函数都会初始化一遍。
把本宏值设置为0,然后在main函数刚运行时调用CPU_TS_TmrInit可避免每次都初始化 */ #define CPU_TS_INIT_IN_DELAY_FUNCTION 0 /*******************************************************************************
* 函数声明
******************************************************************************/
uint32_t CPU_TS_TmrRd(void);
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority); //使用以下函数前必须先调用CPU_TS_TmrInit函数使能计数器,或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION
//最大延时值为8秒
void CPU_TS_Tmr_Delay_US(uint32_t us);
#define HAL_Delay(ms) CPU_TS_Tmr_Delay_US(ms*1000)
#define CPU_TS_Tmr_Delay_S(s) CPU_TS_Tmr_Delay_MS(s*1000) #endif /* __CORE_DELAY_H */

上面代码的核心是:采用Cortex-M3/4内核中的跟踪组件DWT的时钟周期计数CYCCNT实现

参考链接

http://www.firebbs.cn/forum.php?mod=viewthread&tid=19059&fromuid=1

https://blog.csdn.net/linux_liulu/article/details/44998581

【转】STM32 不占用定时器(包括SysTick)实现精确延时(巧用DWT)的更多相关文章

  1. 使用系统定时器SysTick实现精确延时微秒和毫秒函数

    SysTick定时器简介 SysTick定时器是存在于系统内核的一个滴答定时器,只要是ARM Cortex-M0/M3/M4/M7内核的MCU都包含这个定时器,它是一个24位的递减定时器,当计数到 0 ...

  2. STM32时钟系统之利用 systick 定时器来实现准确的延时。

    本篇文章带着大家来认识一下 STM32 的时钟系统,以及利用 systick 定时器来实现一个比较准确的延时. 我们首先从时钟说起,时钟在MCU中的作用,就好比于人类的心脏一样不可或缺.STM32 的 ...

  3. STM32学习笔记——定时器中断(向原子哥学习)

    定时器中断 STM32 的定时器功能十分强大,有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIME5 等通用定时器,还有 TIME6 和TIME7 等基本定时器.在本章中,我们将利 ...

  4. 实现流水灯以间隔500ms的时间闪烁(系统定时器SysTick实现的精确延时)

    /** ****************************************************************************** * @file main.c * ...

  5. STM32 TIM高级定时器死区时间的计算

    STM32 TIM高级定时器的互补PWM支持插入死区时间,本文将介绍如何计算以及配置正确的死区时间. 文章目录 什么是死区时间? 数据手册的参数 如何计算合理的死区时间? STM32中配置死区时间 什 ...

  6. STM32 TIM1高级定时器RCR重复计数器的理解

    STM32 TIM1高级定时器RCR重复计数器的理解 TIMx_RCR重复计数器寄存器,重复计数器只支持高级定时器TIM1和TIM8,下面看标准外设库的TIM结构体的封装: typedef struc ...

  7. 基于Systick系统时钟延时的LED闪烁灯

    1.回顾我们的51 单片机编程,当我们需要做系统延迟的时候,最常采用的一种方式就是使用for 循环的空语句等待来实现. 当然,在STM32 里面也可以这么实现.但是在STM32 的Cortex 内核里 ...

  8. stm32之Cortex系统定时器(SysTick)

    转载自:http://www.21ic.com/app/mcu/201811/781135.htm   SysTick时钟,俗称“嘀嗒定时器”,它能按设定的时间产生一次中断.控制工程代码中随处可见形如 ...

  9. [stm32] STM32的通用定时器TIMx系统了解

    通用定时器(TIMx) 一.TIMx简介 二.TIMx主要功能 三.TIMx功能描述 3.1 时基单元 3.2 计数器模式 3.3 时钟选择 3.4 捕获/比较通道 3.5 输入捕获模式 3.6 PW ...

随机推荐

  1. vim-go 安装

    vim-go 安装 https://studygolang.com/articles/3229

  2. sqlmap的安装

    来自:http://www.51testing.com/html/89/n-3711589.html 一.下载 首先,需下载SqlMap以及适用于Windows系统的Python.下载地址如下: 1. ...

  3. Mvc Session 设置以后再构造函数中取值时为null问题

    在登录界面写了一个session在 别的页面的构造函数中获取始终未null  后来改成 System.Web.HttpContext.Current.Session["User"] ...

  4. web.py模块使用

    web.py模块 import time import web urls=("/",'hello') class hello(): def GET(self): return (t ...

  5. Sqlserver 计算两坐标距离函数

    mark if exists (select * from dbo.sysobjects where id = object_id(N'UF_ETL_GetDistance') and xtype i ...

  6. Docker外包团队 2019年3月更新 企业如何使用Docker

    很难将Docker所带来的影响统一的用一种特质来说.当使用Docker执行好时,它对组织,团队,开发者以及运维人员有多层次的好处.Docker使得架构设计简单化,因为所有的应用都将一致的从外部来透视主 ...

  7. 异常:tomcat与windows时间不同步

    调试一个项目时发现用户那里服务器的Tomcat命令行中log4j输出的时间与操作系统时间不一致,因此日志记录的时间与操作系统时间也不一致,且正好相差8个小时.产生原因是因为Tomcat中的时区设置与操 ...

  8. Vue+Typescript项目中使用echarts

    方案一:推荐 在typescript+Vue的项目中引用echarts,为了加强引用,引入echarts和@types/echarts两个包,一个是工程依赖,一个是声明依赖. npm install ...

  9. 通过 Git 上传代码到 GitHub 必要操作详解

    目录 Git 介绍 起步 下载 配置 准备 在 GitHub 上创建 SSH Key 提交 修改代码 更多信息 Git 欢迎来到 Git 的学习. 介绍 首先先了解一下 Git. Git,是一个开源的 ...

  10. 清空Sql server日志

    日志文件时间长了很大很讨厌,这样清空 1.分离数据库 2.将原数据库的log文件改名 3.附加数据库,在log文件中会显示没有发现,点击删除按钮 4.确定即可