Список таймеров v2.0
- Войдите на сайт для отправки комментариев
Много таймеров из одного
Основная задача, стоящая перед горе-программистом AVR это не строгий математический анализ каких-нить бестолковых данных, не быстрое преобразование Фурье и даже не унылое мигание светлодиодиком. Основная задача, занимающая 80% программы - измерение временных интервалов. Чаще всего требуется узнать, скока времени прошло перед/после какого-нить события, чтобы не пропустить и вовремя откликнуться на него. Кто-то (90% новичков) жизни своей не мыслят без функции delay(), кто-то постоянно теребонькает несчастную millis(), зачастую, делая это неправильно и со священным ужасом ожидая страшного переполнения. Сложность в том, что временных интервалов по ходу программы требуется много, часто и, как правило, разных. Например, время конверсии даччика DS18B20 при максимальном 12-битовом разрешении составляет 750 миллисекунд, и раньше, чем вычислится температура опрашивать снова его бессмысленно. Для других даччиков время опроса будет совершенно другое, и временной интервал для него, соотвецтвенно - тоже. На экран информацию чаще 1 раза в 50 миллисекунд выводить тоже неприлично, только лишняя трата ресурсов, нервов и самого экранчика, значит опять надо где-то хранить время, когда вывод осуществлялся последний раз, чтоб не обращаться к нему чаще положенного. Везде, куда не посмотришь - время, время и время...
Кто-то, не мудрствуя лукаво, использует для своих целей delay() и не парится, даже не понимая, что процессор во время выполнения этой функции просто висит в холостом цикле, не делая ничего полезного, и не способен исполнять что-то иное (на самом деле способен, канеш, но для новичков это тайна). В некоторых задачах, будь то простейший Blink или управление светлодиодной лентой это не критично, но если delay() используется в программе управления газовой горелкой, тут впору эвакуировать из дома родных и близких (и кота) на время эксплуатации такой горелки.
Более продвинутые открыли для себя функцию millis() и поглядывают/поплевывают на делейщиков с высоты своего воображаемого Олимпа как исполненные благодати Свидетели Переполнения. И пестрят их программы чуть более чем полностью конструкциями вида
if (millis()-lastmillis > myinterval) dosomething();
а то и
if (lastmillis+myinterval>millis()) dosomething();
но последние, обычно, к исходу 49-х суток взрываются вместе с переполнившимся millis-om() и угрозы больше не представляют.
delay() похож на дубину, которой нерадивый пользователь со всего маху шарашит бедный процессор по голове, после чего ему становится очень трудно стоять без сознания и он валяется в отключке некоторое заданное количество времени. Естественно, ничего другого он делать в этом состоянии не способен.
millis() в этом отношении гораздо гуманнее. Он похож на хозяина раба, который вручил ему наручные часы, и строго настрого наказал следить за временем, если не хочется получить дубиной по башке, как в прошлый раз. И вот человечек, выполняя свою нехитрую работу, всё время пялится на часы, чтоб узнать не прошло ли достаточно времени, чтоб включить/выключить что то важное. Иначе, не уследишь/забудешь и улетишь вабнимку с газовым котлом Марс заселять вместе с родными и близкими (и котом), а жалка. Такое можно, канеш, потерпеть, если временной интервал один, но как только их становится несколько, да еще и друг от друга зависящих, выполнение задания превращается в атнюдь не тривиальную задачу (мошт, лучше дубиной, а?).
То что предлагаю я, можно назвать будильником. Человек заводит себе несколько будильников на разное время и спокойно занимается своими делами. По мере срабатывания каждого, можно ненадолго отвлечься, включить/выключить то что нужно/ненужно и спокойно продолжить заниматься своими делами дальше. Если действие было однократное, будильник можно отключить, а если совсем-совсем однократное - то и выбросить. Если действие периодическое, а так чаще всего и бывает, ничего делать не нужно, через ранее заданный интервал будильник сам по себе сработает снова.
кого заинтересовало продолжение -> https://github.com/DetSimen/Arduino_TimerList
Ну, а где Consts.h ? Ругаеццо, шо ево нету!
А если include выбросить, то не ругаеццо :)
Пакавырялся. Замечания надо?
include Const.h можно безболезненно удалить.
Замечания от Вас приму с искренней благодарностью, даже если Вы меня в пух и прах разнесете. Я свой уровень +1 см над плинтусом знаю.
Const.h убрал, спасибо.
Ну, дед, очень не хватает примера или там хоть какой документации. Я вот сразу кинулся собственный лист создавать, а она у Вас только свой лист обслуживает.
А так, я пока не сильно много ковырялся, но первое. что в глаза бросилось - неверное условие в строке №182 (если я где случано номера строк не нарушил) файла TTimerList.h. Из-за него невозможно создать максимальное заявленное количество таймеров, а можно только на 1 меньше. Вот пример
#include "TTimerList.h" void loop(void) {} void setup(void) { Serial.begin(57600); for (int i = 0; i < MAXTIMERSCOUNT; i++) { Serial.print("Timer["); Serial.print(i); Serial.print("] - "); Serial.println(TimerList.Add(500, loop) != INVALID_HANDLE ? "Okay" : "Failed"); } } // РЕЗУЛЬТАТ // // Timer[0] - Okay // Timer[1] - Okay // Timer[2] - Okay // Timer[3] - Okay // Timer[4] - Okay // Timer[5] - Okay // Timer[6] - Okay // Timer[7] - Okay // Timer[8] - Okay // Timer[9] - FailedВидите, девять создал, а десятый - никак. Так и должно быть, посмотрите на условие. А память-то на все 10 хапнул :)
Cобственный лист создать нельзя, класс должен быть статическим, иначе аппаратный таймер не будет знать, что вызывать при срабатывании. Наерна?
Строку 182 поправил. Идиот я, естессна, чо с мня взять. :-) Спасибо.
Документацию как-нить, напишу, пока на больничном. Протрезветь бы к завтрему. :-)
А хто и за што мня в программирование перекинул?
Сейчас как раз и можно
#include <TTimerList.h> void setup() { TTimerList list1(2); TTimerList list2(list1); } void loop() { }Чего бы его в синглтон не обернуть
class MyClass { public: static MyClass* instance() { static MyClass one(10); return &one; } protected: MyClass(size_t a){} MyClass(const MyClass& org){} };А хто и за што мня в программирование перекинул?
Не я, я ток в песочницу умею.
А я никуда не умею :(
Алексей. это читерство! :)))))
Дед, а вот строке №33 TTimerList.cpp заводится, кроме всего прочего, ещё и "Set OC0B on Compare Match, clear OC0B at BOTTOM", а потом нигде не используется. На это есть какие-то соображения или просто от чего-то прежнего осталось?
А я никуда не умею :(
Алексей. это читерство! :)))))
Надо попробовать
Cобственный лист создать нельзя, класс должен быть статическим, иначе аппаратный таймер не будет знать, что вызывать при срабатывании. Наерна?
Строку 182 поправил. Идиот я, естессна, чо с мня взять. :-) Спасибо.
Уотт те делать нефиг... Я делаю флаговые битовые поля для калиброванных интервалов времени, допустим, под 18в20 в 750 мск и под дисплей 1/2 секунды. Тупо занимаюсь "своими" делами и посматриваю на флаги и по мере их поступления обрабатываю или "сплю". Делеи вООбще никогда не использовал от слова совсем. Тема, канеш, классная, но новички нипаймут... к сожалению.................)))
у мине пару замечаний :)
1) я так понимаю компиляция под другие чипы вывалится с ошибкой. ну например, ЕСП не знает что такое SREG.
2) в примерах каша с ledState.
у мине пару замечаний :)
1) я так понимаю компиляция под другие чипы вывалится с ошибкой. ну например, ЕСП не знает что такое SREG.
Да, проверено (и используется мной) только под Atmega8, 168, 328 и 2560
Дед, а вот строке №33 TTimerList.cpp заводится, кроме всего прочего, ещё и "Set OC0B on Compare Match, clear OC0B at BOTTOM", а потом нигде не используется. На это есть какие-то соображения или просто от чего-то прежнего осталось?
с аппаратными таймерами разбирался ровно два года назад, с тех пор оставил как есть, думаю, работает и ладно. Сегодня-завтра переделаю по правильному.
Чего бы его в синглтон не обернуть
Столь далеко мои знания лжывого С++ не простираюца. Я вообще не программист и никада на него не учился, и в сортах этих ваших богомерзких сиглтонов не разбираюсь. :) Если сообщество подскажет как - я сделаю.
Только надо понять а надо ли? Никому же не приходит в голову второй объект Serial создавать вручную? Или он тоже синглтоном сделан?
2) в примерах каша с ledState.
Благодарю, поправил.
Дед, а вот строке №33 TTimerList.cpp заводится, кроме всего прочего, ещё и "Set OC0B on Compare Match, clear OC0B at BOTTOM", а потом нигде не используется. На это есть какие-то соображения или просто от чего-то прежнего осталось?
посмотрел, не вижу ничего про OC0B
#elif defined(__AVR_ATmega328P__) void TTimerList::Init() { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { TCCR0A = TCCR0A & 0b11111100; // Таймер в режиме Normal OCR0A = TIMER0_ONE_MS; // загрузим регистр совпадения TIMSK0 |= 0x3; // установить OCIE0A и TOIE0, разрешим совпадение А и переполнение TIFR0 |= 0x2; // очистим флаг OCF0A если до этого он был установлен, ждём следущего совпадения } }Cобственный лист создать нельзя, класс должен быть статическим, иначе аппаратный таймер не будет знать, что вызывать при срабатывании. Наерна?
Строку 182 поправил. Идиот я, естессна, чо с мня взять. :-) Спасибо.
Уотт те делать нефиг... Я делаю флаговые битовые поля для калиброванных интервалов времени, допустим, под 18в20 в 750 мск и под дисплей 1/2 секунды. Тупо занимаюсь "своими" делами и посматриваю на флаги и по мере их поступления обрабатываю или "сплю". Делеи вООбще никогда не использовал от слова совсем. Тема, канеш, классная, но новички нипаймут... к сожалению.................)))
с чего это, понятно жеж что использовать в написании кода без блокирующих функций
посмотрел, не вижу ничего про OC0B
Это мне уже к вечеру поплохело.
:)
2) в примерах каша с ledState.
Благодарю, поправил.
деда !
не до конца поправил ! (3,5 строка)
void tmrGreenLed(void){ static bool ledState=true; // состояние светодиода digitalWrite(greenLedPin, state); // вывести состояние в светодиод !!!! TimerList.setNewInterval(hgreenLed, state ? 200 : 4800); // !!!! ledState = !ledState; // инвертировать состояние }и в первом примере тоже.
не до конца поправил ! (3,5 строка)
ну дак я еще ж и слепой. щас поправлю, канеш
а вот интересно, можно ли использовать таймер в частотомере для задания интервала измерения?
этот - нет, аппаратный можно.
этот - нет, аппаратный можно.
Дак про аппаратный это понятно )))
с чего это, понятно жеж что использовать в написании кода без блокирующих функций
С того это. Вот смотри - используй ЛЮБОЙ таймер так, как тебе нужно, хоть ШИМ. Прикрути к нему прерывание и считай себе на здоровье любые интервалы и одновременно ШИМи. И никаких делаев в коде от слова совсем.
За очередь сапщений v2.0 расказывать?
А то!
Я не верю, Евгений Петрович, что Вы ляпов больше не нашли.
А про очередь, завтра выкладу.
Это штоп ты сразу в запой не ушел...
Дак я и так в запое.
За очередь сапщений v2.0 расказывать?
Сорри, пока некада, до выходных по коновалам брожу...
Правда, в нашей стране, если денег нет - то ты самый здоровый человек на свете. А если есть - то больной пока деньги не кончуцца, потом см. п.1.
Отставить пессимизм! Выздоравливайте!
Отставить пессимизм! Выздоравливайте!
Самому жаль, но не смогу. :-) Вы, кста, можете называть меня на ты, без церемоний, буду только рад.
Это не церемонии. У меня наоборот "на ты" - это церемонии. Так я зову только членов своей семьи (включая кота) и ближайших друзей - 2-3 человека. Иногда в сети, я пытаюсь создать некоего аватара (типа известного Вам аспера), который чем-то от меня отличается, в частности "на ты" общается, но не выдерживаю долго.
А как у тебя отношение к тапкам обстоит?
Дед! Я вешу 152 кг (сын новые весы на НГ подарил), у меня диабет 2, сахар ниже 15 ваще никогда не бывает, вотки я жру не меньше 0.5 ежедневно.
Хошь расскажу, как жить с сахаром 15 и не париццо? ;)))) Просто не мерить его, гада! ;)))
И да - сёння у меня с супругой 29 лет венчания... я - ж веры самой шо ни есть православной ;))), хоть и .... ну да, и что?
Дык я тут Здоровое питание придумал: бананово-клубничный смузи!
1. 1 банан.
2. стакан замороженной клубники окатить кипятком.
3. лед - еще стакан.
4. вода - полстакана, для запаха.
5. водка - стакан с горкой ;))). (ром можно ежли с жабой договориться!)
6. долька лимона с кожурой.
-------------------
Всё скрутить в блендере в теч. минуты. Разлить по стаканам и пить с женой через толстую соломинку.
Лехаим!
А как у тебя отношение к тапкам обстоит?
что мне какие-то тапки, в моём мире измочаленных скалок и сковородок с инверсным барельефом моего затылка?
катушку Мишина не предлагаю )))
Добрый день. А можешь, пожалуйста, добавить пример с запуском и остановкой по некоему внешнему событию (допустим, нажатием кнопки).
могу, но папожже. мы с котом с дачи домой переежжяем.
могу, но папожже. мы с котом с дачи домой переежжяем.
Благодарю
Вопщем, тебе понадобица:
1 Встроенный светодиод на пине 13
2 Тактовая кнопка на пине A0
3 Активный буззер на пине D4
при запуске, программа начинает мигать светодиодом на пине 13. При нажатии на кнопку раздается короткий писк буззером и мигание останавливается, при следующем нажатиии опять писк и мигание продолжается.
/* Name: TimerTest.ino Created: 01.10.2019 8:40:17 Author: DtS */ #include <Arduino.h> #include <TimerList.h> static const uint8_t ACTIVE_BUZZER_PIN = 4; // пин, для активного Buzzer extern TTimerList TimerList; THandle hBlink, hBuzzer; // хэндлы для мигателя и бузера void tmrBuzzer(void) { // выключить бузер и остановить таймер digitalWrite(ACTIVE_BUZZER_PIN, LOW); TimerList.Stop(hBuzzer); } void tmrBlink(void) { // toggle светодиод на ноге 13 static bool state = false; digitalWrite(LED_BUILTIN, state); state = !state; } void Beep(void) { // включить бузер и взвести таймер его выключения digitalWrite(ACTIVE_BUZZER_PIN, HIGH); TimerList.Reset(hBuzzer); } // читает цифровую кнопку на пине APin // отдает true - пока кнопка нажата. bool KeyRead(const uint8_t APin) { static uint32_t lastread = 0; static bool laststate = false; uint32_t now = millis(); if (now - lastread < 100) return laststate; lastread = now; uint8_t cnt = 0; for (uint8_t i = 0; i < 8; i++) { if (!digitalRead(APin)) cnt++; delay(1); } laststate = (cnt > 4); return laststate; } void setup() { Serial.begin(115200); delay(500); hBlink = TimerList.Add(500, tmrBlink); // таймер мигания светодиодом на ноге 13 hBuzzer = TimerList.AddStopped(150, tmrBuzzer);// таймер буззера, 150мс, создается остановленным pinMode(LED_BUILTIN, OUTPUT); // настройка пинов на ввод и вывод pinMode(A0, INPUT_PULLUP); // здесь кнопка pinMode(ACTIVE_BUZZER_PIN, OUTPUT); // здесь бузер } void loop() { if (KeyRead(A0)) { // читаем кнопку, если нажата Beep(); // запускаем писк на нажатие кнопки while (KeyRead(A0)) ; // подождем пока кнопку атпустют if (TimerList.isActive(hBlink)) { // если светодиод на 13 ноге мигает - digitalWrite(LED_BUILTIN, LOW); // потушим его TimerList.Stop(hBlink); // и остановим мигание } else TimerList.Reset(hBlink); // ну а если светодиод не мигает - запустим мигание снова } }Спасибо. Буду экспериментировать.