Відповісти

Введіть повідомлення і натисніть Надіслати
Параметри

Назад

Огляд теми (нові повідомленні вгорі)

jokeer
2026-03-10 18:19:30
dimich пише:

якщо дисплей відправить щось не 8-байтове, парсер розсинхронізується.

Можливо підвисання дисплею з цим і пов"язані.

Взагалі, тут же плюси і ООП. Зробити лібу в arduino-style. Об"єкт з методом tick(), який викликається в loop(), методом data_available(), і всі парсери й буфери сховати всередині. Буде простіше.

dimich
2026-03-10 17:21:40
Primaangel88 пише:
      case 2:  // зчитуємо решту пакету
        buf[idx++]=b;
        if(idx>=8)

Тут би по-хорошому читати байт довжини, а потім buf[2] байтів пакета. Бо якщо дисплей відправить щось не 8-байтове, парсер розсинхронізується.

dimich
2026-03-10 16:53:23
Primaangel88 пише:
  if(millis()-tUART > 5)
  {
    tUART = millis();
    readDWIN();
  }

Навіщо ці паузи між читаннями? dwin.available() просто повертає 0, якщо даних нема.

Що таке "навантаження на порт" і навіщо його "зменшувати"? SoftwareSerial, наскільки бачу, для прийому використовує PCINT. А передача, на відміну від HardwareSerial, не буферизована: write() не повертається поки не видасть весь байт. 

Взагалі я би рекомендував для звʼязку з дисплеєм використовувати апаратний UART, а прошивати програматором. А краще взагалі взяти контролер з двома UART'ами, і не звʼязуватись із SoftwareSerial.

Primaangel88 пише:

проблема в тому що код читає неправильно данні з порта

Можете показати, які саме дані неправильні? Тобто "дисплей відправив ось таку послідовність, а прочиталась ось така".

Kino пише:

Ну если "простой" работает, то надо искать где "сложный" всё ломает.

+1

Kino
2026-03-10 15:26:53

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

jokeer
2026-03-10 15:14:17

Якось воно складно дуже.
Я б порадив складати символи з uart в кільцевий буфер, і запускати обробку тільки коли він заповниться.
Ну і в які місця ви добавили print не очевидно, так що що насправді там відбувається ніхто крім вас не знає.
Не хочете спробувати freertos? Воно є під arduino nano wink Так то esp32/rpi2040 коштує не сильно дорожче, але під rtos робота з купою датчиків виглядає значно простіше.

Primaangel88
2026-03-10 13:44:58

додав для відладки в порт повідомлення отримав ось таке у відповідь

і реле не відпрацьовує

DWIN RX -> 5A A5 6 83 50 1 1 0
Relay command: 0
Sensor 0 error
Temp 1 = 0.00
Sensor 1 error
Temp 2 = 0.00
Sensor 2 error
Temp 3 = 0.00
Sensor 3 error
Temp 4 = 0.00
Sensor 4 error
Temp 5 = 0.00
UART RESET
Heat timer 0:0
Cool timer 0:0
DWIN SEND -> VP:2001 value:0
DWIN SEND -> VP:2002 value:0
DWIN SEND -> VP:2003 value:0
DWIN SEND -> VP:2004 value:0
Flow pulses/sec: 0

Primaangel88
2026-03-10 13:40:27

Доброго дня! Пишу код для домашнього проєкту (самонавчання).
Код має обробляти пакети що приходять з дисплея по uart в вигляді 0x5A 0xA5 0x06 0x83 0x50 0x01 0x01 0x00 0x03.
та надсилати пакети з інформацією у вигляді 0x5A 0xA5 0x06 0x82 0x50 0x01 0x01 0x00 0x03
де
Байти    Значення
5A A5    старт пакета
06        довжина
83            читання VP () дисплей прочитав значення в памяті і передав в порт, якщо дисплей отримує 0х82 він записує в память
50 01    адреса
01           кількість слів
00 03    дані

код має читати пакети данних з дисплея та періодично відправляти на дисплей пакети з данними з 5 датчиків температури, датчика потоку, та час з двох таймерів. а також оновлювати на дисплеї стан кнопок відповідно до поточного стану реле, бо в коді є автоматичне вмикання реле по досягненню температур.
я так розумію що я щось намудрував з парсингом по uart

нижче прикріпляю код мого проекту.

/* =========================================================
  
   Arduino Nano + DWIN + DS18B20 + Flow sensor + RTC DS3231

   Функції:
   • 5 датчиків температури DS18B20 (1-Wire)
   • 3 реле
   • 2 таймери роботи
   • автоматичне керування температурою
   • підрахунок потоку води
   • зв'язок з дисплеєм DWIN
   • захист від зависання UART та датчиків
   ========================================================= */

#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <RTClib.h>

/* ---------------- DWIN UART ----------------
налаштування uart для роботи з дисплеем */
#define DWIN_RX 10
#define DWIN_TX 9
SoftwareSerial dwin(DWIN_RX,DWIN_TX);

/* ---------------- DS18B20 ---------------- */
#define ONE_WIRE_BUS 12
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

/* --------- ФІЗИЧНІ АДРЕСИ ДАТЧИКІВ ---------
АДРЕСИ заповнити вручну
---------------------------------------------- */
DeviceAddress sensorAddr[5] =
{
  {0x28,0xFF,0x00,0x00,0x00,0x00,0x00,0x01}, // датчик 1
  {0x28,0xFF,0x00,0x00,0x00,0x00,0x00,0x02}, // датчик 2
  {0x28,0xFF,0x00,0x00,0x00,0x00,0x00,0x03}, // датчик 3
  {0x28,0xFF,0x00,0x00,0x00,0x00,0x00,0x04}, // датчик 4
  {0x28,0xFF,0x00,0x00,0x00,0x00,0x00,0x05}  // датчик 5
};

/* ---------------- RTC ---------------- 
модуль точного часу ----------------*/
RTC_DS3231 rtc;
bool rtc_ok = false;

/* ---------------- RELAYS ----------------
налаштування пінів реле--------------- */
byte relayPin[3] = {4,5,6};
bool relayState[3] = {0,0,0};

/* ---------------- FLOW SENSOR ----------------
налаштування датчика потоку----------------- */
#define FLOW_PIN 2
volatile uint16_t flow_pulses=0;
uint16_t flow_lpm=0;

/* ---------------- TEMPERATURES ----------------
масив для зберігання температур------------- */
float temp[5];
int lastTempSend[5] = {0,0,0,0,0};

/* ---------------- TIMERS ---------------- */
uint32_t heatStart=0;
uint32_t coolStart=0;
uint32_t heatTime=0;
uint32_t coolTime=0;

/* ---------------- LOOP TASK TIMERS ----------------
налаштування затримок в циклі для зменшення навантаження на порт */
uint32_t tUART=0;
uint32_t tTEMP=0;
uint32_t tFLOW=0;
uint32_t tTIMER=0;

/* ---------------- UART RX ---------------- */
byte buf[8];
byte idx=0;
byte state=0;
uint32_t uartTimer=0;

/* -----------------   FLOW INTERRUPT
   рахує імпульси датчика потоку */
void flowISR()
{
  flow_pulses++;
}

/* --------------SEND VALUE TO DWIN
   формування пакету запису VP------*/
void sendVP(uint16_t addr,int value)
{
  byte pkt[8];
  pkt[0]=0x5A;
  pkt[1]=0xA5;
  pkt[2]=0x05;
  pkt[3]=0x82;
  pkt[4]=addr>>8;
  pkt[5]=addr&0xFF;
  pkt[6]=value>>8;
  pkt[7]=value&0xFF;
  dwin.write(pkt,8);
}

/*------------ RESET SOFTWARE SERIAL
   автоматичний reset якщо UART завис  */
void resetUART()
{
  dwin.end();
  delay(10);
  dwin.begin(115200);
}

/* ------------------   PARSE PACKET
   обробка кнопок реле----------------*/
void parsePacket()
{
  if(buf[3]==0x83 && buf[4]==0x50)
  {
    byte val=buf[7];
    relayState[0]=bitRead(val,0);
    relayState[1]=bitRead(val,1);
    relayState[2]=bitRead(val,2);
  }
}

/*-----------------   READ DWIN PACKETS
   метод state machine: 0-5A,1-A5,2-6 байт
 парсинг пакетів--------------------------------*/
void readDWIN()
{
  while(dwin.available())
  {
    byte b=dwin.read();
    uartTimer=millis();

    switch(state)
    {
      case 0:  // чекаємо стартовий байт 0x5A
        if(b==0x5A){ buf[0]=b; state=1; }
        break;

      case 1:  // чекаємо другий байт 0xA5
        if(b==0xA5){ buf[1]=b; idx=2; state=2; }
        else state=0;
        break;

      case 2:  // зчитуємо решту пакету
        buf[idx++]=b;
        if(idx>=8)
        {
          parsePacket();
          idx=0;
          state=0;
        }
        break;
    }
  }

  // reset UART якщо завис
  if(millis()-uartTimer>500)
  {
    resetUART();
    uartTimer=millis();
  }
}

/* =--------------   READ TEMPERATURES
   зчитування 5 датчиків з захистом обриву  */
void readTemps()
{
  sensors.requestTemperatures();

  for(int i=0;i<5;i++)
  {
    float t=sensors.getTempC(sensorAddr[i]);
    if(t==-127 || t>110 || t<-40) t=0;
    temp[i]=t;
    int v=t*100;

    // передача лише якщо змінилося
    if(v!=lastTempSend[i])
    {
      uint16_t addr;
      switch(i)
      {
        case 0: addr=1005; break;
        case 1: addr=1006; break;
        case 2: addr=1008; break;
        case 3: addr=1009; break;
        case 4: addr=1010; break;
      }
      sendVP(addr,v);
      lastTempSend[i]=v;
    }
  }
}

/* ---------------   AUTOMATIC RELAY CONTROL
   автоматичне керування реле по температурі */
void autoRelays()
{
  if(temp[3]>=70) relayState[1]=1;
  if(temp[1]>=25) relayState[2]=1;
}

/*----------------------- UPDATE RELAYS
   оновлення фізичних реле та дисплея  */
void updateRelays()
{
  static bool lastRelay[3]={0,0,0};

  for(int i=0;i<3;i++)
  {
    digitalWrite(relayPin[i],relayState[i]);
    if(relayState[i]!=lastRelay[i])
    {
      sendVP(0x5001,relayState[0] | relayState[1]<<1 | relayState[2]<<2);
      lastRelay[i]=relayState[i];
    }
  }
}

/*-------------------   READ FLOW SENSOR
   оптимізований підрахунок потоку ----*/
void readFlow()
{
  noInterrupts();
  uint16_t p=flow_pulses;
  flow_pulses=0;
  interrupts();

  flow_lpm=p;
  sendVP(1007,flow_lpm);
}

/* --------------------------UPDATE TIMERS
   таймери роботи нагріву та охолодження */
void updateTimers()
{
  uint32_t now;

  if(rtc_ok) now=rtc.now().unixtime();
  else now=millis()/1000;

  if(relayState[0])
  {
    if(heatStart==0) heatStart=now;
    heatTime=now-heatStart;
  }

  if(relayState[2])
  {
    if(coolStart==0) coolStart=now;
    coolTime=now-coolStart;
  }

  uint16_t h1=heatTime/3600;
  uint16_t m1=(heatTime%3600)/60;
  uint16_t h2=coolTime/3600;
  uint16_t m2=(coolTime%3600)/60;

  sendVP(2001,h1);
  sendVP(2002,m1);
  sendVP(2003,h2);
  sendVP(2004,m2);
}

/* ----------------------  SETUP--------------- */
void setup()
{
  Serial.begin(115200);
  dwin.begin(115200);
  sensors.begin();
  Wire.begin();
  rtc_ok=rtc.begin();

  for(int i=0;i<3;i++)
  {
    pinMode(relayPin[i],OUTPUT);
  }

  pinMode(FLOW_PIN,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(FLOW_PIN),flowISR,RISING);
}

/*-----------------   LOOP (оптимізований планувальник задач)------------- */
void loop()
{
  /* ---------------- читання UART ---------------- */
  if(millis()-tUART > 5)
  {
    tUART = millis();
    readDWIN();
  }

  /* ---------------- температури ---------------- */
  if(millis()-tTEMP > 1000)
  {
    tTEMP = millis();
    readTemps();
    autoRelays();
    updateRelays();
  }

  /* ---------------- потік води ---------------- */
  if(millis()-tFLOW > 1000)
  {
    tFLOW = millis();
    readFlow();
  }

  /* ---------------- таймери ---------------- */
  if(millis()-tTIMER > 1000)
  {
    tTIMER = millis();
    updateTimers();
  }
}

проблема в тому що код читає неправильно данні з порта, і відповідно не виконує обробку натискання з дисплею.
коли пишу простий код то бачу що данні приходять коректні.

Підвал форуму