ARM CMx DWT硬件延时函数实现

在单片机程序当中,延时函数是标配,简单的不精确延时可用软件实现,但如果想要获得精准的可重入微秒级延时,就必须得使用硬件解决。

使用硬件延时主要有3种方案:

1、systick定时器;

2、timerx定时器;

3、DWT系统时钟计数器;

本文所讲解的就是第3种,如何利用DWT硬件,实现硬件延时功能。

Cortex-M3模块框图

DWT是ARM Cortex-M3/M4/M7/M33处理器的标配模块之一,因此只要是基于此内核的单片机都可以实现DWT延时功能,比如常见的STM32F1xx、STM32F4xx、STM32F7xx、GD32F1xx等等等。

DWT模块有很多功能,当前我们只用到它的系统时钟计数功能,DWT模块的系列寄存器中有1个32bit的CYCCNT寄存器,它存储着当前PC采样周期计数值,每个系统时钟其值自增1。例如STM32F103ZET6系统频率为72MHz,那么每秒钟,DWT->CYCCNT会增加72000000。

开启DWT->CYCCNT计数步骤如下:

1、DEMCR的TRCENA置1;(使能DWT功能)

2、DWT->CYCCNT清零;

3、DWT->CTRL的CYCCNTENA置1;(使能DWT_CYCCNT计数器)

经过如上对DWT初始化后,DWT->CYCCNT的值便以系统时钟频率进行递增,溢出后值变成0后再次自动递增。

函数实现逻辑:

1、读取起始时刻CYCCNT值,记录到Start变量;

2、计算需要延时的系统时钟数,并加上Start变量值,记录到Stop变量;

3、一直读取CYCCNT的值,直到CYCCNT超过Stop变量值;

如此,需要分为2种情况:

1、Start <= Stop:

此时,如果读取到的CYCCNT实时值处在B区间,表示当前延时时间还未结束;如果读取到的CYCCNT实时值处在A或者C区间时,表示延时时间已到。

2、Start > Stop:

此时,如果读取到的CYCCNT实时值处在B区间,表示当前延时时间已到;如果读取到的CYCCNT实时值处在A或者C区间时,表示延时时间还未结束。

代码实现如下:

#include "stdint.h"
#include "core_cm4.h"

/*
 * Return:      void
 * Parameters:  void
 * Description: DWT初始化
 */
void vDWTDelayInit(void)
{
    DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
    CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;

    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 秒延时
 */
void vDWTDelayS(float fTime)
{
    int32_t iTime = fTime;

    while((iTime--) > 0)
    {
        vDWTDelayUs(1000000.0f);
    }

    fTime -= iTime;
    vDWTDelayUs(fTime * 1000000.0f);
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 毫秒延时
 */
void vDWTDelayMs(float fTime)
{
    vDWTDelayUs(fTime * 1000.0f);
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 微秒延时
 */
void vDWTDelayUs(float fTime)
{
    volatile uint32_t uiTimeStop = 0u, uiTimeStart = 0u;

    uiTimeStart = DWT->CYCCNT;
    uiTimeStop  = (uint32_t)((SystemCoreClock / 1000000u) * fTime) + uiTimeStart;

    if(uiTimeStop >= uiTimeStart)
        while((DWT->CYCCNT > uiTimeStart) && (DWT->CYCCNT < uiTimeStop));
    else
        while(!((DWT->CYCCNT > uiTimeStop) && (DWT->CYCCNT < uiTimeStart)));
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值