A001 番外篇 如何處理需要等很久的外部呼叫

A001 番外篇  如何處理需要等很久的外部呼叫


        有個FB朋友私我,問我說,要呼叫一個DS18B20 溫度計,但是精度要很高的話,會被哪個感測器拉住很長的時間,導致按鈕的掃描繪被嚴重延遲那要怎麼做?


其實Arduino 很多的Lib 的Example 在設計的時候都是以你只要跑一個功能來設計的,這樣使用的人會比較好了解怎麼去使用那個Lib. 但是如果使用者要同時呼叫很多不同的Lib 的時候就會有撞牆的問題。

以上述的DS18D20 溫度感測器來說,Loop 裡面如果週期性的要取得溫度,然後更新,同時還要接收使用者的按鈕輸入時,就很容易遇到在讀取溫度的時候,按鈕沒法按的問題,為何?? 因為DS18B20 進行轉換溫度的時候,不能即時回應,要等待一陣子才行。


這就會像這樣,你去餐廳點餐。餐點要現做,於是你點餐後只能在那邊等老闆煮好。。
所以你就只能在那邊等,哪裡也不能去。。。。。



但是,如果您在點完餐之後,稍微了解一下老闆多久之後可以煮好,那從點餐到煮好的這段時間,您就可以跑去做你自己的事情了!!


所以這樣怎麼實做最簡單,假設外部的設備需要10 秒才能回應,是否就要停止運作10秒等它呢?


這裡使用simpleTimer 這個好玩的Lib 來做解釋。

假設我們要點一個LED 燈,十秒之後要滅掉,一般最暴力的大概就是這樣

loop(){

digitalWrite(LED_PIN, HIGH);
delay(100000);
digitalWrite(LED_PIN, LOW);


}



不過這樣做,所有的時間都花在delay 上面了,啥事也不能做,所以簡單的調用一下SimpleTimer 的 setTimeout(unsigned long d, timer_callback f) 就可以簡單的處理這種需要等待很久時間後才需要進行下一個動作的呼叫。

簡單的範例程式碼如下 ,大致來說就是,程式設定一個定時鬧鐘,鬧鐘到了就去做我們規定的事情。

下面的範例是設定一個10 秒後會自動把LED關掉的鬧鐘。所以使用者只要把燈開起來之後,10秒後鬧鐘就會自己起來把LED 給關了。

在Loop() 中,因為要讓鬧中持續的計時,所以要持續呼叫 timer.run(); 這樣就可以確保鬧鐘內部的時間計算正確。

對了,如果您的Loop() 裡面也用到很多的delay ,會不會影響鬧鐘的計算精確度呢? 下次我們再來討論。


/*
   SimpleTimerAlarmExample.ino

   Based on usage example for Time + TimeAlarm + SimpleTimer libraries

   A timer is called every 15 seconds
   Another timer is called once only after 10 seconds
   A third timer is called 10 times.
   Toggle an IO pin 100mSec LOW, 900mSec HIGH

*/

#include <SimpleTimer.h>

// There must be one global SimpleTimer object.
// More SimpleTimer objects can be created and run,
// although there is little point in doing so.
SimpleTimer timer;

// Pin to toggle
const unsigned int PIN = 13;


void turnLedOff(void) {
  Serial.println("\n\n\n\n 哈哈關燈了..........");
  digitalWrite(PIN, LOW);

}


void turnLedOn() {
  Serial.println("開燈 .......... ");
  Serial.println("10 秒後自己會關燈,不用理會 .......... ");
  digitalWrite(PIN, HIGH);
  timer.setTimeout(10000,turnLedOff); //10000 = 10 秒後會呼叫 turnLedOff 這個Function 

}



void setup() {
  Serial.begin(9600);

  // welcome message
  Serial.println("SimpleTimer 使用展示");
  pinMode(PIN, OUTPUT ); /// 設定LED 腳,我是用UNO 

   
  turnLedOn();   

}

void loop() {
  // this is where the "polling" occurs
  timer.run();/// 這個要讓他呼叫喔

  /// 做自己的事情..... 



}




所以,像剛剛哪個DS18B20 的問題,要從改寫原來的驅動程式來著手,配合上面這小結simpleTime 的鬧鐘來做。

要有一個"開始轉換" 的 function,還要有一個取得溫度轉換結果的function。

至於中間轉換需要的延遲時間,就去做自己平常要做的程式就好了。大概會像這樣 :

讀取溫度(){

 讀取溫度呼叫();

}



開始轉換(){

啟動轉換呼叫();
 timer.setTimeout(10000,turnLedOff); //10000 = 10 秒後會呼叫 turnLedOff 這個Function 


}


loop(){


/// 某個轉換周期到了
開始轉換()

///// 做自己的事 ................. 


}

留言

這個網誌中的熱門文章

002 如何用4個圖面拆解小設備需求( 說明 )

001 使用Arduino生態建構小型設備程式框架