首页 » 科学 » STM32系列(HAL库)—Delay函数重写_函数_准时器

STM32系列(HAL库)—Delay函数重写_函数_准时器

萌界大人物 2024-12-28 18:00:27 0

扫一扫用手机浏览

文章目录 [+]

HAL库中的Delay函数的思路是,ARM内核会供应一个32位的滴答定时器(即Systick),利用这个定时器设置成1ms产生一次中断,然后Firmware里面有一个32位的变量,通过查询该变量的值,确定韶光到底过了多久。
由于该函数的核心思想是中断,ARM的中断是支持中断优先级以及中断嵌套的,因此,该函数的中断抢占优先级和相应优先级都要设置为最高,这样,其他函数或者中断才有机会调用该函数。

不过,在我利用过程中,我觉得这个函数并不好用,首先,你须要特殊关注在中断处理函数调用的情形,中断优先级是否设置精确?然后,便是不管我有没有调用HAL_Delay函数,实际这个中断每1ms都会产生一个中断,这是一个极大的资源摧残浪费蹂躏。

STM32系列(HAL库)—Delay函数重写_函数_准时器 STM32系列(HAL库)—Delay函数重写_函数_准时器 科学

因此,我对HAL_Delay函数重写,并且增加了HAL_Delayus函数,这样ms级别和us级别的延时延时都有了。

STM32系列(HAL库)—Delay函数重写_函数_准时器 STM32系列(HAL库)—Delay函数重写_函数_准时器 科学
(图片来自网络侵删)

首先,我的思路坚持不变,还是用滴答定时器(Systick)。
Systick的寄存器可以在ARM的官网下载Cortex-M3 Devices Generic User Guide,由于这个定时器是内核自带的。

Systick Ctrl寄存器

SysTick Reload寄存器

SysTick Cur寄存器

HAL_Delay(ms级别的延时函数)思路比较大略,每次调用HAL_Delay函数时,启动Systick,将Systick->Ctrl最低位设置为1,纵然能Systick,其他位默认,这样就不用启动中断。
之后在Systick->LOAD设置为要计数的值,(Clock源为HCLK/8,我的MCU为72M主频,因此最大为9MHz),然后利用while或者for循环查询Systick->CTRL第16位即可。

HAL_DelayUs(us级别的延时函数)基本思路和上面同等,不过,1,2,3us的时候,由于数值比较小,因此,须要重新校准。

代码如下所示:

//延时函数,Delay为延时的ms数void HAL_Delay(uint32_t Delay){uint32_t temp,ctrl_flag;for(temp=0;temp<((Delay>>9)+1);temp++){ //因此Systick定时器时钟为9M,因此计数器的值不能太大,须要分外处理一下,以512ms为一个周期。
如果多于512ms,那么先计数512ms,之后计数值减512msif(temp ==( Delay>>9)){SysTick->LOAD = 9000(Delay&(0x1FF))-20; //减去的20,为校准值,可以根据自己的不同主频,进行调度,我这边72M主频}else{SysTick->LOAD = 9000512; //512ms,9MHz时钟}SysTick->VAL = 0x00;//打消计数器SysTick->CTRL = 0x01;//开始计数 //查询是否计数结束do{ctrl_flag = SysTick->CTRL;}while((ctrl_flag&0x10000)!=0x10000);SysTick->CTRL = 0x00;//关闭滴答定时器}}//延时函数,DelayUs为延时的us数,小于512ms,如果大于512ms,请利用HAL_Delay函数void HAL_DelayUs(uint32_t DelayUs){uint32_t temp;switch(DelayUs){case 1: //1us,只须要几个NOP调度时钟即可,主频不同,这个须要调度__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();break;case 2:SysTick->LOAD =0x04;//2us,计数值须要进行微调SysTick->VAL = 0x00;SysTick->CTRL=0x01;do{temp = SysTick->CTRL;}while(((temp&(0x10000))!=0x10000));SysTick->CTRL = 0x00;break;case 3:SysTick->VAL = 0x00;SysTick->LOAD =0x0D;//3us,计数值须要微调SysTick->CTRL=0x01;do{temp = SysTick->CTRL;}while(((temp&(0x10000))!=0x10000));SysTick->CTRL = 0x00;break;default:SysTick->LOAD = ((DelayUs-1)<<3)+DelayUs-6; //大于3us之后的值,利用通用调度,SysTick->VAL = 0x00;SysTick->CTRL=0x01;do{temp = SysTick->CTRL;}while(((temp&(0x10000))!=0x10000));SysTick->CTRL = 0x00;break;}}

通过上述函数即可实现延时函数,其余提醒一点,HAL库中的HAL_Delay函数定义前面有“_weak”关键字,因此,只须要在main.c文件中,直接定义HAL_Delay即可,HAL库中用到的HAL_Delay函数都将调用我们自己的函数。

其余须要解释一点儿,便是STM32CubeIDE自动使能了Systick,须要在Main.c函数中将其Disable。
如下代码在HAL_Init()之后调用该函数即可

void Systick_DeInit(){SysTick->CTRL = 0x00;}

当然,不管是HAL库自带的延时函数,还是我们这篇文章重写的延时函数,都是串行的办法,便是说,调用延时函数时,MCU是不实行其他指令,只在while循环或者for循环中一次又一次的查询。

那么,如果并行的实行呢,便是说当调用延时函数时,MCU实行其他任务呢?当然可以用定时器来做,不过MCU定时器资源是有限的,那么如何用一个定时器可以实现多个延时函数并行实行呢?我将会不才一篇文章进行阐述。

标签:

相关文章

ITPlay,创新科技的魅力与未来展望

在信息技术的飞速发展下,IT Play作为一种全新的创新模式,正在逐渐改变着我们的生活和工作方式。本文将从IT Play的定义、发...

科学 2024-12-31 阅读0 评论0

ITGD包包,时尚与创新交织的潮流之作

在时尚界,潮流的演变总是令人眼花缭乱。在这其中,有一款名为ITGD的包包,以其独特的魅力和卓越的品质,成为时尚达人们争相追捧的对象...

科学 2024-12-31 阅读0 评论0

ITXbox,引领科技潮流的智能硬件巨头

随着科技的飞速发展,智能硬件逐渐成为人们生活中的重要组成部分。在这个领域,ITXbox作为一家领军企业,凭借其卓越的产品品质和领先...

科学 2024-12-31 阅读0 评论0