delay下面的主要函数是delay_init,delay_us和delay_ms。
非OS的时候,可以很简单
void delay_init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us=SYSCLK/8; //每个us需要运行21个时间片 fac_ms=(u16)fac_us*1000;// }
比如系统的频率是168M,SYSCLK传入的是168,那么systick就是168M/8=21M,那么每us就需要systick运行168/8个时间片。
因为不需要兼容OS,所以可以肆意的对systick计数器进行清零。OS的时候,systick计数到会触发中断,所以不能随便对SysTick->LOAD和SysTick->VAL进行操作。
void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; // 那么多延时需要的时间片 SysTick->VAL=0x00; //计数器清零 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; // do { temp=SysTick->CTRL; } while((temp&0x01)&&!(temp&(1<<16)));// 查询是不是计数到了 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; // SysTick->VAL =0X00; // }
通过查询是systick计数器的寄存器状态,确认计数是否到了。
有OS的时候,要兼容OS和原本的delay_us函数。
void delay_init(u8 SYSCLK) { u32 reload; SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); //没有分频 168M fac_us=SYSCLK; // 168个时间片 reload=SYSCLK; // reload*=1000000/configTICK_RATE_HZ; //168*1000000/1000// fac_ms=1000/configTICK_RATE_HZ; // SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;// 开启中断 SysTick->LOAD=reload; //赋重载值 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启systick }
和之间的非OS相比,reload在初始化被定义,并复制给LOAD。因为非OS的时候,systick只在延时的时候被使用,用来计算时间片。而OS运行的时候,需要一个心
跳,要一直运行的,所以就用systick,systick的频率是168M,reload=168M/1000,所以systick每次都数1ms。每次计数到,都会触发SysTick_Handler中断函数,OS
会在里面做任务切换等等事情。
然后delay_us这个函数,也和之前不一样了。之前可以去修改systick的值来实现固定时间的延时。现在只能通过设置一个tcnt的变量,通过读取systick->VAL的值,来
确定多少us的延时。
void delay_us(u32 nus) { u32 ticks; u32 told,tnow,tcnt=0; u32 reload=SysTick->LOAD; // ticks=nus*fac_us; // told=SysTick->VAL; //¸ while(1) { tnow=SysTick->VAL; if(tnow!=told) { if(tnow<told) tcnt+=told-tnow; // else tcnt+=reload-tnow+told; told=tnow; if(tcnt>=ticks)break; // } }; }
delay_ms都是类似的,基于delay_us,就不做介绍了。