題:
可能有很長的delay()嗎?
Fred Pannekoek
2014-08-21 17:14:29 UTC
view on stackexchange narkive permalink

我正在嘗試打開一個應該每12小時打開或關閉一次的小門。我想知道我是否可以製作一個帶有delay()的小型循環腳本12個小時,delay(43 200 000 000);我猜?但是,我不知道這是否可能和/或值得推薦。一些反饋/替代方法(如果需要)會很不錯:)

好的,我認為延遲的最大值為65535 µs,但現在我需要一個替代方案...
在更成熟的,獨立於MCU的系統中,計時通常是通過對MCU的硬件計時器通道進行編程以定期觸發中斷,然後對它們進行計數來進行的-這使處理器可以同時執行其他操作,並且累積精度與時鐘晶體。
使用延遲會放大一個如此微小的開銷錯誤。最好使用中斷為已知的良好時間計時,然後從那裡開始計數。這是我個人網站上的概念證明:http://blog.linformatronics.nl/213/electronics/timed-1-millisecond-interrupt-routine-for-arduino
如果不一定要定時,可以使用非常規的東西,例如光感應器來感應早晚。
是的,我考慮過這一點,但是我只有一個光探測器部分,並且不確定如何保護它不受天氣影響(小門在外面)
@FredPannekoek。將探測器放在屋頂下。您無需將其直接放在天空下。
我要低20分鐘,高3分鐘的程序結構。我有arduino uno板
六 答案:
geometrikal
2014-08-21 19:08:04 UTC
view on stackexchange narkive permalink

實時時鐘方法是最準確的方法,但否則請使用 millis

  unsigned long startMillis = millis(); while(millis()-startMillis < LONG_DELAY_MS);  

這將最多延遲大約4294967295ms(2 ^ 32-1)或49天,之後計時器將趕上 startMillis

的值
僅使用`delay(LONG_DELAY_MS)`有什麼問題? [arduino實現](https://github.com/arduino/Arduino/blob/master/hardware/arduino/cores/arduino/wiring.c#L109-119)接受未簽名的long。我也不完全確定當`millis()`環繞並且小於`startMillis`時,您的代碼是否工作正確
如果我正確的話,延遲會使您的arduino完全不活動。我不知道當毫秒數回到0時這將如何運作。
@Gerben好東東,把它作為答案!
只要使用* unsigned * long,@FredPannekoek溢出就可以正常工作。
因此,您想每12毫秒中斷一次嗎?為什麼不將控制器置於睡眠模式12h?
@23ars到底要在12個小時後如何喚醒控制器?最優雅的解決方案是帶有12小時警報的外部RTC。
看一下里卡多的答案。或者,如果您不希望看門狗和睡眠模式,一種解決方案是將計時器設置為每秒產生一次中斷(TIMERX_COMPA)併計數秒而不是毫秒。使用millis時,您每ms都會產生一個中斷,這不太正常。即使是Arduino,我還是不贊成使用Millis等庫中的函數。
@23ars Arduino如此成功的主要原因是其易於使用的硬件抽像庫,如果您反對庫中的函數,則會在某種程度上限制自己。無論如何,評論的功能是改善答案,如果您有更好的解決方案,請編寫自己的答案。 ;)
Tom
2014-08-21 18:04:11 UTC
view on stackexchange narkive permalink

delay()有其用途,但是長時間拖延是不好的。它只是告訴微控制器在 x 個時鐘週期內甚麼也不做。在這段時間內,您的Arduino無法做其他任何事情。

您最好的選擇是使用一種稱為實時時鐘(RTC)的東西。這些芯片專門用於跟踪時間,您可以輕鬆地將它們連接到Arduino。 這是一個如何做到這一點的例子。

+1-如果您想獲得比MCU所能提供的精度更高的RTC解決方案就特別好。
@Ricardo-RTC不太可能比帶有時鐘晶體的MCU使用其硬件計時器之一觸發週期性中斷的準確性更高;它通常能使您跟踪功率損耗,以及日曆計劃的一些知識。
Afaik uno的時鐘沒有使用石英鑽頭,而是陶瓷諧振器,因此精度比rtc小得多。
@ChrisStratton-對。點了。如果OP必須在一天的給定時間打開或關閉門,則RTC將是更好的選擇。
Ricardo
2014-08-21 19:28:41 UTC
view on stackexchange narkive permalink

您可以使用看門狗中斷,並在等待時讓MCU休眠並節省功耗。

但是請注意,只有在電路板也保存的情況下,您才可以節省功耗。這意味著您必須有一個低靜態電壓調節器,而不是配備最常見的Arduino板(例如Uno)的常規調節器。否則,如果您的電路板沒有,MCU是否節省能源也沒關係。

以下是代碼(未經試用):

  #include <avr / sleep.h> //此變量被設置為volatile,因為它在中斷函數中更改volatile int sleep_count = 0; //跟踪已完成多少個睡眠週期。const int interval = 720; //喚醒和執行任務之間的時間間隔,以分鐘為單位。const int sleep_total =(interval * 60)/ 8; //在經過上面定義的時間間隔之前//所需的大約睡眠週期數。並不是說這是整數math.void setup(void){watchdogOn(); //打開看門狗計時器。 //通過將ADEN位(位7)設置為零來禁用ADC。 ADCSRA = ADCSRA & B01111111; //通過將ACD位(位7)設置為1來禁用模擬比較器。 ACSR = B10000000; //通過將位0-5設置為1來禁用所有模擬輸入引腳上的數字輸入緩衝器。 DIDR0 = DIDR0 | B00111111;}無效循環(無效){goToSleep(); // ATmega328進入睡眠狀態約8秒鐘// //如果(sleep_count == sleep_total){//要定期執行的代碼}} void goToSleep(){set_sleep_mode(SLEEP_MODE_PWR_DOWN);並在喚醒時繼續執行代碼//設置睡眠模式。 sleep_enable(); //啟用睡眠模式。睡眠模式(); //進入睡眠模式。 //從看門狗中斷喚醒後,代碼//從這一點繼續執行。 sleep_disable(); // //喚醒後禁用睡眠模式。} void watchdogOn(){//清除復位標誌,即MCUSR的WDRF位(第3位)。 MCUSR = MCUSR & B11110111;
//將WDTCSR的WDCE位(位4)和WDE位(位3)置1。 WDTCSR = WDTCSR | B00011000; //將看門狗超時預分頻器值設置為1024 K //,這將產生約8.0 s的超時間隔。 WDTCSR = B00100001; //啟用看門狗定時器中斷。 WDTCSR = WDTCSR | B01000000; MCUSR = MCUSR & B11110111;} ISR(WDT_vect){sleep_count ++; // //跟踪已完成多少睡眠週期。}  

我複制的代碼來自以下頁面:使用看門狗定時器的低功耗Arduino

Lohan
2018-01-23 15:44:18 UTC
view on stackexchange narkive permalink

當我不想在其間做任何事情時,我只使用for循環:

  for(int Hours = 0; Hours < 12; Hours ++){//為以下內容創建12小時(int Minutes = 0; Minutes < 60; Minutes ++){//為(int Seconds = 0; Seconds < 60; Seconds ++)創建1小時{//創建1分鐘延遲(1000); //創建1秒}}}  
說明這比簡單的“延遲(43200000)”更好。
對於初學者來說,修改您要等待的時間會更容易。只需更改小時,分鐘和秒的數字,而無需轉換為毫秒。
TDHofstetter
2014-08-21 18:03:08 UTC
view on stackexchange narkive permalink

您是否有一個睡眠(無符號整數秒)?

如果沒有,這將使您能夠延遲很長時間:

  for( unsigned int bigloop = 0; bigloop<65535; bigloop ++){for(unsigned int smallloop = 0; smallloop<65535; smallloop ++){for(unsigned int tinyloop = 0; tinyloop<65535; tinyloop ++){delay(65535); }}}  
如果我無法像湯姆說的那樣獲得rtc,我可以嘗試一下。感謝您的幫助!
Frank C
2015-12-03 04:24:56 UTC
view on stackexchange narkive permalink

這將起作用:

  longDelayInSeconds = 120; //2分鐘; while(p < longDelayInSeconds){delay(1000); p ++;}  
不是最佳解決方案,OP要求12個小時而不是2分鐘。


該問答將自動從英語翻譯而來。原始內容可在stackexchange上找到,我們感謝它分發的cc by-sa 3.0許可。
Loading...