M3中使用DWT进行精确延时(STM32和GD32)

[复制链接]
9635|7
 楼主| sunmeat 发表于 2014-11-10 18:50 | 显示全部楼层 |阅读模式
本帖最后由 sunmeat 于 2014-11-10 18:56 编辑

这个代码由网友@zkcaptain 找到的,未测试版本,但是应该是可行的,和利用systick不占用中断精确延时一个道理,稍后进行测试
  1. #define  DWT_CR      *(volatile u32 *)0xE0001000

  2. #define  DWT_CYCCNT  *(volatile u32 *)0xE0001004

  3. #define  DEM_CR      *(volatile u32 *)0xE000EDFC

  4. #define  DEM_CR_TRCENA                   (1 << 24)

  5. #define  DWT_CR_CYCCNTENA                (1 <<  0)




  6. #define Delayms(msec)         Delayus(msec*1000)  //对于延时毫秒级的只需要定义一个宏

  7. static u32 cpuclkfeq;     //用于保存cpu运行频率,可运行时动态修改



  8. //初始化延时系统,参数为CPU频率

  9. void DelayInit(u32 clk)
  10. {

  11.     cpuclkfeq = clk;
  12. //打开CYCCNT功能,并把计数器清零,最后打开计数器对cpu时钟进行向上计数

  13.     DEM_CR         |=  DEM_CR_TRCENA;

  14. //    DWT_CYCCNT      = 0u;    //根据需要如果调试,或其他程序要使用CYCCNT时注释掉,否则可直接清零

  15.     DWT_CR         |= DWT_CR_CYCCNTENA;

  16. }



  17. //延时函数,参数为需要延时的微秒数
  18. void Delayus(u32 usec)

  19. {

  20.      u32 startts,endts,ts;

  21.   //保存进入函数时的计数器值

  22.      startts = DWT_CYCCNT;

  23.      ts =  usec * (cpuclkfeq /(1000*1000) );        //计算达到所需延时值的cpu时钟数,^-^如果想要更精确此处可以减去运行前面代码所需的时钟数。

  24.      endts = startts + ts;           //计算达到所需延时时间的DWT_CYCCNT计数值,超过32bit所能表达的最大值2的32次方-1是自动绕回丢弃进位

  25.       if(endts > startts)            //判断是否跨越最大值边界

  26.       {

  27.           while(DWT_CYCCNT < endts);        //等到计数到所需延时值的cpu时钟数值

  28.        }

  29.        else

  30.       {

  31.            while(DWT_CYCCNT > endts);       //等待跨域32bit的最大值,2的32次方-1

  32.            while(DWT_CYCCNT < endts);        //等到计数到所需延时值的cpu时钟数值

  33.       }



  34. }

 楼主| sunmeat 发表于 2014-11-10 20:10 | 显示全部楼层
经测试,没有错误,上面的代码复制过程中有个括号有问题,经更正为放在.h和.c文件中。DWT_Delay.h中的代码如下
  1. #ifndef __DWT_DELAYG_H_
  2. #define __DWT_DELAYG_H_

  3. #include "stm32f10x_conf.h"

  4. #define  DWT_CR      *(volatile u32 *)0xE0001000

  5. #define  DWT_CYCCNT  *(volatile u32 *)0xE0001004

  6. #define  DEM_CR      *(volatile u32 *)0xE000EDFC

  7. #define  DEM_CR_TRCENA                   (1 << 24)

  8. #define  DWT_CR_CYCCNTENA                (1 <<  0)




  9. #define Delayms(msec)         Delayus(msec*1000)  //对于延时毫秒级的只需要定义一个宏

  10. void DelayInit(u32 clk);
  11. void Delayus(u32 usec);
  12. #endif

评分

参与人数 1威望 +3 收起 理由
zkcaptain + 3 感谢楼主

查看全部评分

 楼主| sunmeat 发表于 2014-11-10 20:10 | 显示全部楼层
DWT_Delay.c中的代码如下

  1. #include "DWT_Delay.h"



  2. static u32 cpuclkfeq;     //用于保存cpu运行频率,可运行时动态修改



  3. //初始化延时系统,参数为CPU频率

  4. void DelayInit(u32 clk)
  5. {

  6.     cpuclkfeq = clk;
  7. //打开CYCCNT功能,并把计数器清零,最后打开计数器对cpu时钟进行向上计数

  8.     DEM_CR         |=  DEM_CR_TRCENA;

  9. //    DWT_CYCCNT      = 0u;    //根据需要如果调试,或其他程序要使用CYCCNT时注释掉,否则可直接清零

  10.     DWT_CR         |= DWT_CR_CYCCNTENA;

  11. }



  12. //延时函数,参数为需要延时的微秒数
  13. void Delayus(u32 usec)

  14. {

  15.      u32 startts,endts,ts;

  16.   //保存进入函数时的计数器值

  17.      startts = DWT_CYCCNT;

  18.      ts =  usec * (cpuclkfeq /(1000*1000));        //计算达到所需延时值的cpu时钟数,^-^如果想要更精确此处可以减去运行前面代码所需的时钟数。

  19.      endts = startts + ts;           //计算达到所需延时时间的DWT_CYCCNT计数值,超过32bit所能表达的最大值2的32次方-1是自动绕回丢弃进位

  20.       if(endts > startts)            //判断是否跨越最大值边界

  21.       {

  22.           while(DWT_CYCCNT < endts);        //等到计数到所需延时值的cpu时钟数值

  23.        }

  24.        else

  25.       {

  26.            while(DWT_CYCCNT > endts);       //等待跨域32bit的最大值,2的32次方-1

  27.            while(DWT_CYCCNT < endts);        //等到计数到所需延时值的cpu时钟数值

  28.       }



  29. }

评分

参与人数 1威望 +3 收起 理由
zkcaptain + 3 感谢楼主

查看全部评分

陈子建 发表于 2015-1-17 22:02 | 显示全部楼层
这个程序运行的前提有没有区分CPU是使用哪一个时钟呢?是72MHz的主频还是8MHz的?
陈子建 发表于 2015-1-17 22:29 | 显示全部楼层
//我搞错了,这个函数应该是这么用的。
#include "stm32f10x.h"
#include "usart1.h"
#include "DWT_Delay.h"

/*
* 函数名:main
* 描述  :主函数,使用串口打印出数据
* 输入  :无
* 输出  :无
*/
int main(void)
{       
        int i=0;
        int j;
        /* USART1 config 115200 8-N-1 */
        USART1_Config();    //串口配置
        DelayInit(SystemCoreClock);      //延时函数初始化,讲CPU的主频给DelayInit函数,主频在system_stm32f10x.c中
        for(j=0;j<20;j++)               //循环打印20次,每次间隔1m打印一个数后换行
        {
                printf("%d",i);
                printf("\r\n");
                Delayms(1000);
                i=i+1;
        }
}
jpaekeo 发表于 2018-1-15 20:58 | 显示全部楼层
给大神点赞,精神可嘉。
poikjhmng 发表于 2018-1-24 14:51 | 显示全部楼层
能否做一个宏,来了应对不同的主频
lsz318 发表于 2018-5-19 10:21 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

208

主题

2132

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部