STM32 HAL 庫(kù) uS 延時(shí)的 3 種實(shí)現(xiàn)方式
實(shí)驗(yàn)?zāi)繕?biāo)
- 使用普通定時(shí)器實(shí)現(xiàn) us 延時(shí)
- 使用 Systick 功能實(shí)現(xiàn) us 延時(shí)
- 使用 for 循環(huán)實(shí)現(xiàn) us 延時(shí)
1、普通定時(shí)器實(shí)現(xiàn) us 延時(shí)
1.1、外部時(shí)鐘選擇
我板子上焊接的是 8M 的晶體,如果小伙伴們的板子上不是 8M,根據(jù)自己的晶振頻率配置即可,左側(cè)圈 1 中,可以根據(jù)自己的晶體頻率,輸入相應(yīng)的頻率,經(jīng)過(guò)分頻、倍頻后,系統(tǒng)時(shí)鐘頻率設(shè)置為最大,168MHZ,APB1 的時(shí)鐘頻率為 84MHZ,也是后面用到的 TIM2 掛載的時(shí)鐘源的頻率。
1.2、TIM2 基礎(chǔ)配置
時(shí)鐘及定時(shí)器的配置就完成了,下面是 cubemx 生成工程時(shí)的幾項(xiàng)設(shè)置,建議大家勾選。首先是 HAL 庫(kù)是否需要包含所有的文件,我們選擇只需要用到的文件,這樣可以縮短工程編譯時(shí)間,只編譯我們用到的庫(kù)文件,接著是勾選為每個(gè)外設(shè)生成單獨(dú)的.c .h 文件,這個(gè)建議一定要勾選,會(huì)使代碼結(jié)構(gòu)非常清晰,第三點(diǎn)就非常的重要了,用過(guò) cubemx 的小伙伴是否遇到過(guò)每次重新生成工程后,之前添加的文件都不見(jiàn)了,這一項(xiàng)勾選之后,會(huì)保留用戶文件。
然后是編譯器選擇,可以根據(jù)自己喜歡的 IDE 選擇,我選擇的是 KEIL5。
至此,配置工作就完成了,生成工程就可以了。
1.3、代碼實(shí)現(xiàn)
/*
普通定時(shí)器實(shí)現(xiàn)us延時(shí)
*/ void user_delaynus_tim(uint32_t nus) {
uint16_t differ = 0xffff-nus-5; //設(shè)置定時(shí)器2的技術(shù)初始值 __HAL_TIM_SetCounter(&htim2,differ); //開啟定時(shí)器 HAL_TIM_Base_Start(&htim2); while( differ<0xffff-5)
{
differ = __HAL_TIM_GetCounter(&htim2);
}; //關(guān)閉定時(shí)器 HAL_TIM_Base_Stop(&htim2);
}
/*
普通定時(shí)器實(shí)現(xiàn)ms延時(shí),可直接使用HAL庫(kù)函數(shù)HAL_delay()
*/ void delay_ms_tim(uint16_t nms) {
uint32_t i; for(i=0;i1000);
}
1.4、實(shí)現(xiàn)效果
通過(guò)延時(shí)翻轉(zhuǎn) IO,邏輯分析儀測(cè)試延時(shí)時(shí)間,分別測(cè)試了延時(shí) 20us,500ms,下面是測(cè)量圖:
2、Systick 功能實(shí)現(xiàn) us 延時(shí)
2.1、Systick介紹
CM3與CM4包含一個(gè)系統(tǒng)計(jì)數(shù)器SysTick,是一個(gè)24位倒計(jì)數(shù)定時(shí)器,當(dāng)計(jì)數(shù)到0 時(shí),將從RELOAD寄存器中自動(dòng)重裝載定時(shí)初值,只要把它在SysTick->CTRL中的使能位清除,則一直存在。寄存器介紹:
相應(yīng)代碼在core_cm4.h中
/**
\brief Structure type to access the System Timer (SysTick).
*/ typedef struct
{
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ } SysTick_Type;
SysTick控制及狀態(tài)寄存器(0xE000_E010): 該寄存器第0位:表示SysTick使能位,0表示關(guān);1表示開;SysTick_CTRL_ENABLE_Mask;第1位:表示SysTIck中斷使能位,0-表示關(guān)閉中斷;1-打開中斷;SysTick_CTRL_TICKINT_Mask 第2位:表示時(shí)鐘源選擇位,0,表示HCLK/8;1表示HCLK作為時(shí)鐘源;SysTick_CTRL_SOURCE_Mask; 第16位:表示計(jì)數(shù)比較標(biāo)志,如果上次讀取本寄存器,計(jì)算到了0,則該位置1,如果讀取該位,該位將自動(dòng)清零。SysTick的LOAD寄存器:為遞減計(jì)數(shù),是24位寄存器,最大值為0xFFFFFF;SysTick的VAL寄存器:24位寄存器,讀取時(shí)返回當(dāng)前計(jì)數(shù)值,寫它則使其清零,同時(shí)會(huì)清零CTRL寄存器中的COUNTFLAG標(biāo)志。2.2、代碼實(shí)現(xiàn)
/*
Systick功能實(shí)現(xiàn)us延時(shí),參數(shù)SYSCLK為系統(tǒng)時(shí)鐘
*/ uint32_t fac_us; void HAL_Delay_us_init(uint8_t SYSCLK) {
fac_us=SYSCLK;
} void HAL_Delay_us(uint32_t nus) {
uint32_t ticks;
uint32_t told,tnow,tcnt=0;
uint32_t reload=SysTick->LOAD;
ticks=nus*fac_us;
told=SysTick->VAL; while(1)
{
tnow=SysTick->VAL; if(tnow!=told)
{ if(tnowelse tcnt+=reload-tnow+told;
told=tnow; if(tcnt>=ticks)break;
}
};
}
2.3 實(shí)現(xiàn)效果
通過(guò)延時(shí)翻轉(zhuǎn)IO,邏輯分析儀測(cè)試延時(shí)時(shí)間,測(cè)試了延時(shí) 20us,下面是測(cè)量圖:
for循環(huán)實(shí)現(xiàn)us延時(shí)
這個(gè)方法比較接地氣,采用NOP空語(yǔ)句實(shí)現(xiàn),具體實(shí)現(xiàn)起來(lái)最好是看匯編代碼,有興趣的小伙伴可以研究研究,直接上代碼:/*
for循環(huán)實(shí)現(xiàn)延時(shí)us
*/ void for_delay_us(uint32_t nus) {
uint32_t Delay = nus * 168/4; do {
__NOP();
} while (Delay --);
}
實(shí)現(xiàn)效果:通過(guò)延時(shí)翻轉(zhuǎn)IO,邏輯分析儀測(cè)試延時(shí)時(shí)間,測(cè)試了延時(shí) 20us,下面是測(cè)量圖:
本次要分享的內(nèi)容就要結(jié)束啦,希望對(duì)us延時(shí)有疑惑的小伙伴有幫助,實(shí)現(xiàn)方法不止這些,暫時(shí)就分享這3種。
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!