Каталог товаров
Клиенту
+38 (066) 305-77-25
Наш адрес
Харьков, времено - только доставка Новой Почтой, УкрПочтой, МистЕкспрес, ROZETKA Delivery
Телефоны:
Время работы
  • Пн-Пт: с 9 до 18
  • Сб.: с 10 до 17
  • Вс: с 11 до 16
E-mail
Мы в соцсетях
Перейти в контакты
0 0
Каталог
Главная
Закладки
0
Сравнить
0
Контакты

Моніторинг стану батареї з використанням JKBMS та TFT дисплея

Моніторинг стану батареї з використанням JKBMS та TFT дисплея

Проект мониторинга состояния батареи

Проект мониторинга состояния батареи с использованием JKBMS и TFT дисплея

Недавно получил аккумуляторы LiFePo4 на 3.2V 304Ah и BMS плату от JiKongBMS на 200А (разряд).

Сборка

После сборки и подключения по Bluetooth стало очевидно, что каждый раз заходить в приложение для просмотра информации не очень удобно. Сначала я планировал использовать вольтметр или универсальный индикатор батареи, но особенность LiFePo4 заключается в том, что график разряда на большей части емкости является почти прямой линией. Это означает, что при напряжении, например, 3.3 В на каждой ячейке, довольно сложно определить оставшуюся емкость аккумулятора. А вот использование информации от BMS открывало совсем другие возможности: она могла предоставлять более точные данные о состоянии батареи, такие как SOC (State of Charge) и другие ключевые показатели, которые помогают понять текущий уровень заряда.

Поэтому возникла идея создать проект по мониторингу состояния батареи на базе системы управления батареей JKBMS и дисплея TFT ST7735. Целью было иметь возможность в реальном времени отслеживать ключевые параметры аккумулятора, такие как напряжение ячеек, ток, SOC (State of Charge), температуры и другие важные показатели. Хочу поделиться своим опытом, проблемами, с которыми столкнулся, и путями их решения.

Да, да, я знаю, что можно было купить готовый дисплей для JKBMS. Но простые варианты сразу откинул, очень хотелось "попаять" - не зря за плечами диплом инженера. И с готовым дисплеем не было бы этой статьи. Поэтому самое интересное дальше:

Проблематика: основные вызовы при реализации проекта

Сначала все казалось простым: подключить дисплей к микроконтроллеру, получать данные от JKBMS и выводить их на экран. Но, как всегда бывает в электронике и программировании, реальность оказалась иной (примерно как в этой статье). Основные проблемы, с которыми я столкнулся:

  • Подключение и совместимость устройств: JKBMS использует UART для передачи данных, но нужно было правильно настроить связь с микроконтроллером.
  • Обработка полученных данных: Данные от BMS поступают в специфическом формате, который нужно правильно парсить.
  • Отображение информации на дисплее: Нужно было разработать интерфейс, который был бы удобным и информативным.
  • Работа с кнопкой для переключения экранов: Реализация стабильной работы кнопки с антидребезгом была вызовом, даже когда все было подключено правильно, она все равно отказывалась работать.
  • Энергосбережение: Автоматическое выключение подсветки дисплея после определенного времени неактивности.

Подключение компонентов

Для начала нужно было выбрать подходящий микроконтроллер. После целого дня работы с ESP8266 CH340✨Wi-Fi платой NodeMCU, я понял, что ее недостаточно - одновременно работать с разными портами ей сложно (хотя не исключаю, что это может быть из-за моих рук). Поэтому я выбрал STM32F103C8T6 (так называемый "Blue Pill") потому, что он был под рукой 😊, а еще - он умеет одновременно работать с несколькими UART портами. Сначала подключал к ПК через USB-UART программатор, уже позже догадался использовать ST-LINK V2.

Обратите внимание на ПОДПИСАННЫЕ ПИНЫ на ваших устройствах, потому что разные производители могут их "чередовать", и то, что изображено, не всегда соответствует действительности.

Схема подключения

Дисплей TFT ST7735:

  • CS (Chip Select) – к пину PB0 (настраивается программно)
  • RST (Reset) – к PB1 (настраивается программно)
  • DC (Data/Command) – к PB10 (настраивается программно)
  • MOSI – к PA7 (по умолчанию для SPI1)
  • SCK – к PA5 (по умолчанию для SPI1)
  • Подсветка – к PB4 (через резистор для управления)

JKBMS:

  • TX (от BMS) – к PA3 (RX микроконтроллера)
  • RX (к BMS) – к PA2 (TX микроконтроллера)

Кнопка:

  • Один контакт – к PA0
  • Другой контакт – к GND
  • Пин PA0 настроен с внутренним подтягивающим резистором (INPUT_PULLUP), хотя я для уверенности также через резистор подтянул +3V.

Подключение дисплея не вызвало проблем.

Разъем GPS

А вот, чтобы найти в разъеме на JKBMS выводы RX/TX, пришлось немного погуглить. Оказалось, что в зависимости от "ревизии" платы, "+" и "GND" могут быть симметричными. С помощью мультиметра определил где "VCC" и соответственно рядом с ним должен быть TX.

Определение rx_tx

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

На практике это выглядит так: 

Реальное подключение

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

Пройдусь немного по блокам кода

Начнем с подключения необходимых библиотек и объявления переменных:

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include "FontsRus/TimesNRCyr10.h"  // Шрифт для кириллицы

Кстати, по поводу кириллицы: украинская буква "і" при выводе на дисплей заменяется английской "i". Это, конечно, "костыль", но пока так пойдет.

Объявляем пины для дисплея и создаем его объект:

#define TFT_CS     PB0
#define TFT_RST    PB1
#define TFT_DC     PB10

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

Настраиваем UART для связи с JKBMS:

#define BMS_RX     PA3
#define BMS_TX     PA2
HardwareSerial &BMS = Serial2;

Объявляем пин для кнопки и управления подсветкой:

#define BUTTON_PIN PA0
#define TFT_BACKLIGHT_PIN PB4

Логика работы кнопки

Один из вызовов был в том, чтобы кнопка работала стабильно без ошибочных срабатываний. Для этого реализован антидребезг. Основное назначение кнопки - переключение экранов. Также настроил автоматическое переключение экранов каждые 10 секунд и засыпание дисплея через 5 минут неактивности:

void loop() {
  bool reading = digitalRead(BUTTON_PIN);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == LOW) {
        if (displaySleep) {
          displaySleep = false;
          lastInteractionTime = millis();
          digitalWrite(TFT_BACKLIGHT_PIN, HIGH);
          updateDisplay();
        } else {
          screenIndex = (screenIndex + 1) % 5;
          lastInteractionTime = millis();
          lastScreenChangeTime = millis();
          updateDisplay();
        }
      }
    }
  }

  lastButtonState = reading;

  // Автоматическое переключение экранов
  if (millis() - lastScreenChangeTime >= 10000 && !displaySleep) {
    screenIndex = (screenIndex + 1) % 5;
    updateDisplay();
    lastScreenChangeTime = millis();
  }

  // Выключение дисплея после 5 минут неактивности
  if (millis() - lastInteractionTime >= 300000 && !displaySleep) {
    displaySleep = true;
    digitalWrite(TFT_BACKLIGHT_PIN, LOW);
    tft.fillScreen(ST77XX_BLACK);
  }
}

Получение и обработка данных от JKBMS

Здесь пришлось немного поработать. Согласно инструкции JKBMS, надо вежливо попросить ответ через отправку запроса "send→ 4E 57 00 13 00 00 00 00 06 03 00 ◇ 00 00 00 00 00 68 00 00 01 29".

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

Основная логика получения данных реализована в функции updateDisplay():

void updateDisplay() {
  uint8_t request[] = {
    0x4E, 0x57, // ... остальные байты запроса
  };

  uint8_t responseBuffer[256] = {0};

  while (BMS.available()) {
    BMS.read();
  }

  BMS.write(request, sizeof(request));

  unsigned long startMillis = millis();
  int index = 0;
  bool responseReceived = false;

  // Читаем данные в течение 50 мс
  while (millis() - startMillis < 50) {
    if (BMS.available()) {
      if (index < sizeof(responseBuffer)) {
        responseBuffer[index++] = BMS.read();
        responseReceived = true;
      } else {
        BMS.read();
      }
    }
  }

  // Отображение данных или сообщение об ошибке
  if (responseReceived) {
    displayData(responseBuffer, index);
  } else {
    displayError();
  }
}

Отображение данных на дисплее

Парсинг происходит с помощью инструкции. В интернете есть ее описание, поэтому не буду сосредотачивать на этом внимание. В зависимости от screenIndex отображаются разные экраны. Например, для отображения состояния батареи:

void displayData(uint8_t* buffer, int length) {
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextColor(ST77XX_WHITE);

  switch (screenIndex) {
    case 0:
      displayBatteryStatus(buffer);
      break;
    // Другие случаи...
  }
}

Добавил несколько функций для интерактивности дисплея, например цвет в зависимости от состояния заряда. Вот функция для отображения состояния батареи:

void displayBatteryStatus(uint8_t* buffer) {
  int soc = buffer[SOC_INDEX];
  tft.setTextColor(ST77XX_GREEN);
  tft.setCursor(5, 15);
  tft.println("Состояние батареи");
  tft.drawLine(0, 25, 160, 25, ST77XX_WHITE);

  tft.setTextColor(ST77XX_WHITE);
  tft.setCursor(5, 45);
  tft.print("SOC: ");
  tft.print(soc);
  tft.println("%");

  uint16_t socColor = ST77XX_GREEN;
  if (soc < 20) {
    socColor = ST77XX_RED;
  } else if (soc < 50) {
    socColor = ST77XX_ORANGE;
  }
  tft.drawRect(5, 60, 100, 15, ST77XX_WHITE);
  tft.fillRect(6, 61, soc, 13, socColor);

  uint16_t totalVoltage = (buffer[TOTAL_VOLTAGE_INDEX] << 8) | buffer[TOTAL_VOLTAGE_INDEX + 1];
  tft.setCursor(5, 100);
  tft.print("Напряжение: ");
  tft.setTextColor(ST77XX_RED);
  tft.print(totalVoltage / 100.0);
  tft.println("V");
}

Вот так выглядит код в работе:

Отображение на экранах

Проблемы и их решения

  • Задержка между нажатием кнопки и сменой экрана: Сначала была значительная задержка при переключении экранов. Это было из-за того, что в функции updateDisplay() мы ждали 200 мс на получение данных от BMS. Уменьшив это время до 50 мс, мы достигли более быстрой реакции. ⚡
  • Проблемы с пином для кнопки: Пин PB3 не работал должным образом для кнопки. Оказалось, что этот пин может быть занят другими функциями или не поддерживает внутренний подтягивающий резистор. Заменив его на PA0, мы решили проблему. ✅
  • Автоматическое засыпание дисплея: Сначала дисплей выключался через 3 минуты. Я решил увеличить это время до 5 минут, изменив проверку неактивности. Можете выставить как вам удобно:
if (millis() - lastInteractionTime >= 300000 && !displaySleep) {
  // ...
}

Теперь можно переходить к монтированию в корпус, чтобы выглядело аккуратно и было удобно пользоваться. Кнопку логично вывести рядом с дисплеем. Для крепления деталей можно использовать двусторонний скотч, небольшие винтики или даже горячий клей (зависит от того, насколько крепко хотите закрепить). Не забудьте про вентиляцию, чтобы устройство не перегревалось. После этого остается только проверить, все ли порты и кнопки работают, и можно смело тестировать, подключать и пользоваться!

Мой вывод

Этот проект оказался интересным и полезным опытом. Я научился работать с JKBMS, обрабатывать данные с UART и отображать их на дисплее. Хотя были проблемы, их решение помогло мне глубже понять работу микроконтроллера и периферийных устройств.

Советы для тех, кто хочет повторить этот проект:

  • Подробно ознакомьтесь со спецификациями вашего BMS и микроконтроллера. 📚
  • Проверяйте аппаратное подключение с помощью мультиметра. 🛠️
  • Используйте серийный монитор для отладки и вывода диагностической информации. 🖥️
  • Не бойтесь экспериментировать и менять код под свои нужды. 💡

UPD1 (дополнение статьи №1)

Помимо основных параметров, на TFT-дисплее можно отображать и другие данные, которые передаются по протоколу RX-TX. На скриншотах можно увидеть этот обширный объем информации. По сути, это позволяет пользователю создать "аналог" приложения на экране и отслеживать его параметры в реальном времени. Все эти данные значительно облегчают контроль за работой батареи, обеспечивая своевременное выявление потенциальных проблем и оптимизацию процесса зарядки и разрядки.

Данные, которые можно отображать

Загрузка необходимого скетча

Для успешного выполнения проекта вам нужно загрузить файл:

Загрузить скетч

Загрузить расшифровку полученного ответа от JKBMS

Удачи с проектом вместе с myproject.com.ua.

© 2024 Мій Проект. Автор: Jazzzman. Использование материалов разрешено только со ссылкой на источник.

Рекомендуемые товары