Jako, że Exta-Life od Zamela nie sprawdził się w tej funkcji to postanowiłem zrobić sterowanie ogrzewaniem podłogowym za pomocą Arduino Nano i kilkoma dodatkami do niego.
Do wysterowania mamy 4 pomieszczenia w których jest 5 obwodów podłogówki oraz pompka. Dodatkowo o określonych godzinach załączane jest podgrzanie wody w buforze. Są tam dwie grzałki po 4,5 kW sterowane przez stycznik. Te określone godziny to druga taryfa od Tauron-a. Jak się domyślacie mam ogrzewanie elektryczne domu.
Wszystko działa tak jak zaplanowałem. Mikrokontroler sprawdza temperaturę w pomieszczeniach i jak jest niższa niż ustawiona dla danego pomieszczenia to załącza elektro zawór. Pompka jest połączona układem opóźniającym załączenie zasilania o 2 min. Układ czasowy jest połączony z wyjściem sumatora SEM-01 z firmy Zamel. Wejścia sumatora są połączone z wejściami elektro zawórów. Oczywiście jeżeli pracuje już któryś obwód to pompka jest już załączona.
W godzinach 13-15 i 22-6 oraz całe weekendy załącza grzanie bufora do ustawionej temperatury. (ze względu na brak połączenia w tej chwili z siecią grzanie bufora jest realizowane przez inny układ.)
Kod źródłowy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
[c++]// Dołączanie bibliotek include // include //cyfrowy czujnik temperatury include //wyswietlacz LCD include //magistrala SPI //#include //karta SD //#include //Moduł ethernetowy //Definicja serwera //#define swiatloSalon 3 //definiujemy pod ktory pin w arduino podpięliśmy przekaźnik /* byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address IPAddress ip(192,168,1,201); // ARDUINO IP W SIECI IPAddress gateway(192,168,1,20); // internet access via router IPAddress subnet(255,255,255,0); //subnet mask IPAddress myserver(192,168,1,41); // DOMOTICZ IP EthernetServer server(84); //PORT ARDUINO EthernetClient client; String readString;*/ //__________Obsługa czujników temperatury define ONEWIRE_PIN 2 // Numer pinu do którego podłaczasz czujnik define SENSORS_NUM 4 // Ilość czujników const byte address[SENSORS_NUM][8] PROGMEM = {// Adresy czujników 0x28, 0xFF, 0x46, 0xC8, 0x6B, 0x18, 0x1, 0xB8, 0x28, 0xFF, 0xC1, 0x9B, 0x6B, 0x18, 0x1, 0x72, 0x28, 0xFF, 0xE1, 0x61, 0x6C, 0x18, 0x1, 0x9A, 0x28, 0xFF, 0x59, 0xCF, 0x6B, 0x18, 0x1, 0x2D }; OneWire onewire(ONEWIRE_PIN); DS18B20 sensors(&onewire); //<strong><em><strong><em>____Obsługa wyświetlacza LCD LiquidCrystal_I2C lcd(0x3F, 16, 2); //____</em></strong></em></strong> Zmienne globalne //<strong><em>__</em></strong> Dane wyswietlane na LCD char *k0="Ustaw.T= "; char *k1=" <> Temp="; char <em>k2="</em>C"; char *k3="Zapis! "; char *k4="Odczy.T= "; char *k5="Blad "; char *k6="Ustawiona"; char *k7="Powrot! "; char *k8=""; char *k9=""; char *k10=""; float temp[] = {26.00,26.00,26.00,26.00,22.00,22,00,22.00,22.00}; float histereza[] = {1.20,1.20,1.20,1.20,1.20,1.20,1.20,1.20}; int licznik = 0; int sensorNumber = SENSORS_NUM; String nazwy[] = {"Bartosz: ","Blazej: ","Salon: ","Lazienka:","Puste: ","Puste: ","Puste: ","Puste: "}; String menu[]={"Nazwy kanalow","Histereza","Temperatura","Zapis karta SD","Zapis baza MySQL","Odczyt karta SD","Odczyt z MySQL"}; String puste(" ");//Czyszczenie jednej linii wyświetlacza int menuMax = 6; unsigned long opoznienieAkt[8]; unsigned long opoznienieZap[8]; //Ustawienia po uruchomieniu Arduino void setup() { Serial.begin(9600); //inicjalizacja UART lcd.begin(); //inicjalizacja wyświetlacza LCD lcd.backlight(); //włączenie podświetlenia LCD lcd.clear(); //wyczyszczenie ekranu LCD sensors.begin(); //inicjalizacja DS18B20 /* pinMode(swiatloSalon, OUTPUT);//ustawienie pinu jako wyjścia Ethernet.begin(mac, ip, subnet, gateway); //uruchamiamy moduł ethernet shield server.begin();*/ } void loop() { sensors.request(); //odczytanie danych z czujników temperatury delay(100); if(getAnalogButton()==5){nastawyTemperatura(temp[licznik],18.00,28.00);} if(getAnalogButton()==0){menuGlowne();} if(getAnalogButton()==2){licznik++;if(licznik==sensorNumber){licznik=0;}} if(getAnalogButton()==8){licznik--;if(licznik==-1){licznik=sensorNumber-1;}} odczytTemp(licznik); sterowanieOgrzewaniem(6,0,10000ul,0.5);//PIN D6 Przekaźnik 1 sterowanieOgrzewaniem(7,1,10000ul,0.5);//PIN D7 Przekaźnik 2 sterowanieOgrzewaniem(8,2,10000ul,0.5);//PIN D8 Przekaźnik 3 sterowanieOgrzewaniem(9,3,10000ul,0.5);//PIN D9 Przekaźnik 4 } //Odczyt przycisków z wejścia Analogowego int getAnalogButton(){ if(analogRead(0)<500){delay(30);if(analogRead(0)<500)return 0;} if(analogRead(0)<800 and analogRead(0)>700){delay(30);if(analogRead(0)<800 and analogRead(0)>700)return 5;} if(analogRead(0)<700 and analogRead(0)>600){delay(30);if(analogRead(0)<700 and analogRead(0)>600)return 8;} if(analogRead(0)<600 and analogRead(0)>500){delay(30);if(analogRead(0)<600 and analogRead(0)>500)return 2;} return 100; } //Funkcje ekran wyświetlanie na wyświetlaczy LCD przesłanych danych. Jest kilka funkcji z różnymi typami danych. void ekran(char *kL, float v ,char *kP="",int wiersz=1) { if(wiersz>=0) { lcd.setCursor(0,wiersz);lcd.print(" "); lcd.setCursor(0,wiersz);lcd.print(kL);lcd.print(v);lcd.print(kP); } else {Serial.print(kL);Serial.print(v);Serial.println(kP);} } void ekran(String kL, float v ,char *kP="",int wiersz=1) { if(wiersz>=0) { lcd.setCursor(0,wiersz);lcd.print(" "); lcd.setCursor(0,wiersz);lcd.print(kL);lcd.print(v);lcd.print(kP); } else {Serial.print(kL);Serial.print(v);Serial.println(kP);} } void ekran(char *kK,int wiersz=1) { if(wiersz>=0) { lcd.setCursor(0,wiersz);lcd.print(" "); lcd.setCursor(0,wiersz);lcd.print(kK); } else Serial.print(kK); } void ekran(String kL,int wiersz=1) { if(wiersz>=0){ lcd.setCursor(0,wiersz);lcd.print(puste);lcd.setCursor(0,wiersz);lcd.print(kL); } else Serial.print(kL); } //Wyświetlenie na LCD temperatury odczytanej i ustawionej. void odczytTemp(int i){ float temperature = sensors.readTemperature(FA(address[i])); ekran(nazwy[licznik],temperature,k2,0); ekran(k6,temp[licznik],k2); } //Sterowanie ogrzewaniem w zależności od ustawionych parametrów. void sterowanieOgrzewaniem(int PIN,int i,unsigned long opoznienie,float histereza){ float temperature = sensors.readTemperature(FA(address[i])); int opoz = Opoznienie(i,opoznienie); //Serial.println(hist); if(temperaturetemp[i] and opoz==1){ digitalWrite(PIN, LOW);//Serial.print(digitalRead(6));Serial.print("PIN ");Serial.println(PIN); } } int Opoznienie(int i, unsigned long czas){ opoznienieAkt[i]=millis(); if(opoznienieAkt[i] - opoznienieZap[i]>czas){ opoznienieZap[i]=millis(); return 1; } else {return 0;} } int histerezaSprawdz(int i, float histereza[]){ } void wyswietlanie(int licznik, int v,int vmax, int vmin){ ekran(k0,v,k2); int zm=-1; int x=-1; while(x!=5) { x=getAnalogButton(); if(x!=zm) { switch(x) { case 2: v=v+0.2;if(v>vmax)v=vmax;ekran(k1,v,k2);break; case 8: v=v-0.2;if(vmenuMax){i=menuMax;};ekran(menu[i],1);break; case 8: i--;if(i<0){i=0;};ekran(menu[i],1);break; case 5: ekran(k7);delay(2000);ekran("");return x;break; case 0: break; } } zm=x; } } int nastawyTemperatura(float v, float vmin, float vmax) { ekran(k0,v,k2); int zm=-1; int x=-1; while(x!=0) { x=getAnalogButton(); if(x!=zm) { switch(x) { case 2: v=v+0.2;if(v>vmax)v=vmax;ekran(k1,v,k2);break; case 8: v=v-0.2;if(v<vmin)v=vmin;ekran(k1,v,k2);break; case 0: ekran(k3);delay(2000);ekran("");temp[licznik]=v;return x;break; } } zm=x; } } int nastawyHistereza(unsigned long opoznienie, int roznicaTemperatury){ } int nastawyNazwyKanalow(){ } // Zapisywanie ustawień na kartę SD (temperatura, histereza, nazwa) plik conf.cfg lub sett.cfg int zapisKartaSD(){ /* File plik; if (!SD.begin(4)) //sprawdź czy nie ma karty na pinie ChipSelect 4 { Serial.println("Nie wykryto karty"); //błąd wykrycia karty return; //przerwij program } SD.exists("conf.txt"); plik = SD.open("conf.txt", FILE_WRITE); //Otwarcie pliku do odczytu i zapisu //plik = SD.open("conf.txt", FILE_READ); //Otwarcie pliku do odczytu //SD.remove("conf.txt"); //Usuwanie pliku plik.available(); //Sprawdzenie czy w pliku coś jest plik.read(); */ //Odczytanie danych z pliku } // Zapisywanie ustawień do bazy MySQL (temperatura, histereza, nazwa) int zapisMySQL(){ } // Odczytywanie ustawień z karty SD (temperatura, histereza, nazwa) plik conf.cfg lub sett.cfg int odczytKartaSD(){ } // Odczytywanie ustawień z bazy MySQL (temperatura, histereza, nazwa) int odczytMySQL(){ } [/c++] |
Spis elementów i kosztorys:
- Płytka Arduino Nano – 13,00 zł
- Moduł przekaźników SSR 8 szt. na płytce 42,00 zł
- Zegar czasu rzeczywistego RTC 1307 – 6,50 zł
- Czujniki DS18B20 4 szt. – 14,00 zł
- Wyświetlacz LCD 16×2 – 16,00 zł
- 4 szt. przełączników TACT do zmiany nastaw temperatury – 2,00 zł
- Zasilacz modułowy na szynę DIN 12V – Zamel – 41,60 zł
- Obudowa na szynę DIN Z104 Kradex – 8,67 zł
- Gniazdo USB do przyszłego programowania bez potrzeby rozbierania obudowy – 5,50 zł
- Moduł Ethernet W5100 do połączenia z siecią i zbieraniu danych do bazy danych. – 21,63zł
Witam.
Coś skąpo się dzielisz. Żadnych zdjęć, schematów że o wsadzie nie wspomnę.
Pozdrawiam
Zbigniew Bączalski
Witam
Nie wszystko w obecnej wersji zostało zrealizowane.
Wrzuciłem co mam tzn zdjęcia i kod.
Schemat musiałbym narysować bo poskładałem to w locie.
Będę za jakiś czas to wszystko aktualizował zgodnie z tym co jest w rzeczywistości pozmieniane
Pozdrawiam
Czy ten kod zadziała na arduino yun?
Prawdę mówiąc nie wiem czy zadziała, nigdy go nie używałem. Trzeba by było sprawdzić a nie mam jak.
Dzień dobry. Zainspirowałeś mnie tym projektem. Obecnie pracuję nad sterownikiem PID do wodnego ogrzewania podłogowego w oparciu o esphome. Czy próbowałeś w swoim sterowani zastosować PID?
Witam.
Myślałem nad tym ale ogrzewanie podłogowe ma bardzo duża bezwładność. Ja wodne mam tylko na górze. U mnie włącza się na 2 godziny w nad ranem i to wystarcza na zazwyczaj na całą dobę. Jak komuś jest za zimno w swoim pokoju to może sobie z ręki załączyć.
Mam w planach całość przerobić na PLC Simensa ale ciągle brak czasu. Więc od paru lat to tak działa jak opisałem.