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,就不做介紹了。
