OLED_I2C и millis() или 1000mls = 2.4 сек
- Войдите на сайт для отправки комментариев
Здравствуйте.
При работе с Arduino nano v.3.0, библиотекой OLED_I2C и дисплеем 128X64 OLED Display 0.96" I2C заметил большую задержку по времени работы скетча. Путём эксперементов упёрся в функцию millis();
Для теста залил скетч мигание светодиодом.
/* Blink without Delay – мигаем без задержки :) * * Включение/выключение светодиода, подключённого к * цифровому порту, без использования функции delay(). * Это означает, что «одновременно» можно выполнять другой код, * без прерывания на мигание светодиодом :) * * http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay */ #include <OLED_I2C.h> int ledPin = 13; // наш светодиод на 13 порту int value = LOW; // предыдущее состояние светодиода unsigned long previousMillis = 0; // здесь будет храниться время последнего изменения состояния светодиода long interval = 1000; // интервал мигания в миллисекундах void setup() { pinMode(ledPin, OUTPUT); // устанавливаем порт, как выход } void loop() { // проверяем – настало ли время изменить состояние светодиода // для этого берём разность между текущим временем и // временем последнего изменения состояния светодиода, // а затем сверяем полученный интервал с нужным интервалом // мигания – если больше – значит пора мигать ;) if (millis() - previousMillis > interval) { previousMillis = millis(); // запоминаем текущее время // если светодиод был выключен – включаем и наоборот :) if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } }
Всё отлично, 10 переключений за 10 секунд.
Добавляем библиотеку OLED_I2C и подключаем дисплей:
/* Blink without Delay – мигаем без задержки :) * * Включение/выключение светодиода, подключённого к * цифровому порту, без использования функции delay(). * Это означает, что «одновременно» можно выполнять другой код, * без прерывания на мигание светодиодом :) * * http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay */ #include <OLED_I2C.h> OLED myOLED(SDA, SCL); extern uint8_t SmallFont[]; int ledPin = 13; // наш светодиод на 13 порту int value = LOW; // предыдущее состояние светодиода unsigned long previousMillis = 0; // здесь будет храниться время последнего изменения состояния светодиода long interval = 1000; // интервал мигания в миллисекундах void setup() { pinMode(ledPin, OUTPUT); // устанавливаем порт, как выход myOLED.begin(); myOLED.setFont(SmallFont); } void loop() { myOLED.clrScr(); myOLED.print("QWERTY", RIGHT, 0); myOLED.update(); // здесь можно поместить свой код для постоянного выполнения // проверяем – настало ли время изменить состояние светодиода // для этого берём разность между текущим временем и // временем последнего изменения состояния светодиода, // а затем сверяем полученный интервал с нужным интервалом // мигания – если больше – значит пора мигать ;) if (millis() - previousMillis > interval) { previousMillis = millis(); // запоминаем текущее время // если светодиод был выключен – включаем и наоборот :) if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } }
И начинаются чудеса: 10 переключений за 24 секунды. Если удалить строку №32 myOLED.update(); всё работает нормально.
Если в loop добавить delay(200); то 10 переключений = 12 секунд 0_о
Залил этот скетч в Ардуино МЕГА 2560 ... 10 переключений светодиода за 62 секунды!
Не могу понять почему такой разброс по времени, почему delay влияет на millis()?
Поиск по "OLED_I2C и millis()" ничего не дал. Ткните пожалуйста где копать, это мой первый проект, знаний катастрофически не хватает.
Чудеса были бы если бы обновление дисплея происходило мгновенно.
а так не вижу чудес.
Если в loop добавить delay(200); то 10 переключений = 12 секунд 0_о
.. почему delay влияет на millis()?
Т.е. Реальное время работы == "Количество миллисекунд с момента начала выполнения программы" + время выполнения кода + время опроса-ответа устройств ?
Тогда почему строка delay(200); сокращает время работы на 12сек, в два раза?
Хотя должна увеличить на 0.2 сек.
Потому что видимо иногда ваш интервал равен заданому интервалу а не больше. И становится больше только на следующий круг.
хотите четко по времени, изучайте прерывания.
А если отключить обновление дисплея то сразу 0% совпадений интервала?
Нелогично.
Опять же delay(200)?
Как я понимаю millis() привязан к тактовой частоте, почему увеличивается период импульсов?
Читал что если процессор работает на 8 а не 16 мегагерцах, то это отражается и на millis() т.к. соотношение расчитано на 16. В два раза было бы понятно, но соотношение плавает и зависит от фазы луны.
И начинаются чудеса: 10 переключений за 24 секунды. Если удалить строку №32 myOLED.update(); всё работает нормально.
Аяя... диво дивное! Криворукое, жопомозгое! Очередной автор либы срал на вся и всё вокруг, запретил прерывания где смог достать и закомитил...
Код в студию.. Что там от noInterrupts() и до interrupts() по времени? Все прерывания таймера слиплись в одно, вот и время потерялось.
Спасибо большое за помощь, как раз начал изучать прерывания, попробую разобраться зачем отключены прерывания.
P.S. Спасибо что вернули веру в специалистов, грешным делом подумал что все такие же "програмисты" как я и Puhlyaviy
Убрал строки noInterrupts() и interrupts() и чудо исчезло, теперь 1000мс == 1 сек.
Возможно автор библиотеки отключил прерывания чтоб небыло задержки передачи данных в дисплей в блоке "Send TWI"
Doozer, вооьще-то Вы изначально неправильно используете millis().
Для начала перепишите фрагмент кода примерно так:
Doozer, вооьще-то Вы изначально неправильно используете millis().
Для начала перепишите фрагмент кода примерно так:
Лучше попробуй остановить милис методом запрета прерываний. Я что-то нигде не нашел про такой фокус. А ардуино нет под рукой.
Пишут что прерывания запрещаются но не все. И милисс морозиться только при обработке прерываний.
Код, первый попавшийся в поиске по millis().
С вами согласен, ещё бы заменил if else на digitalWrite(ledPin, !digitalRead(ledPin));
Знаний не хватает для этого. Пока меня устраивает выход с отменой запрета. Код пишу для себя, поэтому сойдёт и так.
как я понимаю милс привязан к прерыванию по таймеру. если не ошибаюсь 1-го. а оно может быть иногда и запрещено локально(только оно) или глобально(все прерывания).
Я бы рекомендовал так. http://arduino.ru/forum/proekty/net-sosed-ili-domofon-avtomat
Пока меня устраивает выход с отменой запрета.
Код пишу для себя, поэтому сойдёт и так.
Код работает месяц. Глюков не замечено.
И слава Богу. Но понять его логику (для чего он это делал) всё же нелишне. Хотя, я бы на код посмотрел (сейчас смотреть не хочу - "не моя война"). Если код выглядит как профессиональный, то старался бы понять, если нет - не парился бы. Если писал непрофессионал, то вполне вероятно, что отключил безо всякой причины :)
Нормально там все без прерываний. Наверно его смущало что програмная реализация I2C и тайминги увеличатся при попадании прерывания на обмен. Но это для синхронной шины до лампочки. Я себе либку писал для этого экрана тоже с програмным I2C, без запрета прерываний и прямо щас крутится месяц в режиме 24*7 (это второй экран для фоторамки - на одном фотка а на этом надпись к ней ). Ни одного глюка. К стати по описанию I2C у экрана 400кГц а в реале он держит максимум возможного от ардуинки 16МГц, вобще без задержек. А это выходит около 1МГц на шине. Может экземляр такой, может на температуре повалится, но пока без замечаний.