基于CYCCNT时钟周期计数器的高精度延时接口

在MCU资源不足时,我们经常会用普通IO模拟串行时序,例如:i2c,uart等。此时,就会需要一个比较精确一点的延时来提供通讯成功率。STM32MCU调试单元提供了一个时钟周期计数器,利用该计数器我们可以实现一个高精度的延时计时器。

概念:频率fclk(cpu时钟)与时间的关系,t=1/fclk,例如:系统时钟为72MHZ,那么一个时钟周期的执行时间为:1/72(us),也就是72个时钟周期的执行时间为1us,这样就可以实现一个us级别的高精度延时。假设,uart的波特率为9600,那么每接收一位数据之间的间隔为1/9600≈104us,那么,只需延时104us*72个时钟周期就可以精确的接收串口数据,共地情况下,误码率基本上为0。

下面为delay模块的源文件,仅供参考。

一 delay.h


#ifndef _DELAY_H
#define _DELAY_H


#include "stm32f1xx.h"




#define  CYCCNT_US			(SystemCoreClock/1000000)



void delay_init(void);

uint32_t get_cyccnt(void);

void udelay(uint32_t us);

void mdelay(uint32_t ms);

void sdelay(uint32_t s);

/* 延时指定个时钟周期数 */
void delay_cyc(uint32_t cyc);


#endif

二、delay.c


#include "delay.h"



                                                           


#define  DWT_CR      *(uint32_t *)0xE0001000           //数据观察点和跟踪控制寄存器
#define  DWT_CYCCNT  *(uint32_t *)0xE0001004           //DWT当前PC采样器周期计数寄存器
#define  DEM_CR      *(uint32_t *)0xE000EDFC           //调试异常和监控控制寄存器
#define  DBGMCU_CR   *(uint32_t *)0xE0042004           //MCU调试模块控制寄存器,详细内容参考《stm32中文参考手册》调试支持(DBG)章节,747页


#define  DEM_CR_TRCENA                   (1 << 24)      //DEM_CR调试异常和监控控制寄存器的Bit24,该位必须为1,使能调试和跟踪模块的使用

#define  DWT_CR_CYCCNTENA                (1 <<  0)      //置为DWT_CR控制寄存器的CYCCNTENA位,使能DWT_CYCCNT计数器





void delay_init(void)
{  
    DEM_CR         |= (uint32_t)DEM_CR_TRCENA;         /* Enable Cortex-M3's DWT CYCCNT reg. 使能调试和跟踪模块的使用                  */
    DWT_CYCCNT      = (uint32_t)0u;                    //初始化当前PC采样器周期计数器的计数值为0
    DWT_CR         |= (uint32_t)DWT_CR_CYCCNTENA;     //使能DWT_CYCCNT计数器。如果不使能,则计数器不执行计
                                                        //数操作,因此不会产生PC采样或CYCCNTENA事件。在正常
                                                        //使用时,CYCCNT计数器应由调试器初始化为0。
}

uint32_t get_cyccnt(void)
{
    return (uint32_t)(DWT_CYCCNT);
}


void udelay(uint32_t us)
{
    uint32_t udly = (uint32_t)(DWT_CYCCNT) + us*CYCCNT_US;
    
	while((uint32_t)(DWT_CYCCNT) < udly);
}

void mdelay(uint32_t ms)
{
	udelay(ms *1000);
}

void sdelay(uint32_t s)
{
	udelay(s*1000000);
}

void delay_cyc(uint32_t cyc)
{
    uint32_t cycdly = (uint32_t)(DWT_CYCCNT) + cyc;
    
	while((uint32_t)(DWT_CYCCNT) < cycdly);
}

三、实例,请看下一篇,基于高精度延时的软件串口模拟

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章