对于STM32系列的延时函数有着不同的写法,本章将给大家带来最简单的延时到最精准延时函数的各种写法及原理。
在STM32系列中要学会用好systick定时器,这很重要
一.普通延时函数
原理:
用C中累加或者累减的方法,到一定条件后就退出。
好处:
好写,用for循环或者while循环,不用去理解各种有关底层硬件的寄存器。
坏处:
延时不精准,误差大,让CPU持续空跑,大大浪费CPU资源。
void delay(uint16 i)
{
#if 0
while(i--)
{}
#endif
for(int j=0;j<i;j++)
{}
}
二.定时器计数
在32中,使用定时器的地方很多,所以对于32中各种稀缺的外设资源极其珍贵,用好各种外设对于小白来说是关键的一步。
原理:
采用C中累加原理,选定某一定时器,通过计数器来产生中断。
好处:
可达到精准延时,但会使CPU在定时器中持续累加或累减,占用CPU资源。
这里随便举的一个例子
void TIM4_Init(u16 ar,u16 rs)
{
TIM_TimeBaseInitTypeDef TIM_InitStrue;
NVIC_InitTypeDef NVIC_InitStrue;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//使能定时器时钟
TIM_InitStrue.TIM_Period=ar;//自动装载值
TIM_InitStrue.TIM_Prescaler=rs;//预分频系数的设置
TIM_InitStrue.TIM_CounterMode=TIM_CounterMode_Up;
TIM_InitStrue.TIM_ClockDivision=TIM_CKD_DIV1;//设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseInit(TIM4,&TIM_InitStrue);//初始化定时器,对定时器进行配置
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);//开启定时器中断
NVIC_InitStrue.NVIC_IRQChannel=TIM4_IRQn;
NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStrue.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStrue);//初始化中断,设置中断的优先级
TIM_Cmd(TIM4,ENABLE);//使能定时器
}
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET)
{
LED1=!LED1;
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//清除中断标志位
}
}
三、Systick定时器
关于滴答定时器,我的理解为可以替代所有的定时器中有关涉及到时间的问题配置,可以让定时器更好的配合其他功能使用,而定时器中的计数器寄存器可以用于PID之类,更好的控制精度。
在此处介绍两种有关Systcik定时器的使用方法
(1).同样运用CPU持续在滴答定时器进行计数
void delay_us(u32 i)
8 {
9 u32 temp;
10 SysTick->LOAD=9*i; //设置重装数值, 72MHZ时
11 SysTick->CTRL=0X01; //使能,减到零是无动作,采用外部时钟源
12 SysTick->VAL=0; //清零计数器
13 do
14 {
15 temp=SysTick->CTRL; //读取当前倒计数值
16 }
17 while((temp&0x01)&&(!(temp&(1<<16)))); //等待时间到达
18 SysTick->CTRL=0; //关闭计数器
19 SysTick->VAL=0; //清空计数器
20 }
void delay_ms(u32 i)
8 {
9 u32 temp;
10 SysTick->LOAD=9000*i; //设置重装数值, 72MHZ时
11 SysTick->CTRL=0X01; //使能,减到零是无动作,采用外部时钟源
12 SysTick->VAL=0; //清零计数器
13 do
14 {
15 temp=SysTick->CTRL; //读取当前倒计数值
16 }
17 while((temp&0x01)&&(!(temp&(1<<16)))); //等待时间到达
18 SysTick->CTRL=0; //关闭计数器
19 SysTick->VAL=0; //清空计数器
20 }
(2).Systick定时器自动计数,到达预初始值后产生中断,CPU进行响应处理事件。
void SysTick_Init(void)
{
if(SysTick_Config(SystemCoreClock/1000)) ;
{
while(1);
}
}
其中SysTick_Config()的参数意思为要计数到多少产生一个中断,换句话说就是多少ms/us产生中断
关于计算ms/us的问题,可以用时间与频率的计算公式
fosc=1/T T=1/fosc ,fosc为系统的频率
如果STM32时钟频率为:72MHz,每次的时间为:T=1/72MHz。1秒钟为:1/(每次的时间)=1/(1/72MHz)=72 000 000次。1MHz是:1000 000
反过来讲。SysTick_Config(72000)代表:72000(1/72MHz)=1/1000=1(ms)。即定时为1ms。
如果需要1S则,可以通一设置一个全局变量,然后定初值得为1000,这样,每个systick中断一次,这个全局变量减1,减到0,即systick中断1000次,时间
为:1ms1000=1S。从而实现1S的定时。
关于程序上的涉及延时或定时,则需采用一个外部的全局变量
volatile uint32_t Number;
有关volatile的作用,若有不知道的,请自行回看C基础知识。
void Delay_ms(uint16_t nTime)
{
Number = nTime;
//使能系统滴答定时器
while(Number !=0);
}
此时还需要在有关延时文件中进行声明extern
最后,中断函数编写
void SysTick_Handler(void)
{
if (Number != 0x00)
{
Number--;
}
}
此时要注意的是需要更改固件库中自带的systick中断函数,将其注释。