4. 延时方式见解及DWT实现硬件延时

目录

一、基于内核DWT实现硬件延时

1. 软件延时

2. 硬件延时方案

3. Cortex-M4内核架构-DWT

4. DWT硬件延时方案

1)DWT寄存器CYCCNT介绍

2)DWT延时功能涉及的寄存器

3)使能DWT的方法:

4)使能计数器的方法

5)延时初始化完整代码整理:

6)延时(微秒级)函数实现

7)延时(毫秒级)函数实现

8)代码实现与头文件包含

9)delay.h头文件内容

二、应用案例

1)例题:LED延时闪烁代码实现

三、知识小结


一、基于内核DWT实现硬件延时
1. 软件延时
  • 实现原理:通过while循环空转实现延时,在system_init函数中提高内核主频后,delay函数的延时时间会变短。
  • 特点:
    • 精度差,受内核主频和while循环指令周期数影响
    • 主频改变时需要重新调校,过程困难
    • 示例代码:static void Delay(uint32_t count){while(count--);}
2. 硬件延时方案

  • 实现方式:
    • 使用片上定时器(Timer)
    • 使用内核滴答定时器(systick)
  • systick实现原理:
    • 中断服务函数SysTick_Handler每1ms触发一次
    • 全局变量uwTick每次中断递增1
    • 延时函数通过比较当前uwTick与起始值的差值实现延时
  • 缺点:需要占用定时器和中断资源,对CPU资源有浪费
3. Cortex-M4内核架构-DWT
  • DWT模块:
    • 数据跟踪监视点单元,位于内核中
    • 仅Cortex-M3及以上内核支持,M0/M1不支持
    • 与systick同属内核调试子系统
4. DWT硬件延时方案
1)DWT寄存器CYCCNT介绍

  • 特性:
    • 32位向上计数器,记录内核时钟运行次数
    • 120MHz主频时精度为:1/120M=8.3ns
    • 溢出后自动从0重新开始计数
  • 最大延时时间:
    • 120MHz时最大延时:2^32∗1/120M=36s
    • 满足单片机程序需求(通常微秒到毫秒级)
2)DWT延时功能涉及的寄存器
  • 关键寄存器:
    • DEMCR:开启DWT功能
    • DWT_CTRL:开启CYCCNT计数
    • DWT_CYCCNT:获取系统时钟计数值
3)使能DWT的方法:

  • 操作步骤:
    • 向DEMCR寄存器的第24位(TRCENA)写1
    • 寄存器定义位于core_cm4.h头文件
4)使能计数器的方法

  • 操作步骤:
    • 向DWT_CTRL寄存器的第0位写1
    • 计数器清零:DWT->CYCCNT = 0
5)延时初始化完整代码整理:
/**
****************************************************************************
*@brief DWT初始化配置
*@param
*@return
****************************************************************************
*/
void Delaylnit(void)
{
     /* 关闭 TRC */
     CoreDebug->DEMCR&=~CoreDebug_DEMCR_TRCENA_Msk;
     /* 打开 TRC */
     CoreDebug->DEMCR|= CoreDebug_DEMCR_TRCENA_Msk;
     /*关闭计数功能 */
     DWT->CTRL &= ~ DWT_CTRL_CYCCNTENA_Msk;
     /*打开计数功能 */
     DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
     
	/*计数清零*/
	 DWT->CYCCNT = 0;
}
    6)延时(微秒级)函数实现
    /**
    ****************************************************************************
    *@brief 微秒级延时函数
    *@param nUs,最大延时时间(2^32/内核主频)*10^6 us
    *@return
    ****************************************************************************
    */
    void DelayNus(uint32_t nUs)
    {
         uint32_t tickStart = DWT->CYCCNT;
         /*转换为nUs对应的时钟跳动次数\微秒单位*/
         nUs*= (rcu_clock_freq_get(CK_AHB)/1000000);
         /*延时等待 */
         while((DWT->CYCCNT - tickStart) < nUs);
    }
    • 实现原理:
      • 获取当前CYCCNT值存入tickStart
      • 将微秒数转换为时钟跳动次数:nUs *= (rcu_clock_freq_get(CK_AHB)/1000000)
      • 循环等待直到(DWT->CYCCNT - tickStart) >= nUs
    • 注意事项:
      • 使用uint32_t类型保证减法运算正确性
      • 最大延时时间限制为36秒(120MHz时)
    7)延时(毫秒级)函数实现
    /**
    ****************************************************************************
    *@brief 毫秒级延时函数
    *@param nMs,延时时间n毫秒
    *@return
    ****************************************************************************
    */
    void DelayNms(uint32_t nMs)
    {
         void DelayNms(uint32_t nMs)
         for (uint32_t i= 0;i<nMs; i++)
         { 
              DelayNus(1000);
         }
        
    }
    • 实现方式:
      • 循环调用DelayNus(1000)实现毫秒延时
    8)代码实现与头文件包含
    • 必要头文件:
      • stdint.h:标准整数类型定义
      • gd32f30x.h:GD32库函数和寄存器定义
      • core_cm4.h:内核相关寄存器定义
    9)delay.h头文件内容
    • 函数声明:
      • 延时初始化:void DelayInit(void)
      • 微秒延时:void DelayNus(uint32_t nUs)
      • 毫秒延时:void DelayNms(uint32_t nMs)
    • 条件编译:使用宏定义防止重复包含
    二、应用案例
    1)例题:LED延时闪烁代码实现

    main.c:

    #include <stdint.h>
    #include "gd32f30x.h"
    #include "delay.h"
    
    int main(void)
    {
    	/*使能GPIO的时钟*/
    	rcu_periph_clock_enable(RCU_GPIOA);
    	/*配置为推挽输出模式*/
    	gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_8);
    
    	while (1)
    	{
    		/*配置为输出高电平*/
    		gpio_bit_set(GPIOA, GPIO_PIN_8);
    		DelayNms(1000);
    		/*配置为输出低电平*/
    		gpio_bit_reset(GPIOA, GPIO_PIN_8);
    		DelayNms(1000);
    	}
    }

    delay.c

    #include <stdint.h>
    #include "gd32f30x.h"
    
    /**
    ***********************************************************
    * @brief DWT初始化配置
    * @param
    * @return 
    ***********************************************************
    */
    void DelayInit(void) 
    {
    	/* 关闭 TRC */
    	CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
    	/* 打开 TRC */
    	CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    
    	/* 关闭计数功能 */
    	DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
    	/* 打开计数功能 */
    	DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    
    	/* 计数清零 */
    	DWT->CYCCNT = 0;
    }
    
    /**
    ***********************************************************
    * @brief 微秒级延时函数
    * @param nUs,最大延时时间( 2^32 / 内核主频 ) * 10^6 us 
    * @return 
    ***********************************************************
    */
    void DelayNus(uint32_t nUs)
    {
    	uint32_t tickStart = DWT->CYCCNT;
    
    	/* 转换为nUs对应的时钟跳动次数*/
    	nUs *= (rcu_clock_freq_get(CK_AHB) / 1000000);
    
    	/* 延时等待 */
    	while ((DWT->CYCCNT - tickStart) < nUs);
    }
    
    /**
    ***********************************************************
    * @brief 毫秒级延时函数
    * @param nMs,延时时间n毫秒
    * @return 
    ***********************************************************
    */
    void DelayNms(uint32_t nMs)
    {
    	
    	for ( uint32_t i = 0; i < nMs; i++)
    	{
    		DelayNus(1000);
    	}
    }
    
    

    • 代码目录结构:
    • 调试注意事项:
      • 下载后可能需要手动复位开发板
      • 在Keil魔术棒设置中勾选"Reset and Run"选项
      • 硬件延时精度验证:通过秒表实测5秒延时误差很小
    • 方案优势:
      • 不占用定时器资源
      • 不需要中断处理
      • 系统资源占用少
      • 延时精度高
    三、知识小结

    知识点

    核心内容

    关键实现细节

    技术对比

    硬件延时方法

    利用单片机内置计数功能硬件实现精确延时

    使用DWT模块的32位CYCCNT计数器,精度达8.3纳秒(120MHz主频)

    vs软件延时:不受主频变化影响,无需循环调优

    DWT模块原理

    Cortex-M3+内核专用数据跟踪监视单元

    需配置DEMCR(24位)、DWT_CTRL(0位)寄存器,CYCCNT自动累加时钟周期

    vs SysTick:无需中断,资源占用更少

    微秒级延时实现

    delay_us()函数动态计算时钟周期数

    通过RCU_Clock_Freq_Get()获取实时主频,当前计数值-起始值≥目标周期数时退出

    最大延时36秒(120MHz时2³²/120M)

    毫秒级延时封装

    循环调用delay_us(1000)组合实现

    在业务逻辑中限制使用场景(建议<1ms)

    长延时替代方案:需配合任务调度机制

    寄存器操作关键

    内核寄存器定义在core_cm4.h

    三步使能流程: 1. DEMCR|=1<<24; 2. DWT_CTRL|=1<<0; 3. CYCCNT=0

    M0/M1内核限制:无DWT功能

    精度验证方法

    实际测试5秒延时误差<1%

    需注意: - 下载后需手动复位; - CYCCNT溢出自动归零

    主频适应性:代码通过动态获取主频保持通用性

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值