Niejednokrotnie korzystałem z porad na różnych forach jak również z tego forum. Postanowiłem się więc podzielić kodem sterownika solarnego podgrzewania basenu. Sterownik nie został jeszcze przetestowany i pewnie wymaga kilku poprawek, lecz nie o sterowanie tu chodzi lecz o zmianę ustawień sterownika za pomocą dwóch przycisków.
W programie wykorzystałem bibliotekę do wielozadaniowości (timers). Przyzwyczajony do programowania w delphi nie mogłem pogodzić się z istnieniem jednej pętli loop i następnych pętli do obsługi np menu. Dzięki niej można podzielić program na procedury i nie bać się, że menu zablokuje nam np odczyt temperatury.
W sterowniku użyłem 3 termometrów DS18B20. Już wcześniej nauczyłem się oszczędzać piny arduino więc skorzystałem z biblioteki onewire.
Całość działa tak:
- Co sekundę aktualizuję wyświetlacz i w razie potrzeby włączam lub wyłączam pompę lub elektrozawór. (1 linia obrony przed błędami odczytu temperatury)
- Co 700 ms sprawdzam temperaturę i w przypadku wystąpienia sytuacji alarmowej odpowiednio włączam pompę i zamykam elektrozawór
- Co 170 ms sprawdzam czy nie nacisnąłem przycisku i w zależności od tego jaki stan ustawiłem przyciskami wyświetlam to.
- Dla zabawy dodałem zegarek, który jest potrzebny co cyklicznego załączania pompy. Dokładność nie jest wymagana, więc wystarczy mi taki mniej więcej. Gdy jest zegar to od razu zachciało się by w nocy pompa pracowała np rzadziej, więc ten zegarek trzeba by jakoś ustawić. A obudowa posiada tylko 2 przyciski. Dodałem więc procedurę inkrementator, która nie robi nic innego tylko liczy jak długo jest naciśnięty przycisk. Dzięki temu ustawienie godziny polega na ustawianiu minut. Jedno naciśnięcie - minuta, gdy dłużej przytrzymamy, to zwiększa o 10min a jeszcze dłużej o 30min.
Ważne! w programie nadal są błędy, więc nie podłączajcie modułów wykonawczych.
#include <stdlib.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include <Timers.h>
Timers <5> akcja;
#define BUTTON_MENU 7
#define BUTTON_SET 6
#define ONE_WIRE_BUS 10 // Wybieramy linię pod którą podepniemy termometry
#define PUMP 9
#define BAYPAS 8
//#include <Wire.h> do SDA SCL
#include <OneWire.h>
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
byte sekundy;
byte minuty;
byte godziny;
byte delta_temp;
byte delta_temp_minus; //histereza
byte delta_temp_old;
byte cykl_filtr;
byte cykl_filtr_old;
byte ustawienie_filtr;
byte licznik_filtr;
byte alarm;
byte MENU;
byte PUMP_STATE; // tu przechowujemy stan pompy
byte BAYPAS_STATE; // tu przechowujemy stab elektrozaworu
byte Dodaj;
int czast;
int korekta_czas = 980;
int korekta_czas_old = korekta_czas;
float t1 = 19.2;
float t2 = 22.1;
float t3 = 77.2;
char *TT;
int mm; //to zmienna do symulacji - usunąć
void displayTemp(float T1, float T2, float T3) {
String test = "";
String linia1 = "";
String linia2 = "";
if ((T1>0) && (T1<100)) {
test = dtostrf(T1,2,1,TT);
test += " ";
} else test = "---- ";
if ((T2>0) && (T2<100)) {
test += dtostrf(T2,2,1,TT);
test += " ";
} else test += "---- ";
if ((T3>0) && (T3<100)) {
test += dtostrf(T3,2,1,TT);
} else test += "----";
linia1 = test.substring(0,8);
linia2 = test.substring(8,16);
lcd.setCursor(0, 0);
lcd.print(linia1);
lcd.setCursor(0, 1);
lcd.print(linia2);
}
void Wyswietlacz() {
if (alarm==1) {
lcd.setCursor(1,1); lcd.print(F("TEMPERAT"));
lcd.setCursor(0,1); lcd.print(F("URA>70'"));
} else {
switch (MENU) {
case 0: displayTemp(t1,t2,t3); break;
case 1: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("Filtr ")); lcd.setCursor(3,1); lcd.print(cykl_filtr); break;
case 2: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("Delta T.")); lcd.setCursor(3,1); lcd.print(delta_temp); break;
case 3: lcd.setCursor(0,0); lcd.print(F("Godzina "));
lcd.setCursor(0,1);
if (godziny<10) lcd.print("0"); lcd.print(godziny); lcd.print(":");
if (minuty<10) lcd.print("0"); lcd.print(minuty); lcd.print(":");
if (sekundy<10) lcd.print("0"); lcd.print(sekundy);
break;
case 4: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("KorCzas+")); lcd.setCursor(3,1); lcd.print(korekta_czas); break;
case 5: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("KorCzas-")); lcd.setCursor(3,1); lcd.print(korekta_czas); break;
}
}
}
void Stan() {
t1 = t1 + mm;
if (t1>100) mm = -1;
if (t1<0) mm = 1;
sensors.requestTemperatures();
float temperature1 = sensors.getTempCByIndex(0); // basen
float temperature2 = sensors.getTempCByIndex(1); // wej solar
float temperature3 = sensors.getTempCByIndex(2); // wyj solar
float avgtemp = ((temperature2+temperature3)/2); // generalnie jak pompa nie będzie pracować woda w solarze nagrzeje się równomiernie
if ((temperature2>70) || (temperature3>70)) {
PUMP_STATE=1;
BAYPAS_STATE=0;
digitalWrite(PUMP, HIGH); // uwaga - teraz jest ustawione dla npn - zmienić na PNP czyli LOW i HIGH
digitalWrite(BAYPAS, LOW);
alarm = 1;
}
else
{
alarm = 0;
if ((avgtemp-temperature1) > delta_temp) {
PUMP_STATE=1;
BAYPAS_STATE=0;
digitalWrite(PUMP, HIGH); // uwaga dopilnować negacji!
digitalWrite(BAYPAS, LOW);
}
// Jeśli temp jest mniejsza niz delta wylaczenia, to
// jesli jest cykl filtrowania to wlaczamy tylko baypas
// w przeciwnym wypadku wylaczamy pompe i baypas
if ((avgtemp-temperature1) < (delta_temp-delta_temp_minus)) {
if (licznik_filtr <= cykl_filtr) BAYPAS_STATE=1;
else
{
PUMP_STATE=0;
BAYPAS_STATE=0;
}
}
}
}
void Czas() {
Wyswietlacz();
if (PUMP_STATE == 1) digitalWrite(PUMP, HIGH); else digitalWrite(PUMP, LOW);
if (BAYPAS_STATE == 1) digitalWrite(BAYPAS, HIGH); else digitalWrite(BAYPAS, LOW);
}
void Inkrementator() {
if (czast>10) Dodaj=10;
if (czast>40) Dodaj=30;
if (czast==0) Dodaj=1;
}
void EEPROMWriteInt(int p_address, int p_value)
{
byte lowByte = ((p_value >> 0) & 0xFF);
byte highByte = ((p_value >> 8) & 0xFF);
EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}
//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
{
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);
return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}
void Przyciski () {
if (digitalRead(BUTTON_MENU) == LOW) {
MENU++;
if (MENU>5) MENU=0;
delay(50);
}
if (MENU !=3) {
if (digitalRead(BUTTON_SET) == LOW) {
switch (MENU) {
case 1: cykl_filtr ++; if (cykl_filtr>4) cykl_filtr=1; break;
case 2: delta_temp = delta_temp+2; if (delta_temp>12) delta_temp=4; break;
case 4: korekta_czas++; break;
case 5: korekta_czas--; break;
}
delay(50);
}
} else {
if (digitalRead(BUTTON_SET) == LOW) {
minuty = minuty + Dodaj;
if (minuty > 59) {
minuty=0;
godziny++;
if (godziny > 23) godziny=0;
}
czast++;
delay(2);
}
}
if (digitalRead(BUTTON_SET) == HIGH) czast=0;
Wyswietlacz();
// zapis ustawień
switch (MENU) {
case 0:
displayTemp(t1,t2,t3);
if (cykl_filtr != cykl_filtr_old) { EEPROM.write(1, cykl_filtr); cykl_filtr_old = cykl_filtr; }
if (delta_temp != delta_temp_old) { EEPROM.write(0, delta_temp); delta_temp_old = delta_temp; }
if (korekta_czas != korekta_czas_old) { EEPROMWriteInt(2,korekta_czas); korekta_czas_old = korekta_czas; }
break;
}
}
void LiczSekundy() {
static unsigned long lastTick = 0;
if (millis() - lastTick >= korekta_czas) { // korekta spóźniania - wygląda na to że 1000 milis trwa dłużej, więc zmniejszymy tą wartość 990 nadal za dużo
lastTick = millis();
sekundy++;
//if (sekundy == 2) sekundy++; // korekta spóźniania
}
if (sekundy > 59) {
sekundy=0;
minuty++;
if (minuty > 59) {
minuty=0;
godziny++;
if (cykl_filtr>0) { // normalny program
licznik_filtr++;
}
// Tutaj program
if (cykl_filtr<4) {
if (licznik_filtr > cykl_filtr*2) {
licznik_filtr=1;
}
if (licznik_filtr <= cykl_filtr) {
PUMP_STATE=1;
} else {
PUMP_STATE=0;
}
}
if (godziny > 23) {
godziny=0;
}
}
}
}
void setup() {
TT = new char[4];
lcd.begin(8, 2);
pinMode(BUTTON_MENU, INPUT);
digitalWrite(BUTTON_MENU, HIGH);
pinMode(BUTTON_SET, INPUT);
digitalWrite(BUTTON_SET, HIGH);
pinMode(PUMP, OUTPUT);
digitalWrite(PUMP, HIGH); // negacja z powodu tranzystorów PNP
pinMode(BAYPAS, OUTPUT);
digitalWrite(BAYPAS, HIGH);
mm=1;
Dodaj = 1;
//Wire.begin();
sensors.begin();
sekundy=0;
minuty=0;
godziny=0;
delta_temp_minus=2;
licznik_filtr=1;
alarm = 0;
MENU=0;
PUMP_STATE=0;
BAYPAS_STATE=0;
delta_temp = EEPROM.read(0);
cykl_filtr = EEPROM.read(1);
korekta_czas = EEPROMReadInt(2);
if (korekta_czas == 0) korekta_czas = 980;
delta_temp_old = delta_temp;
cykl_filtr_old = cykl_filtr;
korekta_czas_old = korekta_czas;
if ((delta_temp<4) || (delta_temp>12)) delta_temp=4;
if ((cykl_filtr<1) || (cykl_filtr>4)) cykl_filtr=1;
akcja.attach(0, 1000, Czas);
akcja.attach(1, 700, Stan);
akcja.attach(2, 170, Przyciski);
akcja.attach(3, 300, Inkrementator);
akcja.attach(4, 50, LiczSekundy);
}
void loop() {
akcja.process();
}