在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);
}
三、實例,請看下一篇,基於高精度延時的軟件串口模擬