Jump to content

Последовательный вывод данных на LCD


_FREEMAN_
 Share

Recommended Posts

Здравствуйте.
Прошу Вас оказать помощь в нахождении ошибки в коде. Ниже приведён код цель которого выдавать соответствующие события на дисплей. Но при комбинации 1 го и 6 сообщения на экран циклично выходит абракадабра. Также прилагаю ссылку на видео демонстрирующую данную проблему. На многих форумах просил помочь найти проблему но пока без результата. Прошу не проходите мимо, Залейте этот скетч в ардуино и подключите только LCD 1602 и по истечению 1 минуты увидите мою проблему. За ранее благодарю.

https://youtu.be/lFPrrpiXIzY

#include <LiquidCrystal_I2C.h>

#include <Wire.h> 

LiquidCrystal_I2C lcd(0x27,16,2);  // устанавливаем адрес 0x27, и дисплей 16 символов в 2 строки (16х2)

#define BUTTON_PIN                 2
#define RX_PIN                     0
#define TX_PIN                     1
#define BUZZER_PIN                 9
#define BACKLIGHT_PIN              13
#define LCD_HEIGHT                 2
#define LCD_WIDTH                  16
#define MSG_COUNT                  8

boolean needUpdateLCD =            true;                    // флаг-признак необходимости одновить данные на дисплее
String lcdBuffer[LCD_HEIGHT];
const unsigned int updateTime =    2000;                    // интервал смены надписей в нижней строке
const unsigned int flashTime =     250;                     // интервал мигания цифр (при аварии)
boolean msgFlag[MSG_COUNT] =      {0, 0, 0, 0, 0, 0, 0, 0 }; // флаги текущих состояний UPS (1 - это авария)
const String message[MSG_COUNT] = {                         // сообщения об авариях
  "U1 Inverter Off ",
  "U1 On Battery   ",
  "U1 General Alarm",
  "U1 Inverter Off ",
  "U2 Inverter Off ",
  "U2 On Battery   ",
  "U2 General Alarm",
  "U2 Inverter Off ",
};

#define TIMEOUT(tm, lastTm) (millis() - lastTm > tm)         // принять как аксиому :)

/*-----( Import needed libraries )-----*/




// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
//LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

//LiquidCrystal_I2C lcd(0x27, BACKLIGHT_PIN, POSITIVE);  // Set the LCD I2C address

// Прототипы функций (чтобы компилятор не ругался)
void displayData();
void dataManager();
void buzzer(byte pin);
void readButtons(byte pin);
void readSerial(byte rxPin);
void sendData(byte txPin);


void loop()
{
  readButtons(BUTTON_PIN);      // сканируем кнопку
  readSerial(RX_PIN);           // слушаем Serial
  dataManager();                // обработка данных
  sendData(TX_PIN);             // отправка данных
  displayData();                // отображение информации
  buzzer(BUZZER_PIN);           // звуковые уведомления
  ledControl();                 // моргание нужными LED
}


void dataManager()
{
  // тут обработка каких-то данных
  // ...

  // эмуляция неисправности трех UPS через 1 мин после включения питания
  if (millis() > 5000)
  {
    msgFlag[0] = true;  // авария на 1-м UPS
    //msgFlag[1] = true;  // авария на 2-м UPS
    //msgFlag[2] = true;  // авария на 3-м UPS
    //msgFlag[3] = true;  // авария на 4-м UPS
    //msgFlag[4] = true;  // авария на 5-м UPS
    msgFlag[5] = true;  // авария на 6-м UPS
    //msgFlag[6] = true;  // авария на 7-м UPS
    //msgFlag[7] = true;  // авария на 8-м UPS
  }

}



void displayData()
{
  // формирование первой строки для вывода на дисплей
  static unsigned long lastFlashTime;
  lcdBuffer[0] = "1 2 3 4 5 6 7 8";          // шаблон для первой строки
  if (TIMEOUT(flashTime, lastFlashTime))     // каждые 0,25 сек формируем первую строку
  {
    static boolean flashFlag = true;
    if (flashFlag)
    {                                        // проверяем флаги на наличие ошибок
      for (byte ups = 1; ups <= MSG_COUNT; ups++)
        if (msgFlag[ups - 1]) lcdBuffer[0].replace(String(ups), "x"); // где ошибка - ставим хер
    }
    flashFlag = !flashFlag;
    lastFlashTime = millis();
    needUpdateLCD = true;
  }

  // формирование второй строки для вывода на дисплей
  static unsigned long lastUpdateTime;
  if (TIMEOUT(updateTime, lastUpdateTime))   // каждые 2 сек формируем вторую строку
  {
    lcdBuffer[1] = "                ";   // 20 пробелов (у меня 20 знаков на дисплее)
    lastUpdateTime = millis();
    //needUpdateLCD = true;                  // не нужно, т.к. первая строка все равно чаще обновляет ЖК
    byte ups = 0;
    while (!msgFlag[ups])                    // проверяем флаги на наличие ошибок
    {
      ups++;
      if (ups >= MSG_COUNT)                  // если нет ни одной ошибки, то выходим
      {
        ups = 0;
        return;
      }
    }
    // сюда попадаем, если есть хоть одна ошибка
    static byte c = 0;
    while (!msgFlag[c]) c++;                 // пропускаем сообщения, к которым ошибка не относится
    lcdBuffer[1] = message[c];               // буферизуем сообщение
    c++;                                     // чередуем все сообщения об ошибках
    if (c >= MSG_COUNT - 1) c = 0;

  }

  // обновление данных на дисплее
  if (needUpdateLCD)
  {
    lcd.setCursor(0, 0);
    lcd.print(lcdBuffer[0]);

    lcd.setCursor(0, 1);
    lcd.print(lcdBuffer[1]);

    needUpdateLCD = false;
  } // if
} // displayData



void ledControl()
{
}



void buzzer(byte pin)
{
}



void readButtons(byte pin)
{
}



void readSerial(byte rxPin)
{
}



void sendData(byte txPin)
{
}


void setup()
{
  lcd.init();                     // инициализация LCD 
  lcd.backlight();                // включаем подсветку
  pinMode ( BACKLIGHT_PIN, OUTPUT );
  digitalWrite ( BACKLIGHT_PIN, HIGH );
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);
  lcd.backlight(); // finish with backlight on
  lcd.clear();
}

 

Link to comment
Share on other sites

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

30 минут назад, _FREEMAN_ сказал:

На многих форумах просил помочь найти проблему но пока без результата.

Потому, что мало кто будет тратить время на разбор этой всей каши. А уж тем более собирать это в железе и пробовать Вашу программу.
Создайте минимальный код, при котором выявляется эта проблема и уже выкладывайте его на форумы. А то совсем не понятно, что за 1 и 6 событие, что за цикличный их вывод, причём тут 1 минута, .... :unknw:

 

Link to comment
Share on other sites

Реле, разъемы, вентиляторы, корпуса, микросхемы, конденсаторы и много другое!

Скидки до 20% на сайте электронного дискаунтера ТМ Электроникс.

Бесплатная доставка в любую точку России + кэшбэк 15%.

Подробнее

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

На первый взгляд, можно Вам посоветовать уйти от класса String. Ваши сообщения можно без проблем вывести с помощью обычный строк в С-стиле (аля массивы). 
String использует кучу, так что хрен знает, что там в ней твориться, учитывая такие мизерные объёмы памяти. Плюс ко всему - нерациональный перерасход памяти. Как минимум, 2 экземпляра каждой строки в ОЗУ (строка при копировании и строка в куче) + 1 экземпляр в flash-памяти.

 

И ещё, Вам нужно пересмотреть реализацию очереди сообщений. Как то она запутанно сделана...

 

Link to comment
Share on other sites

Материалы вебинара «Литиевые аккумуляторы EVE Energy и решения для управления перезаряжаемыми источниками тока»

Опубликованы материалы вебинара Компэл, посвященного литиевым аккумуляторам EVE Energy и решениям для управления перезаряжаемыми источниками тока.

На вебинаре мы представили информацию не только по линейкам аккумуляторной продукции EVE, но и по решениям для управления ею, что поможет рассмотреть эти ХИТ в качестве дополнительной альтернативы для уже выпускающихся изделий. Также рассмотрели нюансы работы с производителем и сервисы, предоставляемые Компэл по данной продукции. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Уважаемый Alex это и есть минимальный код из всей программы которую я написал. Мне нужно исправить ошибку вывода событий на экран. Излагая по простому мне нужен код который будет в одной строке высвечивать и чередовать сообщения о включённых лампочках. Всего лампочек 8 но включаться будут в произвольном порядке. Например 1 и 4, на дисплее чтобя в нижней строке писалось ("Лампа 1 горит" пауза 5 сек в той же строке "Лампа 4 горит") если выключилась лампа 1 и включилась лампа 2 соответственно сообщения должны быть верными. В коде есть ошибка формирования второй строки. Он отмечен комментом. Я начинающий и нет таких знаний чтобы найти данную проблему. Его залить в ардуинку минутное дело и сразу станет понятно. На видео чётко видна проблема. А весь проект опишу так.

Задача состоит в следующем. Два помещения находятся на расстоянии 300 метров между которыми есть холостая витая пара. В помещении первом стоит одна Atmega328p настроенная на приём 8 событий, вторая же Atmega328p на приём и информирование о событиях в первом помещении. Я настроил оба контроллера и они общаются между собой через COM по RX/TX пинам, после завершения пилотирования поставлю RS485.

Логика и схема такова:

1 – контроллер –

· 8 пинов на вход событий

· 1 пин лед отклик от второго устройства что он не завис

· 1 пин переключение режима на RS485

2 – Контроллер

· 8 пинов леды информирующие о сработке на первом контроллере

· 1 пин лед отклик от первого устройства что он не завис

· 1 пин кнопка при нажатии которого посылается код опроса первого устройства на котором 3 раза моргнёт лед и вернётся код об успешном отклике, затем 3 раза маргнёт лед на втором устройстве.

· 1 пин пищалка в случае любого события на первом контроллере пищит

· 2 пина LED дисплей 16х2 по I2C на котором тоже высвечивается информация о сработке.



ЛОГИКА:

ДЕЙСТВИЕ СРАБОТКА

1 Контроллер – в случае сработки посылает в COM букву или цифру соответствующую данному действию.

2 Контроллер приняв букву выполняет действия (зажигает лед, пищит, пишет на экране)

Точно также происходит выключение действия.



ДЕЙСТВИЕ ПРОВЕРКА СВЯЗИ

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

 

 

Link to comment
Share on other sites

Комплексные решения с литиевыми батареями EVE для интеллектуальных систем безопасности

Литиевые химические источники тока EVE по своим характеристикам являются идеальным выбором для современных интеллектуальных систем безопасности. EVE разрабатывает литиевые батареи, опираясь на многолетние исследования таких областей применения, как беспроводная связь стандартов Bluetooth, LoRa, Wi-Fi, NB-IoT и ZigBee. Рассмотрим решения для систем безопасности с использованием батарей EVE. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Для начала, воспользуйтесь советом по уходу от класса String. Это первое, что нужно Вам сделать.

И ещё. На видео высвечивается строка "UPS 2 On Battery", в коде строка немного не та. Есть подозрение, что и код, залитый в МК может отличаться от того, который мы видим :)




 

50 минут назад, _FREEMAN_ сказал:

это и есть минимальный код из всей программы которую я написал

Это вырезанный кусок из программы. А я говорил о создании полноценного минимального кода, при залитии в МК которого, проявляется проблема.
Это немного 2 разные вещи :)
Неизвестно что у Вас может запарывать кучу. Вы добейтесь минимум кода, при котором начинается проблема. Уверен на 99%, что это поможет Вам самостоятельно определить проблему, т.к. будет известно от чего она появляется.
Никаких других советов, скорее всего, Вы на форумах не услышите...

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




 

Link to comment
Share on other sites

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Кстати, вот тут :

while (!msgFlag[c]) c++;

потенциальная ошибка. Попробуйте догадаться какая.
И, скорее всего, проблема из-за неё.


 

Link to comment
Share on other sites

Уважаемый Alex. Выставленный мною код является автономным мне необходимо исправить ошибку в нём так как я затем его применяю в основной программе. Если вы видите в нём ошибку укажите пожалуйста на неё. Я не знаю почему именно при комбинации 1 и 6 происходят эти глюки на экране. Вот ссылка на видео в которой 1, 2 и 3 сработка https://www.youtube.com/watch?v=QMeUeBFLM74  тут всё прекрасно работает. ниже выставление событий. Я думал дело в дисплее но на другом даже 4 строчном та же проблема. Если есть возможность и желание помогите.

// эмуляция неисправности трех UPS через 1 мин после включения питания
  if (millis() > 5000)
  {
    msgFlag[0] = true;  // авария на 1-м UPS
    msgFlag[1] = true;  // авария на 2-м UPS
    msgFlag[2] = true;  // авария на 3-м UPS
    //msgFlag[3] = true;  // авария на 4-м UPS
    //msgFlag[4] = true;  // авария на 5-м UPS
    //msgFlag[5] = true;  // авария на 6-м UPS
    //msgFlag[6] = true;  // авария на 7-м UPS
    //msgFlag[7] = true;  // авария на 8-м UPS
  }

 

В комменте написанно 1 мин но для быстроты проверки уменьшил до 5 сек. Если залить код в Ардуинку то через 5 сек увидите проблему.

Link to comment
Share on other sites

9 часов назад, Alex сказал:

Кстати, вот тут :


while (!msgFlag[c]) c++;

потенциальная ошибка. Попробуйте догадаться какая.
И, скорее всего, проблема из-за неё.


 

Если вы об этом ответе? Может у чукчи это считается помощью, сомневаюсь что многие сочтут этот ответ как решение проблемы. Но уже не нужно проблема решена иным способом. Тема закрыта.

Link to comment
Share on other sites

// сюда попадаем, если есть хоть одна ошибка
    static byte c = 0;						// УБЕРИТЕ static
    while (!msgFlag[c]) c++;
    lcdBuffer[1] = message[c];
    c++;                                     // ЭТА СТРОКА РАБОТАТЬ НЕ БУДЕТ
    if (c >= MSG_COUNT - 1) c = 0;			 // ЭТА СТРОКА РАБОТАТЬ НЕ БУДЕТ

а можно вместо выше указанного кода написать

lcdBuffer[1] = message[ups];

у вас проблема возникает каждые 2 секунды смотри подробнее код с таймаутом 2 секунды

p.s.
arduino не занимаюсь, проверить не могу

Edited by dm37
Link to comment
Share on other sites

10 минут назад, _FREEMAN_ сказал:

сомневаюсь что многие сочтут этот ответ как решение проблемы

А что же это по-Вашему ? 
Если бы Вы были автором кода, то моментально поняли бы о чём идёт речь. Или ищем ответа "Поменяйте вот это на это" ?
Мне 15-ти минут хватило, чтобы проанализировать код и понять в чём проблема, а Вы с явной подсказкой сутки не можете понять...

10 минут назад, _FREEMAN_ сказал:

проблема решена иным способом

Ну-ну... Рассказывайте сказки...




 

@dm37 , static'ом автор хотел сделать, чтобы был перебор и вывод следующего сообщения. Тем самым, наступив на грабли.
Но автор - точно не ТС. ТС - чукча-копипастер. Причём неблагодарный. Вместо "спасибо" за указание на ошибку в его говнокоде, он тут слюнями брызгает.





 

Link to comment
Share on other sites

7 минут назад, Alex сказал:

Но автор - точно не ТС.

а что такое "ТС"?

пусть сначала так заработает (первое сообщение отображает), потом доделает

Edited by dm37
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...