Передача данных между Arduino с выводом на экран
- Войдите на сайт для отправки комментариев
Имеются три платы первая выводит на экран данные с датчиков тимпературы и управляет отоплением, вторая плата на другом объекте собирает показания тимпературы и выводит на свой экран. Появилась необходимость пересылать данные на третью ардуину для вывода на экран, но столкнулся с проблемой при вввыводе на третей ардуино на экран данные с строками разрывает , то есть указываю выводить 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(); // Иначе это не маркер, а х.з. что. Полный ресет. } } // } } } } }
Весь код собираелся по примерам и переделывался под собственные нужды, прошу сильно не пинать.
ЗЫ: для ковыряния кода на коленки реальную тимпературу заменил цифрами