Мерцает дисплей 128х64

Megawollt
Offline
Зарегистрирован: 06.12.2015

Помогите разобраться. Первые две строки работают нормально, а вот последняя и текст по нажатию кнопки мерцают. В чем может быть проблема?

Вот пример видео на ютубе https://www.youtube.com/watch?v=2JINHAXRKQ8

И код 

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>

#define potPin      A6     //Вывод резистора скорости
#define uPin        A5    //Вывод напряжения батареи
#define fwdPin      5    //Вывод кнопки "Вперед"
#define bwdPin      6   //Вывод кнопки "Назад"
                       
#define OLED_MOSI   3  //Выводы дисплея
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

bool con = false;                   //Статус соединения
int u_value = 0;                   //Значение напряжения
int spd = 0;                      //Скорость
float ubat = 0.00;               //Напряжение батареи
int spd_d = 0;                  //Скорость для отображения на дисплее

void setup() 
 { 

 display.begin();         //Инициализация дисплея
 pinMode(fwdPin, INPUT); //Режимы пинов
 pinMode(bwdPin, INPUT);
 pinMode(uPin, INPUT); 
 pinMode(potPin, INPUT);
 digitalWrite(bwdPin,LOW);
 digitalWrite(fwdPin,LOW);
 display.clearDisplay(); 
 display.setTextColor(WHITE); 
} //end setup

 void loop() 
 { //start loop

 display.clearDisplay();             //Очистка дисплея
 u_value=analogRead(uPin);          //Замер напряжения батареи
 ubat =(u_value*5.0)/1024.0;       //Рассчет напряжения
 spd =analogRead(potPin);         //Обработка данных резистора скорости
 spd =map(spd,0,1023,0,255);     //Маппинг 10 бит в 8 бит
 spd_d =map(spd,0,255,0,100);   //Маппинг скорости для дисплея из 255 в 100
 
 
 //Строка напряжения батареи
 display.setTextSize(1); 
 display.setCursor(0,0); 
 display.println("Battery voltage "); 
 display.setCursor(94,0);   
 display.print(ubat); 
 display.print("V"); 
 
 //Строка скорости
 display.setCursor(9,12); 
 display.println("Current speed  "); 
 display.setCursor(92,12);   
 display.print(spd_d); 
 display.print("%"); 
 display.display();
 
 //Строка соединения
 if(con==true){
 display.setCursor(23,55);   
 display.print("Connection OK"); 
 display.display();
 }//endif
 else{
 display.setCursor(23,55);   
 display.print("Not connected!"); 
 display.display(); 
 }//end else
  
 //если кнопка "Вперед" нажата ... 
 if(digitalRead(fwdPin)==HIGH&&!digitalRead(bwdPin)==HIGH)
 { 
 display.setTextSize(2); 
 display.setCursor(15,25); 
 display.println("Move FWD"); 
 display.display();
 }//endif 

 //если кнопка "Назад" нажата ... 
 if(digitalRead(bwdPin)==HIGH&&!digitalRead(fwdPin)==HIGH)
 { 
 display.setTextSize(2); 
 display.setCursor(10,25); 
 display.println("Move BACK"); 
 display.display(); 
 }//endif 
 
 //если обе кнопки нажаты ... 
 if(digitalRead(fwdPin)==HIGH&&digitalRead(bwdPin)==HIGH)
 { 
 display.setTextSize(2); 
 display.setCursor(5,25); 
 display.println("BTN ERROR!"); 
 display.display();
 } //endif 
 
 
 
  
 } //end loop
 

Еще маленький вопрос. Библиотека подразумевает вывод RST, но у дисплея его нет. Как освободить занятый библиотекой вывод?

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

В правом верхнем углу есть кнопка "Поиск". Забиваем туда "мерцание дисплея" без кавычек и убеждаемся, что проблема не нова и решалась здесь уже раз 100500 - не меньше.

Megawollt
Offline
Зарегистрирован: 06.12.2015

Не особо разобрался. Я так понял, мешает функция очистки дисплея, но как же без нее?

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

Молча. Зачем чистить целиком? Выводите букву, вот только её знакоместо и чистим, а веь экран зачем трогать?

Megawollt
Offline
Зарегистрирован: 06.12.2015

Подскажите как. Это мой первый проект на ардуино кроме мигания светодиодом.

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

В тех темах, что поиск выдаёт были готовые примеры, поищите.

Megawollt
Offline
Зарегистрирован: 06.12.2015

Не нашел. Честно

makc014
makc014 аватар
Offline
Зарегистрирован: 18.01.2016

Можно использовать фунцию "fillrect" или текст заменят пробелами. Все зависит от библиотеки

Megawollt
Offline
Зарегистрирован: 06.12.2015

А что это за функция? Библиотека от Adafruit

makc014
makc014 аватар
Offline
Зарегистрирован: 18.01.2016

это прямоугольник, число/текст замещаем черным прямоугольником

vde69
Offline
Зарегистрирован: 10.01.2016

зачем тебе нужно обновлять экран 3000 раз в секунду ???

сделай обновление 1 раз в секунду, даже с полной очисткой будет значительно лучше...

Megawollt
Offline
Зарегистрирован: 06.12.2015

Это уже интересно. А как? Делей использовать нельзя

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Megawollt пишет:

Это уже интересно. А как? Делей использовать нельзя

unsigned long CTime01;

unsigned long LTime01;
void setup()
{;}
void loop()
{ 

    CTime01 = millis();
    if (CTime01 >= (LTime01 +1000)) //задержка 1с
    {
     //Тут обновляем
     LTime01 = CTime01;  
    }
}

 

Megawollt
Offline
Зарегистрирован: 06.12.2015

Спасибо.Приеду на работу, попробую

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

Okmor, ну не так же! LTime01 используется до инициализации! Сравнение написано так, что боится переполнения! Человек же начинающий, ему аккуратно надо давать информацию, он пока не в состоянии такие вещи сам отследить.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

ЕвгенийП пишет:

Сравнение написано так, что боится переполнения! 

Тут уточние, а то я не понял. 

Я не большой спец по Ардуино. LTime01 фиксированого типа и функция millis() того же типа.

Вот если использовать unsigned int LTime01; Да тогда возможно переполнение.

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

Okmor пишет:

Тут уточние, а то я не понял. 

Я не большой спец по Ардуино. LTime01 фиксированого типа и функция millis() того же типа.

Вот если использовать unsigned int LTime01; Да тогда возможно переполнение.

значение millis через приблизительно месяц работы  переполняется и после самого большого для unsigned long значения (4 294 967 295) снова становится нулём.

При таком подходе, как у Вас, в этом момент произойдёт сбой. Смотрите:

1. допустим, что в момент очередного срабатывания LTime01  стала 4 294 966 296
2. через одну миллисекунду CTime01  будет  4 294 966 297, а LTime01 +1000 будет нулём.
3. Тогда Ваше условие благополучно сработает, хотя прошло не 1000 мс, а всего одна.

Чтобы такого не было, надо писать через вычитание и сравнивать с интервалом (см. пример "Миллис без делэй"). Там всё в порядке и никакого переполнения тот пример не боится.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

CTime01  будет  4 294 966 297, а LTime01 +1000 будет нулём.

Нет не будет 

  4 294 966 297  +1 = -2 147 483 648

-2 147 483 648+1 = -2 147 483 647

 и так по кругу.

Я всегда пользуюсь переполнением переменных  когда нужно создать очень быстры перебор значений.

Напимер

uint8_t MyBuff[255];

ISR(ADC_vect)
{
  MyBuff[N] =  ADCH;
  N++;

}

Работает на 10% быстрее чем IF ... THEN ...

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

Okmor пишет:

CTime01  будет  4 294 966 297, а LTime01 +1000 будет нулём.

Нет не будет 

  4 294 966 297  +1 = -2 147 483 648

-2 147 483 648+1 = -2 147 483 647

 и так по кругу.

Я всегда пользуюсь

Переменная, описанная, как unsigned long станет равной -2 147 483 648 ???? У меня больше нет вопросjв, пользуйтесь дальше :)))))

А слабо написать скетч из трех строк, в котором к переменной unsigned long, равной 4 294 967 295 прибавить единицу и напечатать, что получилось? :)))

 

Megawollt
Offline
Зарегистрирован: 06.12.2015

Спасибо за информацию, но в моем случае включение пульта больше, чем на час не планируется, поэтому такой вариант вполне устроит

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Уже давно сделано уважаемым лешаком.

http://arduino.ru/forum/programmirovanie/eshche-raz-migaem-svetodiodom-bez-delay#comment-39994

Ну и подробные пояснения тут:

http://alxarduino.blogspot.com/2013/09/ComfortablyBlinkWithoutDelay.html

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

trembo пишет:

Уже давно сделано уважаемым лешаком.

Это Вы мне или Окмору? Если мне, так у меня и нет возражений против того, как сделано у Лешака. А вот так как у Окмора - сломается при переполнении. Только он не хочет этого понять. Какие-то отрицательные числа для беззнакового типа приводит.

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

Megawollt пишет:
Спасибо за информацию, но в моем случае включение пульта больше, чем на час не планируется, поэтому такой вариант вполне устроит

Дело Ваше, только Вы сказали, что Вы человек начинающий. Так вот, не учитесь писать неправильно - это плохая привычка. Трудно что ли плюс на минус поменять и сделать правильно, как у Лешака?

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Извините.

Я ошибся. После 4294967295 будет не -2147483648, а 0,1,2,3,,, 

Видимо в этом контроллере учитывается обработа бита отрицательного значения.

Переполнения не будет, да и не может быть. Для переполнения надо использовать указатель адреса и записать туда тип большей битности. Особенно нужно быть внимательным при присвоении типа  = ( &value,sizeof(value) ). 

Код приведенный в примере Лешака не правильный. Потому, что к каждой задержке будет прибалятся время исполнения { action; } Измерять время можно только один раз. 

Поверьте мне, инженеру-механику.

// НЕ ПРАВИЛЬНЫЙ КОД!!!!!!!
     if( millis() - t > interval )    
    {                               
        { action; }                 
        t = millis();               
    }      
                         

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

Okmor пишет:

После 4294967295 будет не -2147483648, а 0,1,2,3,,, 

Переполнения не будет, да и не может быть. 

Именно это (сброс в 0) и называется переполнением, так что оно ещё как будет и именно из-за него не будет работать Ваш код (будет сбоить при переходе через 0).

Okmor пишет:

Код приведенный в примере Лешака не правильный. 

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

А вот что важно в том коде - он не сбоит при переполнении (переходе через 0, если Вам угодно). А то, что Вы написали - сбоит.

Okmor пишет:

Видимо в этом контроллере учитывается обработа бита отрицательного значения.

Не знаю, что Вы имеете в виду, но в этом контроллере всё абсолютно также, как и в любом другом - это общие правила арифметики в дополнительном коде.

Okmor пишет:
Поверьте мне, инженеру-механику.

Поверьте мне, как инженеру-программисту.

 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

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

Вы просили залить код в Ардуину, и я это сделал. На скриншоте видно момент так называемого переполнения. Только хочу заметить, что на скриншоте показал переполнение регистра, а переход на отрицательное значение смотрите здесь. Икак видно, что чудес не бывает и в контроллере как и всех других не учитывается переполнение бита знака числа. Да и вообще в контроллерах нету поняти знака числа - это все довольно условно.

Относительно компенсации времени исполнения тела функции.

- Нокогда не знаеш какое время отработает функция и ее нельзя заведомо компенсировать. Все нужно учитывать.

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

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

Okmor пишет:

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

Боюсь, что это Вы не понимаете. Вы путаете арифметическое переполнение с переполнением буфера. Ну, да Господь с Вами, специально ради Вас я готов называть арифметическое переполнение - "переходом через ноль".

Okmor пишет:

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

 
Разумеется, это так. Только писать надо правильно. В случае Вашего кода из поста №12 это приводит к сбою программы, о чём я Вам талдычу уже второй день. Даже не понимаю, с чем Вы спорите. Что, неужели не приводит? Приводит! Так и успокойтесь - о чём спорить-то?
 
Okmor пишет:
И еще. дайте пример переполнения переменной типа long, без использования указателей памяти, которое ведет к сбою программы.

Я никогда не говорю, о чём-то "вообще". Гармония вселенной - не моя тема. В данном топике мы говорим о Вашм коде, из поста №12. Там используется не long, а unsigned long.

Вам нужен пример переполнения unsigned long, которое приводит к сбою программы? Пожалуйста! Ваш код из поста №12 - и есть такой пример. Сбой проявляется в том, что при переходе через 0 задержка будет не 1с, а меньше.

Megawollt
Offline
Зарегистрирован: 06.12.2015

Эмм...Так как лучше поступить то?

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Megawollt пишет:

Эмм...Так как лучше поступить то?

Через 70 минут дам ответ. Запустил micros() на переполнение.

Megawollt
Offline
Зарегистрирован: 06.12.2015

Хотя наверное на так поставил вопрос. Примерно понятно что делать...

Стирать дисплей не миллион раз в минуту, а раз в секунду, но не будут ли накладываться цифры друг на друга при изменении параметров переменным резистором? Ведь значения изменяются быстрее частоты стрирания

 

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

Megawollt пишет:

Хотя наверное на так поставил вопрос. Примерно понятно что делать...

Стирать дисплей не миллион раз в минуту, а раз в секунду, но не будут ли накладываться цифры друг на друга при изменении параметров переменным резистором? Ведь значения изменяются быстрее частоты стрирания

А зачем Вам вообще его стирать с какой-то периодичностью?

Поменялось что-то - стёрли это место и перерисовали. А если ничего не меняется, так и стирать нечего - пусть торчит на экране без изменений хоть секунду, хоть минуту, хоть час.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Эксперимент переполнения.

Проскочили long.  Полет нормальный.

Ждем переполнения unsigned long.

 

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

Okmor пишет:

Эксперимент переполнения.

Проскочили long.  Полет нормальный.

Ждем переполнения unsigned long.

 

О, Господи, а что, написать MyMillis, которая стартует с близкого к переполнению числа и каждый раз его инкрементирует и выдаёт, и провести эксперимент за несколько секунд не судьба?

Да и зачем там эксперимент, когда и так всё ясно, в правой части получится 0, а в левой число заведомо большее? Впрочем, если Вам больше нечем заняться ....

vde69
Offline
Зарегистрирован: 10.01.2016
чего спорите?

i = millis()
if(  max(i,t)-min(i,t) > interval )  

 

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

vde69 пишет:

чего спорите?

i = millis()
if(  max(i,t)-min(i,t) > interval )  

 

Мы говорим о конкретном коде. А Вы что-то другое написали. Мы не это обсуждаем.

vde69
Offline
Зарегистрирован: 10.01.2016

а давайте обсуждать мой код, так интереснее :)

 

а обсуждать переполнение интов совсем к сабжу не относящаяся тема...

Megawollt
Offline
Зарегистрирован: 06.12.2015

Так, получается нужно прописать стирание после изменения информации на резисторе? Почему тогда первые две строки на дисплее отлично работают?

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

ЕвгенийП пишет:

vde69 пишет:

чего спорите?

i = millis()
if(  max(i,t)-min(i,t) > interval )  

 

Мы говорим о конкретном коде. А Вы что-то другое написали. Мы не это обсуждаем.

Вот оно ваше переполнение:

Попробую if(  max(i,t)-min(i,t) > interval )  

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Megawollt пишет:

Так, получается нужно прописать стирание после изменения информации на резисторе? Почему тогда первые две строки на дисплее отлично работают?

Уберите функцию display.clearDisplay(); из кода вообще. И пишите поверх предыдущего значения, добивая строку пробелами. А то у вас значения стираются, а потом выводятся. Отсюда и мерцание.

Megawollt
Offline
Зарегистрирован: 06.12.2015

Да, но если писать поверх предыдущего не стирая, то будет ведь наложение цифр?

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Megawollt пишет:

Да, но если писать поверх предыдущего не стирая, то будет ведь наложение цифр?

С этим дисплеем не работал. На моем перезатирает старые без мерцания и наложения.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Предлагаю вопрос с переходом через ноль вынести в отдельную тему. Надо Okmorа вывести на чистую воду.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Andy пишет:

Предлагаю вопрос с переходом через ноль вынести в отдельную тему. Надо Okmorа вывести на чистую воду.

В сад! Все в сад!

http://arduino.ru/forum/programmirovanie/zaderzhka-bez-delay-i-perepolneniya-schetchikov

Megawollt
Offline
Зарегистрирован: 06.12.2015

Я попробовал Ваш вариант. Дисплей моргает с частотой 1с :) Почему не моргают первые 2 строки при одинаковой частоте обновления?

makc014
makc014 аватар
Offline
Зарегистрирован: 18.01.2016

покажите весь код?

Megawollt
Offline
Зарегистрирован: 06.12.2015

В первом сообщении

makc014
makc014 аватар
Offline
Зарегистрирован: 18.01.2016

В первом используется команда очистки дисплея. Я не увидел изменений с учётом обсуждений здесь. Так же код можно оптимизировать, убрать дублирующие команды "дисплей" и "установка размера шрифта". Если будет время, я вам вечером скину код скорректированный

Megawollt
Offline
Зарегистрирован: 06.12.2015

Хорошо. Я думаю нет смысла скидывать код с тем, что предложили выше, так как изменилось всего две строки и то без толку.

Размер шрифтра там меняется всего один раз и обратно. А вот без команды дисплей ничего не отображается

makc014
makc014 аватар
Offline
Зарегистрирован: 18.01.2016
 //если кнопка "Вперед" нажата ...
078  if(digitalRead(fwdPin)==HIGH&&!digitalRead(bwdPin)==HIGH)
079  {
080  display.setTextSize(2);
081  
084  }//endif
085  
086  //если кнопка "Назад" нажата ...
087  if(digitalRead(bwdPin)==HIGH&&!digitalRead(fwdPin)==HIGH)
088  {
089  display.setTextSize(2);
090  
093  }//endif
094  
095  //если обе кнопки нажаты ...
096  if(digitalRead(fwdPin)==HIGH&&digitalRead(bwdPin)==HIGH)
097  {
098  display.setTextSize(2);
099  

зачем объявлять размер шрифта три раза?

makc014
makc014 аватар
Offline
Зарегистрирован: 18.01.2016

программа выполняется сверху-вниз

makc014
makc014 аватар
Offline
Зарегистрирован: 18.01.2016

Вот пример для одностраничного вывода информации. Если многостраничный режим - статичную информацию из setup перенести в loop

void setup()   {                

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)

 // display.display();
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1); 
 
 display.setCursor(0,0); 
 display.println("Battery voltage "); 
 
 display.setCursor(9,12); 
 display.println("Current speed  "); 
 
}

void loop() {
//display.clearDisplay();             //Очистка дисплея

 int ubat = random (0,20);       //Рассчет напряжения
 int spd_d =random (0,100);   //Маппинг скорости для дисплея из 255 в 100
 
 
 //Строка напряжения батареи
 display.setTextSize(1); 
 
 display.setCursor(94,0);
display.fillRect(94, 0, 100, 8, BLACK);

 display.print(ubat); 
 display.print("V"); 
 
 //Строка скорости
 
 display.setCursor(92,12);   
 display.fillRect(92, 8, 96, 14, BLACK);

 display.print(spd_d); 
 display.print("%"); 
 display.display();
 
  
 //если кнопка "Вперед" нажата ... 
 display.setTextSize(2); 

//условие 
 display.setCursor(15,25); 
 display.fillRect(0, 25, 120, 40, BLACK);
 display.println("Move FWD"); 
 display.display();

 delay (100);
//условие
 display.setCursor(10,25); 
 display.fillRect(0, 25, 120, 40, BLACK);
 display.println("Move BACK"); 
 display.display(); 
 
 delay (100);
 //условие
 display.setCursor(5,25);
 display.fillRect(0, 25, 120, 40, BLACK);
 display.println("BTN ERROR!"); 
 display.display();
 
 delay (100);
 
}