2015年9月9日 星期三

Arduino 的時間函式

做完 Arduino UART 串列埠測試後, 覺得對基本的函式了解不夠, 所以就從時間函式開始做個詳細的測試. 以下都使用小巧輕便的 Nano 實驗.

Arduino 的時間函式有如下三個 :

一. millis() :

此函式會傳回從開機到現在的毫秒數, 無參數, 傳回值為 unsigned long, 故最大值為  4294967295 毫秒, 即 4294967.295 秒, 換算成天數為 4294967.295/86400=49.71027 天, 即約 50 天就會重新歸零.

測試程式如下 :

unsigned long time;
void setup() {
  Serial.begin(9600);
  }

void loop() {
  time=millis();
  Serial.println(time);
  }

執行後開啟串列埠監視視窗, 會看到數字飛快地往下跑, 觀察這些數字可發現差額約為 9~10 ms, 亦即 loop() 函式執行一圈大約為 0.01 秒 (100Hz), 一秒鐘可以跑 100 圈.

2054497
2054507
2054516
2054525
2054535
2054544
2054553

二. micros() :

此函式會傳回從開機到現在的微秒數, 也就是 millis() 的千分之一. 無參數, 傳回值為 unsigned long, 故最大值為  4294967295 微秒, 即 4294.967295 秒, 換算成分鐘數為 4294.967295/60=71.583 分, 即約 72 分鐘就會重新歸零.

測試程式如下 : 

unsigned long time;
void setup() {
  Serial.begin(9600);
  }

void loop() {
  time=micros();
  Serial.println(time);
  }

擷取串列埠輸出資料, 差額為 9360, 即 9.36ms, 似乎較 millis() 精確些.

2429604
2438964
2448324
2457684
2467044
2476404
2485764

三. delay(ms)

暫停程式執行, 傳入參數是型態為 unsigned long 之毫秒數, 無傳回值.

測試程式 :

nsigned long time;
void setup() {
  Serial.begin(9600);
  }

void loop() {
  time=millis();
  delay(1000);
  Serial.println(time);
  }

我們在呼叫 millis() 後加了 delay(1000) 來延遲 1 秒再往下執行, 結果序列埠輸出如下 :

0
999
1999
3000
4000
5000
6000
7001
8001
9000
10001
11001
12002
13002
14003
15002
16003

可見迴圈所耗時間幾乎完全被 delay() 主宰了. 


此函式是延遲指定之微秒數, 但是與 delay() 不同的是, 傳入參數類型為 unsigned int, 因此最大值為 16383, 即約 16 ms. 

測試程式 : 

unsigned long time;
void setup() {
  Serial.begin(9600);
  }

void loop() {
  time=micros();
  delayMicroseconds(16383);
  Serial.println(time);
  }

擷取序列埠視窗輸出如下, 可見差額約為 16ms : 

0
16656
33424
50216
67008
83796
100592
117428
134276
151120
167972
184812

但若傳入超過 16383 之參數, 仍可編譯成功, 只是執行結果並非所預期者, 例如傳入 1000000 (延遲 1 秒) :

unsigned long time;
void setup() {
  Serial.begin(9600);
  }

void loop() {
  time=micros();
  delayMicroseconds(1000000);
  Serial.println(time);
  }

序列埠輸出卻是差額 700 左右 :

0
148
752
1508
2320
3132
3936
4740
5552
6364
7176
7972

delayMicroseconds() 是給延遲數千微秒用的, 秒級的應該使用 delay().


3 則留言 :

DavidGU 提到...

請問要製作一個電器上電開機時開始計時,關機時保存時間數值,重新開機後繼續累計時間,一直到reset才歸零,如何運用呢?謝謝

小狐狸事務所 提到...

雖然我沒做過這種應用, 但據我閱讀之印象, 應該有種作法 :
1. 紀錄在 Arduino 內建的 EEPROM (512KB)
2. 記錄在外加的 TF 卡模組內

小狐狸事務所 提到...

關於 EEPROM 用法可參考 :
https://makerpro.com.tw/2014/12/how-to-control-arduino%CA%BBs-built-in-eeprom/