OLED_I2C и millis() или 1000mls = 2.4 сек

Doozer
Offline
Зарегистрирован: 30.07.2015

Здравствуйте.

При работе с Arduino nano v.3.0, библиотекой OLED_I2C и дисплеем 128X64 OLED Display 0.96" I2C заметил большую задержку по времени работы скетча. Путём эксперементов упёрся в функцию millis();

Для теста залил скетч мигание светодиодом.

Всё отлично, 10 переключений за 10 секунд.

Добавляем библиотеку OLED_I2C и подключаем дисплей:

И начинаются чудеса: 10 переключений за 24 секунды. Если удалить строку №32 myOLED.update(); всё работает нормально.

Если в loop добавить delay(200); то  10 переключений = 12 секунд 0_о 

Залил этот скетч в Ардуино МЕГА 2560 ... 10 переключений светодиода за 62 секунды!

Не могу понять почему такой разброс по времени, почему delay влияет на millis()?

Поиск по "OLED_I2C и millis()" ничего не дал. Ткните пожалуйста где копать, это мой первый проект, знаний катастрофически не хватает. 

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

Чудеса были бы если бы обновление дисплея происходило мгновенно.
а так не вижу чудес.

Doozer
Offline
Зарегистрирован: 30.07.2015

Puhlyaviy пишет:
... не вижу чудес.

Doozer пишет:
 10 переключений за 24 секунды...

Если в loop добавить delay(200); то  10 переключений = 12 секунд 0_о 

.. почему delay влияет на millis()?

Т.е.  Реальное время работы == "Количество миллисекунд с момента начала выполнения программы" + время выполнения кода + время опроса-ответа устройств ?

Тогда почему строка delay(200); сокращает время работы на 12сек, в два раза?

Хотя должна увеличить на 0.2 сек.

 

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

Потому что видимо иногда ваш интервал равен заданому интервалу а не больше. И становится больше только на следующий круг.
хотите четко по времени, изучайте прерывания.

Doozer
Offline
Зарегистрирован: 30.07.2015

Puhlyaviy пишет:
... иногда ваш интервал равен заданому интервалу а не больше...

А если отключить обновление дисплея то сразу 0% совпадений интервала? 

Нелогично. 

Опять же delay(200)?

Как я понимаю millis() привязан к тактовой частоте, почему увеличивается период импульсов?

Читал что если процессор работает на 8 а не 16 мегагерцах, то это отражается и на  millis() т.к. соотношение расчитано на 16. В два раза было бы понятно, но соотношение плавает и зависит от фазы луны.

Logik
Offline
Зарегистрирован: 05.08.2014

Doozer пишет:

И начинаются чудеса: 10 переключений за 24 секунды. Если удалить строку №32 myOLED.update(); всё работает нормально.

 

Аяя... диво дивное! Криворукое, жопомозгое! Очередной автор либы срал на вся и всё вокруг, запретил прерывания где смог достать и закомитил...

Код в студию.. Что там от noInterrupts() и до interrupts() по времени? Все прерывания таймера слиплись в одно, вот и время потерялось.

01void OLED::update()
02{
03    noInterrupts();
04    _sendTWIcommand(SSD1306_SET_COLUMN_ADDR);
05    _sendTWIcommand(0);
06    _sendTWIcommand(127);
07 
08    _sendTWIcommand(SSD1306_SET_PAGE_ADDR);
09    _sendTWIcommand(0);
10    _sendTWIcommand(7);
11 
12    if (_use_hw)                    // Send TWI Start
13    {
14        // Send start address
15        TWCR = _BV(TWEN) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
16        while ((TWCR & _BV(TWINT)) == 0) {};
17        TWDR = SSD1306_ADDR<<1;
18        TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA);
19        while ((TWCR & _BV(TWINT)) == 0) {};
20        TWDR = SSD1306_DATA_CONTINUE;
21        TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA);
22        while ((TWCR & _BV(TWINT)) == 0) {};
23    }
24    else
25    {
26        _sendStart(SSD1306_ADDR<<1);
27        _waitForAck();
28        _writeByte(SSD1306_DATA_CONTINUE);
29        _waitForAck();
30    }
31 
32    for (int b=0; b<1024; b++)       // Send data
33        if (_use_hw)
34        {
35            TWDR = scrbuf[b];
36            TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA);                                  // Clear TWINT to proceed
37            while ((TWCR & _BV(TWINT)) == 0) {};                                        // Wait for TWI to be ready
38        }
39        else
40        {
41            _writeByte(scrbuf[b]);
42            _waitForAck();
43        }
44 
45    if (_use_hw)                    // Send TWI Stop
46        TWCR = _BV(TWEN)| _BV(TWINT) | _BV(TWSTO);                                  // Send STOP
47    else
48        _sendStop();
49    interrupts();
50}

 

Doozer
Offline
Зарегистрирован: 30.07.2015

Logik пишет:
...вот и время потерялось.

Спасибо большое за помощь, как раз начал изучать прерывания, попробую разобраться зачем отключены прерывания.

P.S. Спасибо что вернули веру в специалистов, грешным делом подумал что все такие же "програмисты" как я и Puhlyaviy

Doozer
Offline
Зарегистрирован: 30.07.2015

Убрал строки noInterrupts() и interrupts() и чудо исчезло, теперь 1000мс == 1 сек.

Возможно автор библиотеки отключил прерывания чтоб небыло задержки передачи данных в дисплей в блоке "Send TWI"

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Doozer, вооьще-то Вы изначально неправильно используете millis().

Для начала перепишите фрагмент кода примерно так:

1long CurrentTime = millis();
2 
3if (CurrentTime - previousMillis > interval)
4 
5{
6 
7  previousMillis += interval;

 

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

andriano пишет:

Doozer, вооьще-то Вы изначально неправильно используете millis().

Для начала перепишите фрагмент кода примерно так:

1long CurrentTime = millis();
2 
3if (CurrentTime - previousMillis > interval)
4 
5{
6 
7  previousMillis += interval;

 


Лучше попробуй остановить милис методом запрета прерываний. Я что-то нигде не нашел про такой фокус. А ардуино нет под рукой.
Пишут что прерывания запрещаются но не все. И милисс морозиться только при обработке прерываний.

Doozer
Offline
Зарегистрирован: 30.07.2015

andriano пишет:
..неправильно используете millis(). ...

Код, первый попавшийся в поиске по millis().

С вами согласен, ещё бы заменил if else на digitalWrite(ledPin, !digitalRead(ledPin));

 

Doozer
Offline
Зарегистрирован: 30.07.2015

Puhlyaviy пишет:
Лучше попробуй остановить милис методом запрета прерываний. ...

Знаний не хватает для этого. Пока меня устраивает выход с отменой запрета. Код пишу для себя, поэтому сойдёт и так.

MacSim
Offline
Зарегистрирован: 28.11.2012

Doozer]</p> <p>[quote=Puhlyaviy пишет:
...понимаю millis() привязан к тактовой частоте,

как я понимаю милс привязан к прерыванию по таймеру. если не ошибаюсь 1-го. а оно может быть иногда и запрещено локально(только оно) или глобально(все прерывания).

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Я бы рекомендовал так. http://arduino.ru/forum/proekty/net-sosed-ili-domofon-avtomat

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Doozer пишет:

Пока меня устраивает выход с отменой запрета.

Будьте осторожны. Постарайтесь точно понять для чего автор библиотеки запрещал прерывания. А то как бы потом Вам не прийти сюда с постом типа: "чё за глюки дисплея?".

Doozer пишет:

Код пишу для себя, поэтому сойдёт и так.

Странная позиция. Надо ж так себя не любить! Не разумнее ли "для себя всё самое лучшее?". 

Doozer
Offline
Зарегистрирован: 30.07.2015

ЕвгенийП пишет:
Будьте осторожны. Постарайтесь точно понять для чего автор библиотеки запрещал прерывания. А то как бы потом Вам не прийти сюда с постом типа: "чё за глюки дисплея?".

Код работает месяц. Глюков не замечено.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

И слава Богу. Но понять его логику (для чего он это делал) всё же нелишне. Хотя, я бы на код посмотрел (сейчас смотреть не хочу - "не моя война"). Если код выглядит как профессиональный, то старался бы понять, если нет - не парился бы. Если писал непрофессионал, то вполне вероятно, что отключил безо всякой причины :)

Logik
Offline
Зарегистрирован: 05.08.2014

Нормально там все без прерываний. Наверно его смущало что програмная реализация I2C и тайминги увеличатся  при попадании прерывания на обмен. Но это для синхронной шины до лампочки. Я себе либку писал для этого экрана тоже с програмным I2C, без запрета прерываний и прямо щас крутится месяц  в режиме 24*7 (это второй экран для фоторамки - на одном фотка а на этом надпись к ней ). Ни одного глюка. К стати по описанию I2C у экрана 400кГц а в реале он держит максимум возможного от ардуинки 16МГц, вобще без задержек. А это выходит около 1МГц на шине.  Может экземляр такой, может на температуре повалится, но пока без замечаний.