#include #include #include #include // --- ПИНЫ RS485 --- #define INV_RX 4 #define INV_TX 5 #define INV_DE 6 #define BMS_RX 7 #define BMS_TX 15 #define BMS_DE 16 // --- ПИНЫ ДИСПЛЕЯ --- #define TFT_CS 3 #define TFT_DC 17 #define TFT_RST 18 #define TFT_SCLK 12 #define TFT_MOSI 11 Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); float mVolt = 0; float mCurr = 0; int mSoc = 0; uint16_t getCRC(const uint8_t *buf, size_t len) { uint16_t crc = 0xFFFF; for (size_t pos = 0; pos < len; pos++) { crc ^= (uint16_t)buf[pos]; for (int i = 8; i != 0; i--) { if ((crc & 0x0001) != 0) { crc >>= 1; crc ^= 0xA001; } else crc >>= 1; } } return crc; } void drawUI() { static unsigned long lastDraw = 0; if (millis() - lastDraw < 5000) return; lastDraw = millis(); // SOC - шрифт 11, Желтый на Черном tft.setTextSize(11); tft.setCursor(0, 10); tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK); tft.printf("%3d%%", mSoc); // V и A - шрифт 4, Белый на Черном tft.setTextSize(4); tft.setCursor(10, 145); tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK); tft.printf("%4.1fV %4.1fA", mVolt, mCurr * 3.0f); } void setup() { Serial.begin(115200); pinMode(TFT_RST, OUTPUT); digitalWrite(TFT_RST, LOW); delay(150); digitalWrite(TFT_RST, HIGH); delay(150); tft.init(240, 320); tft.setRotation(1); // ПРИНУДИТЕЛЬНО ВЫКЛЮЧАЕМ ИНВЕРСИЮ tft.invertDisplay(false); tft.fillScreen(ST77XX_BLACK); Serial1.begin(9600, SERIAL_8N1, INV_RX, INV_TX); Serial2.begin(9600, SERIAL_8N1, BMS_RX, BMS_TX); pinMode(INV_DE, OUTPUT); pinMode(BMS_DE, OUTPUT); } void loop() { // Проброс Инвертор -> BMS if (Serial1.available()) { digitalWrite(BMS_DE, HIGH); while (Serial1.available()) Serial2.write(Serial1.read()); Serial2.flush(); digitalWrite(BMS_DE, LOW); } // Ответ BMS -> Инвертор if (Serial2.available()) { uint8_t buf[128]; int len = 0; uint32_t t = micros(); while (micros() - t < 15000 && len < 128) { if (Serial2.available()) { buf[len++] = Serial2.read(); t = micros(); } } // Если пришел нужный пакет данных (43 байта) if (len == 43 && buf[0] == 0x01 && buf[1] == 0x03) { // Напряжение (индексы 3-4) mVolt = (float)((buf[3] << 8) | buf[4]) * 0.01503f; // Заряд (индекс 14) mSoc = buf[14]; // Ток (индексы 32-33) int16_t cRaw = (int16_t)((buf[32] << 8) | buf[33]); mCurr = (float)cRaw * 0.001f; // Подмена лимита тока на 75А для Growatt buf[21] = 0x1D; buf[22] = 0x4C; uint16_t newCrc = getCRC(buf, len - 2); buf[len - 2] = newCrc & 0xFF; buf[len - 1] = (newCrc >> 8) & 0xFF; // СНАЧАЛА отправка инвертору (критично для отсутствия ошибок связи) digitalWrite(INV_DE, HIGH); Serial1.write(buf, len); Serial1.flush(); digitalWrite(INV_DE, LOW); // ПОТОМ отрисовка на экране drawUI(); } else if (len > 0) { // Все остальные пакеты просто пробрасываем digitalWrite(INV_DE, HIGH); Serial1.write(buf, len); Serial1.flush(); digitalWrite(INV_DE, LOW); } } }