В общем исключительно в научных целях собираю метео станцию. запись с термистора на SD. для того чтобы не тормозить loop dalay*ем написал ф-ю elapsed() c 5-ю таймерами. если заданно время проходит он возвращает true и if выполняет блок кода, при этом все что ниже блока ни ждет ни какого dalay. Код (Text): /* SD card read/write This example shows how to read and write data to and from an SD card file The circuit: * SD card attached to SPI bus as follows: ** MOSI - pin 11 ** MISO - pin 12 ** CLK - pin 13 ** CS - pin 4 created Nov 2010 by David A. Mellis modified 9 Apr 2012 by Tom Igoe This example code is in the public domain. */ #include <SPI.h> #include <SD.h> File myFile; void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } Serial.print("Initializing SD card..."); // On the Ethernet Shield, CS is pin 4. It's set as an output by default. // Note that even if it's not used as the CS pin, the hardware SS pin // (10 on most Arduino boards, 53 on the Mega, 14 on the Leonardo) must be left as an output // or the SD library functions will not work. if (!SD.begin(4)) { Serial.println(F("initialization failed!")); return; } Serial.println(F("initialization done.")); } bool elapsed(int ms, int t) { static long int timers[5]= {0}; if ((timers[t]-millis()) > ms) { timers[t] = millis() + ms; return true; } return false; } void loop() { if (elapsed(1000, 0)) { float v = analogRead(A0) * 5.0 / 1024.0; float t = -21.9 * log((10000.0 * v) / (5.0 - v) / 27074.0); Serial.println(t); myFile = SD.open("logT.txt", FILE_WRITE); if (myFile) { myFile.println(String(t)); myFile.close(); } } // nothing happens after setup } Так странность в том что если у меня таймера объявлены как static int timers[5]= {0}; после 2-3 десятков тиков таймера он ускоряется т.е. не держит заданный интервал, но если обьявить таймеры как static long int timers[5]= {0}; я тестировал наверное минут 5-10 все еще тикало как надо. В чем может быть дело?
int в avr-gcc имеет размерность два байта, т.е. диапазон от -32768 до 32767. В результате примерно через 32 секунды после старта скетча значение, возвращаемое millis(), выходит ха этот диапазон и при присваивании наступает переполнение. Осюда и спецэффекты. Если использовать long int, то диапазон увеличивается до где-то чуть больше чем +-2 миллиарда. В результате результат millis в течении более долгого времени можно присваивать без потерь. Если делать совсем хорошо, то лучше будет static unsigned long int timers[5]= {0};
Т.е. я правильно понимаю, что таймеры с unsigned long int проработают корректно всего 49,71 суток? Т.к. имеют разрядность 4 байта - диапазон от 0 до 4 294 967 295. А программно никак не сбросить millis(), для увеличения срока автономной работы, не прибегая к перезагрузке Arduino?
На самом деле все проще. Когда таймер дотикает до максимума, то он перескочит опять на 0. И дальше вступает в силу хитрая компьютерная арифметика, работающая при переполнениях. В результате для значений с типом unsigned long int разница между зафиксированным ранее и текущим значениями millis() будет корректной до тех пор, пока между событиями не пройдет больше чем 4 294 967 295 миллисескунд. Например, фиксация ранее t1 $FFFFFFFE Текущая фиксация t2 10 то значение t2-t1 будет 12, т.е. равно количеству миллисекунд, прошедших с первой отсечки до второй. И сравнение (t2-t1)>interval будет корректно работать, несмотря на переход через 0. Для знакового long int и для простого int в случае переполнения все будет несколько по другому.
Ого не знал, т.е. можно абсолютно не волноваться за таймеры, и держать Arduino включенной более 2 месяцев
>Когда таймер дотикает до максимума, то он перескочит опять на 0. а если я ниже добавлю маленький delay(1000) та часть чипа что "крутит" счетчик таймера тоже будет стоять 1с ? >И сравнение (t2-t1)>interval будет корректно работать, несмотря на переход через 0. т.е. пока есть напряжение этот вариант будет работать корректно бесконечно ?
Нет. Таймер будет продолжать считать. Да. Только следует учитывать, что оно работает правильно только если не останавливать таймер надолго (а уж тем паче навсегда) запретом прерываний и не вызывать рестарт МК.