Программа Arduino, использующая i2c, перестает работать после нескольких раз печати на OLED

ПРИМЕЧАНИЕ О СТРУКТУРЕ ПРОЕКТА И ПРОГРАММЫ

Я разрабатываю проект Smart Watch с открытым исходным кодом, используя Arduino. Код можно найти здесь: https://github.com/shivangsgangadia/SmartWatch. Код слишком большой и разделен на несколько файлов, поэтому я не могу вставить его сюда в вопросе, поэтому прошу вас заглянуть в репозиторий github.

До сих пор я подключал OLED (128 X 64 SSD1306) и RTC (DS3231 в ZS-042). Я написал библиотеки для обоих, которые были включены в репозиторий Github.

Структура программы позволяет добавлять несколько «модулей», которые в основном похожи на приложения. Существует статический класс State, в котором хранится состояние программы, например модули, подлежащие обслуживанию, и время от RTC. Каждый «модуль» может быть «приложением» или «наложением». Оверлеи видны всегда, может быть несколько активных оверлеев, но одновременно может существовать только одно приложение.

ЧТО Я ПЫТАЮСЬ СДЕЛАТЬ?

  1. Чтение RTC в статические переменные класса State
  2. Показать один раз
  3. Прикрепите прерывание, чтобы установить логический флаг, когда RTC выдает прерывание (тревога). установлено на 1 минуту) Прерывание службы в цикле:

    • Чтение RTC в статические переменные класса State
    • Сбросить будильник для RTC
    • Обновить отображение

В ЧЕМ ПРОБЛЕМА?

Программа работает нормально 2-3 раза, т.е. делает то, что ожидается после обслуживания 2-3 прерываний (отсюда 2-3 минуты), но после этого печать на OLED искажается и программа вообще останавливается.

ЧТО Я ПЫТАЛСЯ РЕШИТЬ?

Используя Serial.println() во многих областях, таких как до и после вызова OLED::writeString в соответствующих классах, я пришел к выводу, что проблема не в RTC , но OLED каким-то образом заставляет программу останавливаться.

Удаление инструкций OLED::writeString позволяет продолжить печать в течение более чем 2-3 раз, но в конечном итоге программа останавливается. Я пытался заменить провода и макетную плату, но ничего не помогло.

, 👍1

Обсуждение

Я не вижу ничего сразу очевидного (престижность вам за ваш аккуратный стиль программирования и отсутствие у вас чего-либо, связанного со строками). Скорее всего, это связь I2C. Это не здорово по проводам или с макетами. Вы можете попробовать добавить меньшие (1 кОм) подтягивающие резисторы на провода I2C., @Majenko

Спасибо за комплимент ! Я попытался добавить подтяжки 1k и передать соединения OLED через дополнительные выводы модуля ZS04, и это все еще не работает., @Shivang Gangadia


2 ответа


Лучший ответ:

4

Это неправильно во многих отношениях:

String input = Serial.readString();
serialInputBuffer = new char[input.length()];
input.toCharArray(serialInputBuffer, input.length());

Фатальным является то, что позже вы не освободите память, выделенную с помощью new. Не используйте String и new. Оба используют память кучи и будут фрагментировать ее этими небольшими выделениями до тех пор, пока не останется места для следующего выделения. Я вижу, у вас есть динамическое выделение в других частях скетча, и там похоже, что у вас есть delete, но они все еще вызывают проблему фрагментации.

Используйте глобальный буфер, например char serialInputBuffer[64]; и используйте:

int l = Serial.readBytes(serialInputBuffer, sizeof(serialInputBuffer));
serialInputBuffer[l] = 0;

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

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

,

Я попытался закомментировать всю часть Serial, и это все еще не имеет никакого эффекта., @Shivang Gangadia

@ShivangGangadia, у вас есть несколько динамических распределений в других частях скетча, и похоже, что у вас есть удаление, но они все еще вызывают проблему фрагментации., @Juraj

Я заменил все динамические аллокации статикой внутри модулей. Тем не менее, не имеет никакого эффекта, @Shivang Gangadia

@ShivangGangadia, почему вы используете pgm_read_word для чтения байтов?, @Juraj

Потому что нужные мне байты, то есть шрифт, находятся в PROGMEM, @Shivang Gangadia

@ShivangGangadia, pgm_read_byte?, @Juraj

@ShivangGangadia, вы выделяете «toReturn» в «scale» много раз, но не удаляете его. (только последний в writeString), @Juraj

Ты был прав ! Хотя я мог бы обойтись всего одним динамическим распределением, но встроенные системы действительно неумолимы. Пожалуйста, просмотрите и одобрите запрошенные мной правки, чтобы я мог принять это как правильный ответ., @Shivang Gangadia


-1

Не используйте библиотеку Wire. Если вы внимательно посмотрите на twi.c, то обнаружите, что в нем есть блокирующие вызовы с (потенциально) бесконечными циклами. В конце концов возникнет условие, из-за которого один из блокирующих вызовов зависнет навсегда.

См. эту публикацию и этот пост для подробностей

Используйте что-то вроде SBWire

Фрэнк

,

Я заменил библиотеку Wire на SBWire. Все еще нет улучшения., @Shivang Gangadia

Хорошо, теперь вы вернулись к основному устранению неполадок. Временно откажитесь от своего проекта и создайте новый, используя только Arduino и OLED — ничего больше — и самый простой код для его управления., @user3765883

Как только у вас заработает этот простой проект, вы сразу узнаете, является ли проблема OLED и его драйвером., @user3765883

Сделал шаг за шагом, примет ответ Юрая, @Shivang Gangadia