有很多方法可以实现微秒延时,我也仅仅刚学一个月,分享一下自己的理解,这里是大神的方法:
原文链接:https://blog.csdn.net/Firefly_cjd/article/details/106709259
我们来看看下面这个方法:
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000000/8*nus;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
比较大神的代码,我这里采用HAL库来实现,没有找到这段内容:RCC_Clocks.HCLK_Frequency,
这代表HCLK的时钟频率,SysTick 8分频,所以后面除以8;
我用的是STM32cubeMX直接生成初始化代码,在这里直接用 HAL_RCC_GetHCLKFreq(void)来代替RCC_Clocks.HCLK_Frequency;
把得到的值赋给重装载值寄存器。
函数在HAL库文件stm32g4xx_hal_rcc.c(我这里用的是G4的芯片)
/**
* @brief Return the HCLK frequency.
* @note Each time HCLK changes, this function must be called to update the
* right HCLK value. Otherwise, any configuration based on this function will be incorrect.
*
* @note The SystemCoreClock CMSIS variable is used to store System Clock Frequency.
* @retval HCLK frequency in Hz
*/
uint32_t HAL_RCC_GetHCLKFreq(void)
{
return SystemCoreClock;
}
下面就是操控相应的寄存器,我们重点说控制寄存器:
首先是清空寄存器,定时器使能
SysTick->CTRL=0X01:这里就第0位置位,使能了定时器。
接下来在 do while()循环中不断读取CTRL寄存器,当前值寄存器(VAL)从设定的重装载值递减到0后,CTRL寄存器的第16位置位,(!(temp&(1<<16))表达式为假,此时就会跳出循环,延时结束,清空计数器,关闭定时器。
下面我们验算一下:
假设我们 HCLK 频率 为 16 MHz 并且 8分频,nus为延时微秒
首先算出自动重装载值: 16000000/ 8 /1000000 *nus ==2*nus;
SysTick->LOAD = HAL_RCC_GetHCLKFreq()/1000000/8*nus;
清空计数值,使能定时器:
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
进入循环: 因为SysTick时钟频率为16000000/8 =2000000;他的计数器递减周期为 1/2000000
,所以从自动重装载值递减到0 用时:2*nus;*1/2000000 (s)=nus (us),递减到0后跳出循环,延时完成。