基於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);
}

三、實例,請看下一篇,基於高精度延時的軟件串口模擬

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