Управление котлом на ардуино

Проекты наших посетителей и проекты найденные на просторах...
Ответить
Сообщение
Автор
Аватара пользователя
admin
Site Admin
Site Admin
Сообщения: 115
https://www.facebook.com/wroclaw.meble.kuchenne/
Зарегистрирован: Пт дек 10, 2021 1:33 am
Благодарил (а): 6 раз
Поблагодарили: 2 раза

Управление котлом на ардуино

#1 Сообщение admin »

Буду сюда складывать всё что найду и считаю полезным, по большому счёту видимо для себя.
Это скетч найденый на просторах интернета, и предназначен для управления электрокотлом с 3 тенами через реле.
Буду его допиливать.
Свои скетчи утеряны так как года два назад разработки забросил.

Код: Выделить всё

#include <OneWire.h>
#include <DallasTemperature.h>
#include <PID_v1.h>
#include <DHT.h>
#include <Ethernet.h>
#include <SPI.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire  ds(6);  // on pin 10 (a 4.7K resistor is necessary)
DallasTemperature sensors(&ds);
boolean waithTemp = false;
int TEMPERATURE_PRECISION = 10;

int  lamp1 = 7;
int  lamp2 = 8;
int  lamp3 = 9;

DeviceAddress IntThermometer = { 0x28, 0x8E, 0xF4, 0x28, 0x05, 0x00, 0x00, 0x07 };
DeviceAddress OutThermometer = { 0x28, 0x65, 0x15, 0x32, 0x05, 0x00, 0x00, 0xE2 };
DeviceAddress KatThermometer = { 0x28, 0x61, 0x43, 0x28, 0x05, 0x00, 0x00, 0x14 };

byte addr[8];
unsigned long StartTime = 0;
unsigned long WorkWindow = 60000; // 10min
unsigned long WorkTime, TenTime;
float maxData = 100;
float celsius, temp;
double Setpoint, Input, Output;

int ThermometerCount;
DeviceAddress Thermometer[100];

PID myPID(&Input, &Output, &Setpoint, 10, 0.1, 5, DIRECT); //0.000006 0.03 40

double targetTemp = 22.5;

byte mac[] = { 0xE0, 0x69, 0x95, 0x72, 0x65, 0xE8 };
byte ip[] = { 192, 168, 1, 100 };
byte server[] = { ?, ?, ?, ? };
EthernetClient client;
byte webskipcount = 10;
byte webcount = 0;  

void setup(void) {

  Serial.begin(9600);
  
  //Ethernet.begin(mac, ip);
  Ethernet.begin(mac);
  
  sensors.begin();
  
  pinMode(lamp1, OUTPUT);
  pinMode(lamp2, OUTPUT);
  pinMode(lamp3, OUTPUT);
  


  Setpoint = targetTemp;
  myPID.SetOutputLimits(0, maxData);
  myPID.SetMode(AUTOMATIC);
  
  celsius = targetTemp;
  
  StartTime = millis();
}

long filter(long x, long Nb, long k) {
  static long y = 0, z = 0;
  z += (x - y);
  return y = (Nb * z) >> k;
};  

void loop(void) {

  byte i;
  byte type_s;
  byte data[12];
  long Out;
  
  if (millis() < StartTime) {
    StartTime = millis();
  }
  
  WorkTime = millis() - StartTime;
  if (WorkTime > WorkWindow) {
    WorkTime = WorkTime - WorkWindow;
    StartTime = millis() + WorkTime;
  }

  //Serial.println("cycle");
  sensors.requestTemperatures();
  celsius = sensors.getTempC(IntThermometer);
  Input = celsius;
  if (webcount >= webskipcount) {
    char buffer[10];
    String temperatureS1 = dtostrf(celsius, 2, 2, buffer);
    String temperatureS2 = dtostrf(sensors.getTempC(OutThermometer), 2, 2, buffer);
    String temperatureS3 = dtostrf(sensors.getTempC(KatThermometer), 2, 2, buffer);
    String OutputPowerS = dtostrf(Output, 2, 2, buffer);
    String msg = "GET /temp.php?t1="+ temperatureS1 + "&t2=" + temperatureS2 + "&t3=" + temperatureS3 + "&p="+OutputPowerS;
    Serial.println(msg);
    client.connect(server, 80);
    client.println(msg);
    client.stop();
    webcount = 0;
  } else {
    webcount += 1;
  }

  myPID.Compute();
  //Serial.print(Input);Serial.print(" ");Serial.print(Output);Serial.print(" ");Serial.println(Setpoint);
  
  if (Output > maxData/3*2) {
    digitalWrite(lamp1, HIGH);
    digitalWrite(lamp2, HIGH);
    Out = Output - maxData/3*2;
  } else if (Output > maxData/3) {
    digitalWrite(lamp1, HIGH);
    digitalWrite(lamp2, LOW);
    Out = Output - maxData/3;
  } else {
    digitalWrite(lamp1, LOW);
    digitalWrite(lamp2, LOW);
    Out = Output;
  }

  TenTime = map(Out, 0, maxData/3, 0, WorkWindow);

  Serial.print(celsius);
  Serial.print("  ");
  Serial.print(sensors.getTempC(OutThermometer));
  Serial.print("  ");
  Serial.print(sensors.getTempC(KatThermometer));
  Serial.print("  ");
  Serial.print(Output);
  Serial.print("  ");
  Serial.print(TenTime);
  Serial.print("  ");
  Serial.println(WorkTime);
  
  if (WorkTime < TenTime) {
    digitalWrite(lamp3, HIGH);
  }
  if (WorkTime > TenTime) {
    digitalWrite(lamp3, LOW);
  }
  
}
PHP скрипты

Код: Выделить всё

<?php
$dbhost = 'localhost';
$dbuser = '***';
$dbpass = '***';
$dbname = 'nikolaarduino';
$client_ip = $_SERVER['REMOTE_ADDR'];
$temp1 = $_GET["t1"];
$temp2 = $_GET["t2"];
$temp3 = $_GET["t3"];
$power = $_GET["p"];

$connect = mysql_connect($dbhost, $dbuser, $dbpass);
if(! $connect )
{
  die('Could not connect: ' . mysql_error());
}
mysql_select_db ($dbname, $connect);

$sql = "INSERT INTO Temp (datetime, temp1, temp2, temp3, power, ip) VALUES (Now(), '$temp1', '$temp2', '$temp3', '$power', '$client_ip')";

if(!mysql_query($sql))
{echo '<p><b>Data upload error!</b></p>';}
else
{echo '<p><b>OK</b></p>';}
mysql_close($connect);
?>

Код: Выделить всё

<?php
$dbhost = 'localhost';
$dbuser = '***';
$dbpass = '***';
$dbname = 'nikolaarduino';
$client_ip = $_SERVER['REMOTE_ADDR'];

$connect = mysql_connect($dbhost, $dbuser, $dbpass);
if(! $connect )
{
  die('Could not connect: ' . mysql_error());
}
mysql_select_db ($dbname, $connect);

$query = 'SELECT * FROM Temp WHERE id=(SELECT MAX(ID) FROM Temp)';
$result = mysql_query($query) or die('Error get data: ' . mysql_error());

echo "<table style='text-align: left; width: 100%;' border='1' cellpadding='2' cellspacing='2'>\n";
while ($line = mysql_fetch_array($result, MYSQL_NUM)) {
  echo "<tr align='center'><td colspan='2' rowspan='1'>$line[1]</td></tr>";
  echo "<tr align='center'><td>TempIN = $line[2]</td><td> TempOUT = $line[3]</td></tr>\n";
  echo "<tr align='center'><td colspan='2' rowspan='1'>TempKotel = $line[4]</td></tr>\n";
  echo "<tr align='center'><td colspan='2' rowspan='1'>Power = $line[5]</td></tr>\n";
}
echo "</table>\n";

mysql_free_result($result);

mysql_close($connect);
?>
Не бойся поломать. Бойся не починить ))

Изображение
Аватара пользователя
admin
Site Admin
Site Admin
Сообщения: 115
Зарегистрирован: Пт дек 10, 2021 1:33 am
Благодарил (а): 6 раз
Поблагодарили: 2 раза

Управление котлом на ардуино

#2 Сообщение admin »

Вернулся к проекту контроллера котла
Накидал по памяти, проверил - работает. Тоесть включает выключает , температуру считывает с 2х датчиков.
#include <OneWire.h>
#include <DallasTemperature.h> //
#include <Wire.h>
#include <EEPROM.h>
#define _LCD_TYPE 1 // для работы с I2C дисплеями
#include <LCD_1602_RUS_ALL.h>
LCD_1602_RUS lcd(0x27, 16, 2);

#define ONE_WIRE_BUS 2
// Настройте oneWire для связи с любыми устройствами OneWire (а не только с микросхемами температуры Maxim / Dallas)
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

//служебные переменные
int counter = 0; //счетчик циклов
String strOut = ""; //строка для вывода на дисплей
//float rh; //для считывания влажности
float rt; //для считывания температуры
//float h=0; //для хранения усредненного значения влажности
float t = 0; //для хранения усредненного значения температуры
String out_h = "--.--"; //строка для вывода влажности
String out_t = "--.--"; //строка для вывода темературы

//количество необходимых измерений для вычисления среднего значения
#define measureCntMax 5
//количество произведенных измерений
int measureCnt = 0;

String tiktak = ""; //для отображения процесса работы в виде мигающей справа на экране точки, чтобы понимать что устройство не зависло и производит измерения
//температура включения и выключения отопления по умолчанию
float tempHeatOn = 23.00;
float tempHeatOff = 26.00;
//состояние обогревателя
byte HeatState = 0; //0 - обогрев выключен, 1 - обогрев включен

int mode = 0; //режим экрана и ввода с кнопок
//0 - отображает значения температуры и влажности
//1 - экран настройки температуры включения обогрева
//2 - экран настройки температуры отключения обогрева
//3 - экран настройки влажности включения вентиляции
//4 - экран настройки влажности отключения вентиляции
//5 - экран настройки включения вентиляторов 1 и 2
//7 - отображение текущих параметров влажности
//8 - отображение текущих температурных параметров
//6 - служебное значение, по которому сбрасываем режим на 0 и сохраняем настройки!!!!!
//предыдущее значение кнопок
byte RbtnLastState = -1; //для красной
byte GbtnLastState = -1; //для зеленой

//время удержания кнопок
int RHoldTime = 0; //для красной
int GHoldTime = 0; //для зеленой

int address; // переменная для хранения адреса
byte value; // переменная для хранения значения

void setup() {
Serial.begin(9600); // устанавливаем скорость передачи данных последовательного соединения
////// Serial.println(EEPROM.length()); // выводим общее количество ячеек в памяти

// перебираем в цикле все адреса в EEPROM памяти, пока все не переберем
/* while (address < EEPROM.length()) {
value = EEPROM.read(address); // считываем значение байта
Serial.print("Address: "); // выводим полученные данные на монитор порта
Serial.print(String(address));
Serial.print(", value: ");
Serial.println(String(value));
address++; // наращиваем адрес и повторяем операции
delay(100);
}
*/
pinMode(13, OUTPUT); //гасим штатный светодиод на 13 выводе
pinMode(5, INPUT); //настраиваем цифровой вход 5 на ввод
pinMode(8, INPUT); //настраиваем цифровой вход 8 на ввод
digitalWrite(5, HIGH); //подтягиваем резистор на вход 5
digitalWrite(8, HIGH); //подтягиваем резистор на вход 8

lcd.init(); // инициализация
lcd.backlight(); // включить подсветку
lcd.clear();
lcd.setCursor(1, 0); // столбец 1 строка 0
lcd.print("Boiler control");
lcd.setCursor(0, 1); // столбец 0 строка 1
lcd.print(" v.0.1 by AlexB");
delay(5000);
lcd.clear();
//запускаем датчик
sensors.begin();
//объявляем 4 переменные для чтения настроек из памяти EEPROM
float e1;
float e2;
byte v1;
byte v2;

//читаем настройки из памяти
EEPROM.get(0, e1);
EEPROM.get(20, e2);
//EEPROM.get(40, e3);
//EEPROM.get(50, e4);
//EEPROM.get(200, v1);
// EEPROM.get(201, v2);
//if (v1>1){v1=0;}
//if (v2>1){v2=0;}
//Поочередно покажем считанные настройки (либо их отсутствие)
lcd.setCursor(0, 0);
lcd.print(MakeString("Read Temp On"));
lcd.setCursor(0, 1);
if (isnan(e1)) {
lcd.print(MakeString("EEPROM EMPTY"));
} else {
lcd.print(MakeString(String(e1)));
tempHeatOn = e1;
}
delay(2000);
lcd.setCursor(0, 0);
lcd.print(MakeString("Read Temp Off"));
lcd.setCursor(0, 1);
if (isnan(e2)) {
lcd.print(MakeString("EEPROM EMPTY"));
} else {
lcd.print(MakeString(String(e2)));
tempHeatOff = e2;
}
delay(2000);
//отобразим служебное сообщение, пока производится первое измерения данных до вывода на экран
lcd.setCursor(0, 0);
lcd.print(MakeString("Starting Sensor"));
lcd.setCursor(0, 1);
lcd.print(MakeString("V0.3 15.10.2024"));
}

void loop() {
//измеряем температуру и влажность каждые 2 секунды
if (counter >= 200 && mode == 0) {
counter = 0;
ReadData(); //процедура для чтения информации с датчика DHT22
}

//читаем кнопки
byte btnG = digitalRead(8);
byte btnR = digitalRead(5);

//1.если удерживаюися обе кнопки
if (btnG == 0 && btnR == 0 && RbtnLastState == 0 && GbtnLastState == 0) {
counter = 0;
RHoldTime++;
GHoldTime++;
//если удерживаются обе кнопки более 2 секунд то переходим на следующий экран
if (RHoldTime >= 200 && GHoldTime >= 200) {
RHoldTime = 0;
GHoldTime = 0;
if (mode > 6) { mode = 0; }
mode++;
//сохраним настройки
if (mode == 6) {
mode = 0;
EEPROM.put(0, tempHeatOn);
EEPROM.put(20, tempHeatOff);
//EEPROM.put(40, humVentOn);
//EEPROM.put(60, humVentOff);
//EEPROM.put(200, Vent1Active);
//EEPROM.put(201, Vent2Active);
//выведем сообщение об успешном сохранении настроек
lcd.setCursor(0, 0);
lcd.print(MakeString("Settings"));
lcd.setCursor(0, 1);
lcd.print(MakeString("Saved"));
delay(2000);
}
DrawLCD();
}
}
//2.короткое нажатие красной кнопки
else if (btnR == 0 && RbtnLastState == 1 && btnG == 1) {
counter = 0;
switch (mode) {
case 0:
mode = 7;
DrawLCD();
break;
case 1:
tempHeatOn += 0.1;
DrawLCD();
break;
case 2:
tempHeatOff += 0.1;
DrawLCD();
break;
case 3:
//humVentOn++;
DrawLCD();
break;
case 4:
//humVentOff++;
DrawLCD();
break;
case 5:
//Vent1Active = Vent1Active + 1;
// if (Vent1Active > 1) { Vent1Active = 0; }
DrawLCD();
break;
case 7:
mode = 0;
DrawLCD();
break;
case 8:
mode = 7;
DrawLCD();
break;
}
}
//3.короткое нажатие зеленой кнопки
else if (btnG == 0 && GbtnLastState == 1 && btnR == 1) {
counter = 0;
switch (mode) {
case 0:
mode = 8;
DrawLCD();
break;
case 1:
tempHeatOn -= 0.1;
DrawLCD();
break;
case 2:
tempHeatOff -= 0.1;
DrawLCD();
break;
case 3:
//humVentOn--;
DrawLCD();
break;
case 4:
//humVentOff--;
DrawLCD();
break;
case 5:
//Vent2Active = Vent2Active + 1;
//if (Vent2Active > 1) { Vent2Active = 0; }
DrawLCD();
break;
case 7:
mode = 8;
DrawLCD();
break;
case 8:
mode = 0;
DrawLCD();
break;
}
}
//4.длинное нажатие зеленой кнопки - отключаем подсветку дисплея
else if (btnG == 0 && btnR == 1 && GbtnLastState == 0) {
counter = 0;
GHoldTime++;
if (GHoldTime >= 300) {
GHoldTime = 0;
lcd.noBacklight();
}
}
//5.длинное нажатие красной кнопки - включаем подсветку дисплея
else if (btnG == 1 && btnR == 0 && RbtnLastState == 0) {
counter = 0;
RHoldTime++;
if (RHoldTime >= 300) {
GHoldTime = 0;
lcd.backlight();
}
}
//когда ничего не нажато
else {
RHoldTime = 0;
GHoldTime = 0;
//если на экране настройки/информации ничего долго (в течение 10 сек) не нажимается то возвращаемся в режим отображения температуры и влажности
if (mode != 0 && counter > 1000) {
//если возврат производится с какого-либо экрана настройки, то сообщим о том, что настройки не были сохранены
if (mode < 6) {
lcd.setCursor(0, 0);
lcd.print(MakeString("Settings"));
lcd.setCursor(0, 1);
lcd.print(MakeString("NOT Saved"));
delay(2000);
}
counter = 0;
mode = 0;
DrawLCD();
}
}

//запоминаем предыдущее значение кнопок
RbtnLastState = btnR;
GbtnLastState = btnG;

counter++; //увеличиваем значение счетчика циклов программы
delay(10); //задержка 10 мсек между циклами программы
}
void ReadData() {
//float tempC = sensors.getTempCByIndex(0); // the index 0 refers to the first device
/*
String tmb = "Котел: ";
String tmv = "Воздух: ";
String str;
str = "\xC2\xB0";
String str2 = "C";
str = str + str2;
str = tempC + str;
// lcd.setCursor(0, 0);
//lcd.print(sensors.getTempCByIndex(0));
lcd.setCursor(0, 0);
lcd.print(tmb + str);
lcd.setCursor(0, 1);
lcd.print(tmv + str);
*/
/////////////////////////
sensors.requestTemperatures();
//rt = sensors.getTempCByIndex(0); //получаем температуру теплоносителя

// Округление полученной температуры до десятых
// Пример: 23.899 => 238.99 => 239.49 => 239 => 23.9) // При округлении изменился первый разряд, после запятой. Правило работает.
//float tempC = sensors.getTempCByIndex(0) * 10;
//tempC = tempC + 0.5;
//tempC = (int)tempC;
//tempC = tempC / 10;
rt = sensors.getTempCByIndex(0);
//проверяем считанное значение, если пустое то выдаем ошибку, если не пустое то производим вычисления
if (isnan(rt)) {

//если не удалось считать данные
lcd.setCursor(0, 0);
strOut = MakeString("Read Error");
lcd.print(strOut);
lcd.setCursor(0, 1);
strOut = "Check Sensor";
lcd.print(strOut);
} else {
//Serial.println("ReadData: if isnan rt=" + String(rt));
measureCnt++; //увеличили количество проведенных измерений
//h=h+rh; //суммируем показания влажности
t = t + rt; //суммируем показания температуры
//если набрали нужное количество измерений
if (measureCnt == measureCntMax) {
//вычисляем средние значения
//h=h/measureCntMax;
t = t / measureCntMax;
//запомним последние значения температуры и влажности для вывода на экран
//out_h=String(h);
out_t = String(t);
//включаем/отключаем нагрузку
if (t != 0) {
DoAll(); //процедура, котоаря управляем нагрузкой в соответствии с правилами
}
//сбрасываем счетчик количества измерений
measureCnt = 0;
//h=0;
t = 0;
}
DrawLCD();
}
}

//процедура отрисовки экрана LCD
void DrawLCD() {
Serial.println("DrawLCD function mode = " + String(mode));

switch (mode) {
case 0:
lcd.setCursor(0, 0);

strOut = MakeString("tB: " + out_t + "\xC2\xB0" + "C");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("tV: " + out_h + "\xC2\xB0" + "C");
lcd.print(strOut);

//рисуем и убираем точку в правом нижнем углу для индикации процесса измерения
lcd.setCursor(15, 1);

if (tiktak == " ") {
tiktak = "#";
} else {
tiktak = " ";
}
lcd.print(tiktak);

Serial.println("DrawLCD function tiktak = " + tiktak);
break;
case 1:
lcd.setCursor(0, 0);
strOut = MakeString("Temp On: " + String(tempHeatOn) + "*C");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("");
lcd.print(strOut);
break;
case 2:
lcd.setCursor(0, 0);
strOut = MakeString("Temp Off: " + String(tempHeatOff) + "*C");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("");
lcd.print(strOut);
break;
case 3:
lcd.setCursor(0, 0);
strOut = MakeString("Hum On:");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("");
lcd.print(strOut);
break;
case 4:
lcd.setCursor(0, 0);
strOut = MakeString("Hum Off: ");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("");
lcd.print(strOut);
break;
case 5:
lcd.setCursor(0, 0);
strOut = MakeString("Vent 1 Active: ");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("Vent 2 Active: ");
lcd.print(strOut);
break;
case 6:

break;
case 7:
lcd.setCursor(0, 0);
strOut = MakeString("Temp On: " + String(tempHeatOn) + "*C");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("Temp Off: " + String(tempHeatOff) + "*C");
lcd.print(strOut);
break;
case 8:
lcd.setCursor(0, 0);
strOut = MakeString("Hum On: ");
lcd.print(strOut);

lcd.setCursor(0, 1);
strOut = MakeString("Hum Off: ");
lcd.print(strOut);
break;
}
}

//правила поведения устройства в зависимости от температуры и влажности
void DoAll() {

//отключаем обогрев, когда температура пришла в норму, а также влажность не превышает верхний предел (порог включения вытяжки)
if (t >= tempHeatOff && HeatState == 1) {
//digitalWrite(4,0);
//digitalWrite(14,LOW);
HeatState = 0;
delay(200);
Serial.println("heat off");
}



//здесь будет код для открытия приточки
//если влажность в помещении высокая, и на улице температура больше 0 и нет дождя и сухая земля, и приточка закрыта, то открываем приточку
//если влажность вернулась в норму и приточка открыта, то закрываем приточку
//реле 3, разъем 4
//digitalWrite(3,1);
//digitalWrite(3,0);
}

//функция для формирования строки длинною 16 символов для вывода на экран, позволяет не вызывать функцию очистки экрана, ускоряет процесс работы скетча
//недостающие символы заполняются пробелами до 16 знака
String MakeString(String str) {
String res;
res = str;
while (res.length() < 16) {
res = res + " ";
}
return res;
}
Не бойся поломать. Бойся не починить ))

Изображение
Ответить