《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 模擬設(shè)計(jì) > 業(yè)界動(dòng)態(tài) > 嵌入式里的“延遲”

嵌入式里的“延遲”

2015-05-27

  在版主上學(xué)的年代里,,單片機(jī)課程老師對有著非常深入的了解,如XX指令是單指令周期,,XX指令是雙指令周期,。如果使用了C語言編程,,也要仔細(xì)看生成的匯編代碼然后再調(diào)節(jié)。例如下面的代碼示例:

  功能 延時(shí)(12M 24M)

  誤差 Ms S 5% 10Us 8%-80%

  //24M晶振 延時(shí) n毫秒

  void DelayMs_24M(unsigned int n)

  {

  unsigned int i=0,j=0;

  for(i=0;i

  for(j=0;j<357;j++);

  }

  延遲函數(shù)是通過的兩個(gè)循環(huán)計(jì)算而形成的停機(jī)等待而達(dá)到延遲的目的,。代碼是通過查看由C語言生成的匯編代碼指令——那個(gè)357便是由此計(jì)算出來的,。當(dāng)然,延遲函數(shù)是否精準(zhǔn)也完全取決于那個(gè)357數(shù)字的選擇了。

  單周期指令,,雙周期指令,,數(shù)一數(shù)便可以了?其實(shí)查看匯編代碼沒有這么簡單的,畢竟For循環(huán)也需要系統(tǒng)開銷的,,還有其它比較,,判斷指令什么的。但這一切在IAR for AVR編譯環(huán)境里似乎就簡單多了,。

  在IAR for AVR編譯環(huán)境里,,用戶只需要 #include "intrinsics.h"便可以調(diào)用void __delay_cycles(unsigned long);函數(shù),這個(gè)函數(shù)是系統(tǒng)函數(shù),,其代表著一個(gè)機(jī)器周期,。用戶不再需要計(jì)算匯編語言的指令周期,,不必再細(xì)讀單片機(jī)的操作手冊,,強(qiáng)大的IAR編譯環(huán)境自己就算好了——單片機(jī)發(fā)展到IAR for AVR時(shí)代,也基本代表著匯編退居二線,。由于篇幅的原因,,版主就不再這里為大家帖出代碼示例了。

  在Atmel的8位單片機(jī)AVR系列一統(tǒng)天下的時(shí)候,,ARM內(nèi)核為代表的單片機(jī)在悄然崛起,。不知不覺,以ST公司stm32f103為代表的32位Cortex-M3內(nèi)核的單片機(jī)占據(jù)了市場大部分分額,,各大論壇爭先推出STM32版塊,。

  其中,某位牛人推出的使用systick函數(shù)來完成延遲函數(shù)頗具人氣,。我們來看一下源代碼:

  //初始化延遲函數(shù)

  void delay_init(u8 SYSCLK)

  {

  SysTick->CTRL&=0xfffffffb;//選擇內(nèi)部時(shí)鐘 HCLK/8

  fac_us=SYSCLK/8;

  fac_ms=(u16)fac_us*1000;

  }

  void delay_ms(u16 nms)

  {

  SysTick->LOAD=(u32)nms*fac_ms; //時(shí)間加載

  SysTick->CTRL|=0x01; //開始倒數(shù)

  while(!(SysTick->CTRL&(1<<16))); //等待時(shí)間到達(dá)

  SysTick->CTRL&=0XFFFFFFFE; //關(guān)閉計(jì)數(shù)器

  SysTick->VAL=0X00000000; //清空計(jì)數(shù)器

  }

  牛人的代碼還是非常簡潔的,,使用起來也方便,首先調(diào)用delay_init函數(shù),,然后,,再調(diào)用delay_ms()函數(shù)。這個(gè)延遲函數(shù)也是非常準(zhǔn)確的,,因?yàn)槠涫褂昧藛纹瑱C(jī)的硬件定時(shí)器模塊,。在STM32F103高達(dá)72MHz的主頻,優(yōu)化的指令集系統(tǒng)下,,系統(tǒng)的開銷完成可以忽略,。筆者也將其成功應(yīng)用于單總線通訊方式的數(shù)字溫度采集傳感器18B20芯片上,測試良好,。

  寫到這里,,筆者已經(jīng)介紹了三種延遲函數(shù),它們?nèi)齻€(gè)都有一個(gè)共同的特點(diǎn):阻塞延遲函數(shù)——在“等待”延遲函數(shù)到來的時(shí)候里,,單片機(jī)并沒有處理其它有用,,有意義的事情,,而是停機(jī)在等待著時(shí)間的到來。對于我們要處理大量數(shù)據(jù)的單片機(jī)系統(tǒng)來說,,這個(gè)劣勢有時(shí)就很難接受的,。那么我們要怎么解決呢?

  我們?nèi)匀灰許TM32F103為例,仍然要使用強(qiáng)大的定時(shí)器,,這里我們再次選用systick定時(shí)器,。我們首先要初始化ST單片機(jī)systick,其每1ms進(jìn)入中斷一次,,代碼如下:

  if (SysTick_Config(72000)) //參數(shù)為系統(tǒng)時(shí)鐘的向上溢出值,,此配置為72000,即1ms中斷一次

  {

  /* Capture error */

  while (1);

  }

  之后,,我們在systick的中斷函數(shù)里計(jì)數(shù),,示例代碼如下:

  void SysTick_Handler(void)

  {

  if(gCntLed[0] > 0)

  {

  gCntLed[0]--;

  }

  else

  {

  gCntLed[0] = 0;

  }

  }

  從上面代碼可以清楚看到,每1ms,,gCntLed[0]將計(jì)數(shù)值減1,,直到為0時(shí)止。而main函數(shù)里,,就要不斷的查詢這個(gè)gCntLed[0]的值,,當(dāng)未達(dá)到0值時(shí),就去做別的事情,,而查詢到0值時(shí),,再去處理自己的事情,示例代碼如下:

  while(1)

  {

  if(gCntLed[0] == 0)

  {

  LedToggle(0);

  gCntLed[0] = 200;

  }

  KeyScan();

  }

  通過未阻塞的延遲函數(shù),,我們實(shí)現(xiàn)了LED燈每隔200ms閃爍一次的效果,,與其同時(shí),我們也沒有停止不斷掃描按鍵,?!@就是非阻塞延遲函數(shù)的強(qiáng)大優(yōu)勢。非阻塞式延遲函數(shù)還主要應(yīng)用于嵌入式操作系統(tǒng)函數(shù)里,,喜歡的網(wǎng)友可以自己查看相關(guān)函數(shù),。

  隨著時(shí)代的進(jìn)步,能源的問題逐漸突出出來,。剛剛筆者介紹的幾種函數(shù)都是在不停的“運(yùn)行”,,看似什么事情也沒有做,但是單片機(jī)確實(shí)在全力的“奔跑”,,這與當(dāng)前節(jié)碳減排,,低功耗格格不入。MSP430算得上是低功耗的代表了,其延遲函數(shù)可以拿來借鑒一下,。

  在MSP430的低功耗設(shè)計(jì)中,,阻塞式延遲函數(shù)是基本不用的——因?yàn)楣奶螅醋枞窖舆t函數(shù)是必備條件,。設(shè)計(jì)主要思想是,,定時(shí)讓MSP430從睡眠模式里“醒”過來,查看一下當(dāng)前的時(shí)間與狀態(tài),,然后再做決定如何處理,。換句話說,上面的示例就變成了,,MSP430每1ms準(zhǔn)時(shí)醒來一次,,處理了一下gCntLed[0]的值,然后又查看了一下,,如果非0值,,則繼續(xù)“睡”去了;如果恰好是0值,則再干一會兒事情……這里,,MSP430大部分時(shí)間里就處于了低功耗的睡眠模式,,自然也就節(jié)能了。


本站內(nèi)容除特別聲明的原創(chuàng)文章之外,,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點(diǎn),。轉(zhuǎn)載的所有的文章,、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有,。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認(rèn)版權(quán)者,。如涉及作品內(nèi)容、版權(quán)和其它問題,,請及時(shí)通過電子郵件或電話通知我們,,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失,。聯(lián)系電話:010-82306118,;郵箱:[email protected]