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