Как мне недавно стало известно в arduino имеется очень удобная библиотека TimerOne для обработки прерываний по времени. Как я понял при помощи этой библиотеки можно создать лишь одно прерывание по времени Код (Text): #include <TimerOne.h> void setup() { Serial.begin(9600); Timer1.initialize();// 1 секунда по умолчанию Timer1.attachInterrupt(Interview); } void Interview() { Serial.println("GPSInterview"); } void loop() { } а как быть если необходимо использовать 2 прерывания по времени, и возможно ли это аппаратно на Arduino Uno?
А зачем больше? Задаем минимально необходимый интервал и считаем срабатывания. например, надо прерывания через две секунды и через три. Делаем прерывание раз в секунду, увеличиваем счетчик и каждое второе срабатывание (count%2==0) делаем то, что надо раз в две секунды, а каждое третье (count%3==0) то, что надо раз в три секунды.
Да у Arduino UNO (ATmega328) есть 3 таймера. Данная библиотека работает только с 1 таймером. Можно работать, как сказал geher, но в Вашем случае таймер лишний в принципе, достаточно сделать счетчик при помощи millis().
Все зависит от того, что Вам нужно, если просто отправить данные в Serial, то точность (именно 750, а не 751 к примеру) Вам не нужна и можно сделать как в примерах со светодиодом - Blink without Delay. Если же Вам нужна супер точность, то тогда решение от geher. UPD. Для чего Вам нужен второй таймер? Чтобы понять, нужно ли там использование прерывания или нет.
Одного таймера хватит - делаем прерывание каждые 250 мс и в нем смотрим: если прошло 750 мс, вызываем функцию 1, если прошло 1000 мс, вызываем функцию 2.
Вот как на millis, без прерываний Код (Text): unsigned long previousT0Millis = 0; unsigned long previousT1Millis = 0; const long intervalT0 = 1000; const long intervalT1 = 750; void setup() { Serial.begin(115200); } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousT0Millis >= intervalT0) { previousT0Millis = currentMillis; Serial.println("1 sec."); } currentMillis = millis(); if(currentMillis - previousT1Millis >= intervalT1) { previousT1Millis = currentMillis; Serial.println("0,75 sec."); } } Иногда таймер это единственный выход, иногда лучше обходится без него. Все от задачи.
Таймер 0 задействован для millis(). Его лучше не трогать. Остается еще только два, которые бывают нужны еще много для чего: ШИМ (каждый из двух таймеров обслуживает свои пины), некоторые библиотеки (например, IRrecv, servo). Но если очень нужно, то можно залезть в исходники того же TimerOne и самому по аналогии задействовать второй таймер.
Да, для простой отправки сериала использовать таймер, мне кажется расточительным. Лучше это сделать, через millis().
В догонку о прерываниях. Код (Text): #include <TimerOne.h> volatile int LoopNum = 0; volatile unsigned long int PackageNum = 0; void setup() { Serial.begin(115200); Timer1.initialize(50000);// 50мс Timer1.attachInterrupt(Interview); Serial.println("START"); } void Interview() { if ((LoopNum % 2) == 0) { Serial.println("AX"); Serial.println("MG"); } if ((LoopNum % 15) == 0) { Serial.println("SN"); } if ((LoopNum % 20) == 0) { //опрашиваем GPS и отправляем в сериал порт строку GPS String GPS = "GPS:"; GPS += PackageNum; GPS += "; LAT="; GPS += 0.000000; GPS += "; LON="; GPS += 0.000000; GPS += "; DATE="; GPS += 30062015; GPS += "; TIME="; GPS += 2; GPS += "; VALID="; GPS += 0; GPS += ";"; Serial.println(GPS); } if (LoopNum >= 20) LoopNum = 0; else LoopNum++; } void loop() { } Не как не могу понять в чем дело. Все работает хорошо, если не использовать код с 31 по 38 строку (где String GPS) то ничего не работает, в чем может быть дело?
Возможно, слишком много действий для прерывания: создается достаточно длинная строка и проталкивается в последовательный порт. При этом много накладных расходов на перевыделение памяти и преобразование чисел в строку. А до следующего прерывания только 50 мс
Тогда отсюда вытекает следующий вопрос: как посчитать количество символов которые можно передать за 50мс при скорости сериал порта равным 115200 бод? Для UART 1бод = 1бит/с, следовательно если каждый символ весит 8 бит = 1 байт, то за 50мс можно передать 115200/1000=115,2 * *50 = 5760 бит = 720 символов, так ли это?
Несколько меньше, поскольку в потоке еще присутствуют стартовые и стоповые биты, защитные интервалы. А еще есть дополнительная вычислительная нагрузка по построению строки, которая тоже занимает какое-то время.
Измерил необходимое мне время Код (Text): void loop() { unsigned long curr_time = millis(); if ((LoopNum % 2) == 0) { String AX = "AX:"; AX += PackageNum; AX += "; X="; AX += random(-1000, 1000); AX += "; Y="; AX += random(-1000, 1000); AX += "; Z="; AX += random(-1000, 1000); AX += ";"; Serial.println(AX); String MG = "MG:"; MG += PackageNum; MG += "; X="; MG += random(-1000, 1000); MG += "; Y="; MG += random(-1000, 1000); MG += "; Z="; MG += random(-1000, 1000); MG += ";"; Serial.println(MG); } if ((LoopNum % 15) == 0) { String SN = "SN:"; SN += PackageNum; SN += "; TMP="; SN += random(0, 100); SN += "; PRS="; SN += random(0, 100000); SN += "; U="; SN += random(0, 10); SN += ";"; Serial.println(SN); } if ((LoopNum % 20) == 0) { String GPS = "GPS:"; GPS += PackageNum; GPS += "; LAT="; GPS += 0.000000; GPS += "; LON="; GPS += 0.000000; GPS += "; DATE="; GPS += 30062015; GPS += "; TIME="; GPS += 2; GPS += "; VALID="; GPS += 0; Serial.println(GPS); } PackageNum++; Serial.print("Time="); Serial.print(millis() - curr_time); Serial.println(" ms"); } Получилось в среднем 160мс, поставил период 200мс Код (Text): Timer1.initialize(200000);// 200мс ничего не работает... Попробовал увеличить до 1 сек, опять же ничего не заработало