Передача данных между Arduino с выводом на экран

Нет ответов
vermaht
Offline
Зарегистрирован: 17.09.2016

Имеются три платы первая выводит на экран данные с датчиков тимпературы и управляет отоплением, вторая плата на другом объекте собирает показания тимпературы и выводит на свой экран. Появилась необходимость пересылать  данные на третью ардуину для вывода на экран, но столкнулся с проблемой при вввыводе на третей ардуино на экран данные с строками разрывает , то есть указываю выводить 39 символов на 3 строку (lcd.setCursor(0, 2)) с расчетом что первые 20 символов будут на 3 строке, а следующие 19 перейдут на 4 строку, но их перекидывает на 2 строку, пробовал разделить данные на две части и каждой части по отдельности указывать строку вывода на экране - не помогло :(

Первое устройство

//Управление отоплением
//
//
#include <Wire.h>
#include <LiquidCrystal_I2C.h> // Библиотека I2C экрана
#include "RTClib.h" // Подключение библиотеки для часового модуля
#include <OneWire.h> // Шина i-wire
#include <DallasTemperature.h> // работа с датчиами температуры i-wire
#include <avr/wdt.h>

#define ONE_WIRE_BUS 10 // определяем куда подключены датчик тимпературы
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 20 chars and 4 line display

DeviceAddress Thermometer1 = {
  0x28, 0x03, 0x43, 0x76, 0x04, 0x00, 0x00, 0xDF
};  // Прописываем все датчики, адрес в обратном порядке
DeviceAddress Thermometer2 = {
  0x10, 0x55, 0x7B, 0xA0, 0x02, 0x08, 0x00, 0xB3
};
DeviceAddress Tbak1 = {
  0x28, 0x62, 0x3F, 0x4B, 0x03, 0x00, 0x00, 0xC8
};
DeviceAddress Tbak2 = {
  0x28, 0xC0, 0x38, 0x4B, 0x03, 0x00, 0x00, 0xAB
};
DeviceAddress Tkot1 = {
  0x28, 0xED, 0x45, 0x4B, 0x03, 0x00, 0x00, 0xD6
};
DeviceAddress Tkot2 = {
  0x28, 0xCD, 0x4C, 0x4B, 0x03, 0x00, 0x00, 0x93
};


float t1;
float t2;
float t3;
float t4;
float tk1;
float tk2;

int vent1 = 4; //прописываем пины вентиляторов
int vent2 = 5;


int nasos1 = 6; //прописываем пины насосов
int nasos2 = 7;

int tmag = 18.00; //желаемая температура 
int hist = 2;       //гистерезис
int tkot = 3; //гистерезис для котла
int tminbak = 40; //минимальная температура в баке для работы системы

unsigned long preMillis = 0; // создаем переменную для задержки
long inter = 60000; //задаем интервал проверки параметров в миллисекундах
unsigned long preMillis2 = 0; //переменная для задержки движения экрана
unsigned long preMillis3 = 0; // создаем переменную для задержки проверки тимпературы
unsigned long currentMillis3;

// для передачи данных
String sp_startMarker;           // Переменная, содержащая маркер начала пакета
String sp_stopMarker;            // Переменная, содержащая маркер конца пакета
String sp_dataString;            // Здесь будут храниться принимаемые данные
int sp_startMarkerStatus;        // Флаг состояния маркера начала пакета
int sp_stopMarkerStatus;         // Флаг состояния маркера конца пакета
int sp_dataLength;               // Флаг состояния принимаемых данных
boolean sp_packetAvailable;      // Флаг завершения приема пакета

// Объявляем переменные строки для передачи данных
String stringTk3, stringTk1, stringTb1, stringTb2, stringTt1, stringTt2, stringData, stringData1;
char unit='c';            //метка для приемника
char unit1='d';            //метка для приемнка




void setup()
{
    wdt_disable(); // отключение сторожевого таймера
  
  pinMode(nasos1, OUTPUT);  // пины насосов настраиваем на выход
  pinMode(nasos2, OUTPUT);
  digitalWrite(nasos1, HIGH);   //устанавливаем низкий уровень
  digitalWrite(nasos2, HIGH);

  pinMode(vent1, OUTPUT);  // пины вентиляторов настраиваем на выход
  pinMode(vent2, OUTPUT);
  digitalWrite(vent1, HIGH);   //устанавливаем низкий уровень
  digitalWrite(vent2, HIGH);


  Serial.begin(9600);                               // Инициализируем последовательный интерфейс
  sp_SetUp();                                       // Инициализируем протокол.

  Wire.begin();
  rtc.begin();

  lcd.init();                            // Инициализация lcd
  lcd.backlight();                       // Включаем подсветку
  lcd.setCursor(0, 0); 
  lcd.print("Loading");            // Выводим текст
  delay(250);
  lcd.print (" .");
  delay(250);
  lcd.print (" .");
  delay(250);
  lcd.print (" .");
  delay(250);
  lcd.print (" .");
  delay(250);
  lcd.print (" .");
  lcd.setCursor(0, 1);                   // Устанавливаем курсор в начало 2 строки
  lcd.print("Otoplenie");              // Выводим текст


  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(__DATE__, __TIME__));
  }

  sensors.begin();                      // работаем с датчиками
  sensors.setResolution(Thermometer1, 10);
  sensors.setResolution(Thermometer2, 10);
  sensors.setResolution(Tbak1, 10);
  sensors.setResolution(Tbak2, 10);
  sensors.setResolution(Tkot1, 10);
  sensors.setResolution(Tkot2, 10);

  stringTk3 = String("tk3=");
  stringTk1 = String("tk1=");
  stringTb1 = String("tb1=");
  stringTb2 = String("tb2=");
  stringTt1 = String("tt1=");
  stringTt2 = String("tt2=");
  stringData = String();
  stringData1 = String();

  delay (1000);
  lcd.clear();
  
  wdt_enable (WDTO_8S); // включение сторожевого таймера
  Serial.println("Watchdog enabled.");
}


void loop () {

  digitalClockDisplay();   //вывод часов на дисплей
  sensors.requestTemperatures(); // команда датчикам считывать температуру

  //интервал опроса датчиков
  unsigned long currentMillis3 = millis();
  if (currentMillis3 - preMillis3 > 1500) { //опрос датчиков милисекунд
    preMillis3 = currentMillis3;

// вывод времени в сериал порт
/*    DateTime now = rtc.now();
    
//    Serial.print(now.hour(), DEC);
//    Serial.print(':');
//    Serial.print(now.minute(), DEC);
//    Serial.println();
*/
    t1 = 15.52; //wireFunction(Thermometer1); //считываем данные с датчика по адресу1
    lcd.setCursor(0, 1);
    lcd.print(stringTk3);
    lcd.print(t1); //выводим на экран

    t2 = 16.52; // wireFunction(Thermometer2); //считываем данные с датчика по адресу2
    lcd.setCursor(10, 1);
    lcd.print(stringTk1);
    lcd.print(t2);

    t3 = 40.54; // wireFunction(Tbak1);
    lcd.setCursor(10, 2);
    lcd.print(stringTb1);
    lcd.print(t3);
    
    t4 = 38.58; //wireFunction(Tbak2);
    lcd.setCursor(10, 3);
    lcd.print(stringTb2);
    lcd.print(t4);

    tk1 = 52.52;//wireFunction(Tkot1);
    lcd.setCursor(0, 2);
    lcd.print(stringTt1);
    lcd.print(tk1);

    tk2 = 37.85;//wireFunction(Tkot2);
    lcd.setCursor(0, 3);
    lcd.print(stringTt2);
    lcd.print(tk2);
  }

     
  //интервал проверки параметров
  unsigned long currentMillis = millis();
  if (currentMillis - preMillis > inter) {
    preMillis = currentMillis;

    if (t3 > tminbak) {
      digitalWrite(nasos2, LOW); //включаем насос для поттебителей
    }
    else {
      digitalWrite(nasos2, HIGH);
    }

    if (t3 > tminbak + 2) { //включаем тепловентиляторы когда в баке будет температура tminbak+2
      if (t1 < tmag) digitalWrite(vent1, LOW); // управление тепловинтеляторами
      if (t1 > tmag + hist) digitalWrite(vent1, HIGH);
      if (t1 < 22) { // !!!!если возле тепловентилятора температура больше 22 градусов не включаем второй тепловентилятор !!!!
        if (t2 < tmag) digitalWrite(vent2, LOW); // управление тепловинтеляторами
        if (t2 > tmag + hist) digitalWrite(vent2, HIGH);
      }
      else digitalWrite(vent2, HIGH);
    }
    if (t3 < tminbak) {
      digitalWrite(vent1, HIGH);
      digitalWrite(vent2, HIGH);
    }

    //управление насосом котла
    if (tk1 > (t3+t4)/2) digitalWrite(nasos1, LOW); //если температура на выходе котла больше температуры бака включить насос
    if (tk1 < (tk2+2)) digitalWrite(nasos1, HIGH);     //

    lcd.clear(); //раз в интервал очищаем экран

  }
  //конец интервала проверки параметров

  
// отправка данных
  unsigned long currentMillis2 = millis();
  if (currentMillis2 - preMillis2 > 5000) {
    preMillis2 = currentMillis2;
    
     stringData = stringTk3 + t1 + " " + stringTk1 + t2 + " " + stringTb1 + t3 + " " + stringTb2 + t4;
     sp_Send(stringData);  
     
//     stringData1 =stringTb1 + t3 + " " + stringTb2 + t4;
//     sp_Send1(stringData1);  
     
  }

  
  wdt_reset();    // сброс отсчета сторожевого таймера

}


void digitalClockDisplay() {        // относится к часам
  // digital clock display of the time
  DateTime now = rtc.now();
  lcd.setCursor(0, 0);
  printDigits(now.hour()); // печатает часы
  //рисуем мигающие двоеточие, привязано к секундам
  lcd.setCursor(2, 0);
  if (now.second() % 10 % 2 == 0) {
    lcd.print(":");
  }
  else
  {
    lcd.print(" ");
  }
  lcd.setCursor(3, 0);
  printDigits(now.minute());//рисуем минуты

}

void printDigits(int digits) {               // относится к часам
  // utility function for digital clock display: prints preceding colon and leading 0
  if (digits < 10) {
    lcd.print('0');
  }
  lcd.print(digits);
}


//функция получения температуры
float wireFunction(DeviceAddress te) {
  float result;
  result = sensors.getTempC(te);
  if (result >= -30 && result <= 120) //отсеиваем данные не входящие в интервал
  { int i;
    for ( i = 0; i < 9; i++) {
//      Serial.print(te[i], HEX);
//      Serial.print(" ");
    }
//    Serial.println(result);
    return result;
  }
  else {
//    Serial.print("*** ");
   /* int i;
    for ( i = 0; i < 9; i++) {
      Serial.print(te[i], HEX);
      Serial.print(" ");
    }
    Serial.println(result);
    delay(100);
    wireFunction(te);*/
  }
}

// > относится к протоколу приема/передачи данных

// Первичная инициализация протокола:
void sp_SetUp() 
{
  sp_startMarker = "<bspm>";     // Так будет выглядеть маркер начала пакета
  sp_stopMarker = "<espm>";      // Так будет выглядеть маркер конца пакета
  sp_dataString.reserve(64);     // Резервируем место под прием строки данных
  sp_ResetAll();                 // Полный сброс протокола
}

// Полный сброс протокола:
void sp_ResetAll()
{
  sp_dataString = "";           // Обнуляем буфер приема данных
  sp_Reset();                   // Частичный сброс протокола
}

// Частичный сброс протокола:
void sp_Reset()
{
  sp_startMarkerStatus = 0;     // Сброс флага маркера начала пакета
  sp_stopMarkerStatus = 0;      // Сброс флага маркера конца пакета
  sp_dataLength = 0;            // Сброс флага принимаемых данных
  sp_packetAvailable = false;   // Сброс флага завершения приема пакета
}

//Отправка данных на UART
void sp_Send(String data)
{
  Serial.print(unit);         // Отправляем номер устройства
  Serial.print(sp_startMarker);         // Отправляем маркер начала пакета
  Serial.write(data.length());          // Отправляем длину передаваемых данных
  Serial.print(data);                   // Отправляем сами данные
  Serial.print(sp_stopMarker);          // Отправляем маркер конца пакета
}

 void sp_Send1(String data5)
{
  Serial.print(unit1);         // Отправляем номер устройства
  Serial.print(sp_startMarker);         // Отправляем маркер начала пакета
  Serial.write(data5.length());          // Отправляем длину передаваемых данных
  Serial.print(data5);                   // Отправляем сами данные
  Serial.print(sp_stopMarker);          // Отправляем маркер конца пакета
}

 

  Код приемника


String sp_startMarker;           // Переменная, содержащая маркер начала пакета
String sp_stopMarker;            // Переменная, содержащая маркер конца пакета
String sp_dataString;            // Здесь будут храниться принимаемые данные
int sp_startMarkerStatus;        // Флаг состояния маркера начала пакета
int sp_stopMarkerStatus;         // Флаг состояния маркера конца пакета
int sp_dataLength;               // Флаг состояния принимаемых данных
boolean sp_packetAvailable;      // Флаг завершения приема пакета

#include <avr/wdt.h>
#include <Wire.h> // i2c (для RTC)
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,20,4);  // ПРОВЕРИТЬ the LCD address to 0x20 for a 16 chars and 2 line display

unsigned long preMillis = 0; // создаем переменную для задержки
long inter = 60000; //задаем интервал проверки параметров в миллисекундах
unsigned long currentMillis;

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete
char Unit;
char Unit0='a';
char Unit1='b';
char Unit2='c';
char Unit3='d';

void setup() {
  wdt_disable(); // отключение сторожевого таймера

  lcd.init();                      // initialize the lcd 
  lcd.backlight();
  
  Serial.begin(9600);                               // Инициализируем последовательный интерфейс
  sp_SetUp();                                       // Инициализируем протокол.

  inputString.reserve(200);

  wdt_enable (WDTO_8S); // включение сторожевого таймера
  Serial.println("Watchdog enabled.");
}

void loop() {
  sp_Read();
  if(sp_packetAvailable == true)
  {
    if(Unit0 == Unit)
    {
      lcd.setCursor(0,0);
      lcd.print(sp_dataString);
      sp_packetAvailable = false;
    };
    if(Unit1 == Unit)
    {
      lcd.setCursor(0,1);
      lcd.print(sp_dataString);
      sp_packetAvailable = false;
    };
    if(Unit2 == Unit)
    {
      lcd.setCursor(0,2);
      lcd.println(sp_dataString);
      sp_packetAvailable = false;

    };
    if(Unit3 == Unit)
    {
      lcd.setCursor(0,3);
      lcd.print(sp_dataString);
      sp_packetAvailable = false;
    };
    
  };
  
  delay(200);

  wdt_reset();    // сброс отсчета сторожевого таймера
  
   unsigned long currentMillis = millis();
  if (currentMillis - preMillis > inter) {
    preMillis = currentMillis; 
    lcd.clear();
  }
}






// > относится к протоколу приема/передачи данных

// Первичная инициализация протокола:
void sp_SetUp() 
{
  sp_startMarker = "<bspm>";     // Так будет выглядеть маркер начала пакета
  sp_stopMarker = "<espm>";      // Так будет выглядеть маркер конца пакета
  sp_dataString.reserve(64);     // Резервируем место под прием строки данных
  sp_ResetAll();                 // Полный сброс протокола
}

// Полный сброс протокола:
void sp_ResetAll()
{
  sp_dataString = "";           // Обнуляем буфер приема данных
  sp_Reset();                   // Частичный сброс протокола
}

// Частичный сброс протокола:
void sp_Reset()
{
  sp_startMarkerStatus = 0;     // Сброс флага маркера начала пакета
  sp_stopMarkerStatus = 0;      // Сброс флага маркера конца пакета
  sp_dataLength = 0;            // Сброс флага принимаемых данных
  sp_packetAvailable = false;   // Сброс флага завершения приема пакета
}
/*
//Отправка данных на PC
void sp_Send(String data)
{
  Serial.print(sp_startMarker);         // Отправляем маркер начала пакета
  Serial.write(data.length());          // Отправляем длину передаваемых данных
  Serial.print(data);                   // Отправляем сами данные
  Serial.print(sp_stopMarker);          // Отправляем маркер конца пакета
}
*/

//Собственно, сама «читалка»

void sp_Read()
{
  Unit = Serial.read();         //считываем номер устройсва

  while(Serial.available() && !sp_packetAvailable)            // Пока в буфере есть что читать и пакет не является принятым
  {
    int bufferChar = Serial.read();                           // Читаем очередной байт из буфера
    if(sp_startMarkerStatus < sp_startMarker.length())        // Если стартовый маркер не сформирован (его длинна меньше той, которая должна быть) 
    {  
     if(sp_startMarker[sp_startMarkerStatus] == bufferChar)   // Если очередной байт из буфера совпадает с очередным байтом в маркере
     {
       sp_startMarkerStatus++;                                // Увеличиваем счетчик совпавших байт маркера
     }
     else
     {
       sp_ResetAll();                                         // Если байты не совпали, то это не маркер. Нас нае****, расходимся. 
     }
    }  
    else
    {
     // Стартовый маркер прочитан полностью
       
       if(sp_dataLength <= 0)                                 // Если длинна пакета на установлена
       {
         sp_dataLength = bufferChar;                          // Значит этот байт содержит длину пакета данных
       }
      else                                                    // Если прочитанная из буфера длинна пакета больше нуля
      {
        if(sp_dataLength > sp_dataString.length())            // Если длинна пакета данных меньше той, которая должна быть
        {
          sp_dataString += (char)bufferChar;                  // прибавляем полученный байт к строке пакета
        }
        else                                                  // Если с длинной пакета данных все нормально
        {
          if(sp_stopMarkerStatus < sp_stopMarker.length())    // Если принятая длинна маркера конца пакета меньше фактической
          {
            if(sp_stopMarker[sp_stopMarkerStatus] == bufferChar)  // Если очередной байт из буфера совпадает с очередным байтом маркера
            {
              sp_stopMarkerStatus++;                              // Увеличиваем счетчик удачно найденных байт маркера
              if(sp_stopMarkerStatus == sp_stopMarker.length())
              {
                // Если после прочтения очередного байта маркера, длинна маркера совпала, то сбрасываем все флаги (готовимся к приему нового пакета)
                sp_Reset();    
                sp_packetAvailable = true;                        // и устанавливаем флаг готовности пакета
              }
            }
            else
            {
              sp_ResetAll();                                      // Иначе это не маркер, а х.з. что. Полный ресет.
            }
          }
          //
        }
      } 
    }    
  }
}

Весь код собираелся по примерам и переделывался под собственные нужды, прошу сильно не пинать.

ЗЫ: для ковыряния кода на коленки реальную тимпературу заменил цифрами