-
-
Save anonymous/9dc7c6319224941b2e40 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Includes ------------------------------------------------------------------------------------------------------------------------------------------------------- | |
#include <avr/sleep.h> | |
#include <Time.h> | |
#include <Wire.h> | |
#include <DS3232RTC.h> | |
#include <LiquidCrystal.h> | |
#include "stdio.h" | |
#include "string.h" | |
//Defines ------------------------------------------------------------------------------------------------------------------------------------------------------- | |
//IO-Exp | |
#define Addr 0x20 //wenn A0,A1,A2 auf GND gezogen werden, 0x27 A0,A1,A2 auf 5V | |
#define Ausgang_All 0x00 //0 entspricht Output | |
#define IODIR 0x00 //00h | |
#define GPIO 0x09 //09h | |
//FeldA[GP0] | |
//FeldB[GP1] | |
//FeldC[GP2] | |
//FeldD[GP3] | |
//Schlauch[GP4] | |
#define Fass 5 //Digitaler Pin am Portexpander für Fassventil [GP5] | |
#define Pumpe 6 //Digitaler Pin am Portexpander für Pumpe und 12V Versorgungsspannung der Ventile [GP6] | |
#define SensorRelais 7 //Digitaler Pin am Portexpander für 5V Versorgungsspannung der Feuchtigkeitssensoren (und LCD) [GP7] | |
//Analog Pins | |
#define SensorA 0 | |
#define SensorB 1 | |
#define SensorC 2 | |
#define SensorD 3 | |
//Digitale Pins | |
#define minFuellstand 8 //Digitaler Pin für Fuellstandssesnsor min | |
#define maxFuellstand 9 //Digitaler Pin für Fuellstandssensor max | |
#define BestButton 2 | |
#define HochButton 3 | |
#define LS_Pin 10 | |
#define RunterButton 13 | |
#define maxLiter 1 | |
#define minLiter 0.5 | |
#define MAX_INDEX 12 | |
#define HOCH 'w' | |
#define RUNTER 's' | |
#define OK 'f' | |
//Variablen | |
volatile int pulses = 0; | |
volatile bool autModus = 0; | |
int fehler = 0; | |
int _index = 0; | |
int alt_index = -1; | |
char _eingabe = '\0'; | |
int _cursor = 1; | |
bool taster_val = false; | |
bool oldvalB = true; | |
bool oldvalH = true; | |
bool oldvalR = true; | |
long sleepTime = 0; | |
//Arrays ------------------------------------------------------------------------------------------------------------------------------------------------------- | |
int bewaesserungsArray[5] = { | |
0 , /* initializers for row indexed by 0 [Feld A] */ | |
0 , /* initializers for row indexed by 1 [Feld B] */ | |
0 , /* initializers for row indexed by 2 [Feld C] */ | |
0 , /* initializers for row indexed by 3 [Feld D] */ | |
0 /* initializers for row indexed by 4 [Schlauch] */ | |
}; | |
int grenzwertArray[4][2] = { | |
//Sehr trocken , trocken | |
{20, 50} , /* initializers for row indexed by 0 [Feld A] */ | |
{20, 50} , /* initializers for row indexed by 1 [Feld B] */ | |
{20, 50} , /* initializers for row indexed by 2 [Feld C] */ | |
{20, 50} /* initializers for row indexed by 3 [Feld D] */ | |
}; | |
/* LCD MENU -----------------------------------------------------------------------------------------------------------------------------*/ | |
LiquidCrystal lcd(12, 11, 4, 5, 6, 7); | |
struct Anzeige{ | |
char line1[16]; | |
char line2[16]; | |
}; | |
struct Anzeige _step0 = {"Zeit:", "Manuell giesen?"}; | |
struct Anzeige _step1 = {"Feld A:", "Manuell giesen?"}; | |
struct Anzeige _step2 = {"Feld A:", "min max aus"}; | |
struct Anzeige _step3 = {"Feld B:", "Manuell giesen?"}; | |
struct Anzeige _step4 = {"Feld B:", "min max aus"}; | |
struct Anzeige _step5 = {"Feld C:", "Manuell giesen?"}; | |
struct Anzeige _step6 = {"Feld C:", "min max aus"}; | |
struct Anzeige _step7 = {"Feld D:", "Manuell giesen?"}; | |
struct Anzeige _step8 = {"Feld D:", "min max aus"}; | |
struct Anzeige _step9 = {"Schlauch:", "Manuell giesen?"}; | |
struct Anzeige _step10 = {"Schlauch:", "min max aus"}; | |
struct Anzeige _last = {"Starten?", "\0"}; | |
struct Anzeige lcdTEXT[MAX_INDEX] = {_step0, _step1, _step2, _step3, _step4, _step5, _step6, _step7, _step8, _step9, _step10, _last}; | |
void printLCD(struct Anzeige _a){ | |
lcd.clear(); | |
lcd.setCursor(0, 0); | |
lcd.print (_a.line1); | |
lcd.setCursor(0, 1); | |
lcd.print(_a.line2); | |
if(_index == 0) { | |
lcd.setCursor(8, 0); | |
printTime(); | |
} | |
else if(_index < 9) { | |
if(_index == 1 || _index == 2){ | |
lcd.setCursor(8, 0); | |
lcd.print(getFeuchtigkeit(SensorA)); | |
} | |
if(_index == 3 || _index == 4){ | |
lcd.setCursor(8, 0); | |
lcd.print(getFeuchtigkeit(SensorB)); | |
} | |
if(_index == 5 || _index == 6){ | |
lcd.setCursor(8, 0); | |
lcd.print(getFeuchtigkeit(SensorC)); | |
} | |
if(_index == 7 || _index == 8){ | |
lcd.setCursor(8, 0); | |
lcd.print(getFeuchtigkeit(SensorD)); | |
} | |
lcd.setCursor(11, 0); | |
lcd.print(F("%")); | |
} | |
lcd.setCursor(0,1); //Quick an durty curser steht sonst für ->Min<- max auf falscher Stelle | |
} | |
/* LCD MENU ENDE-----------------------------------------------------------------------------------------------------------------------------*/ | |
void setTime() | |
{ | |
//this example first sets the system time (maintained by the Time library) to | |
//a hard-coded date and time, and then sets the RTC from the system time. | |
//the setTime() function is part of the Time library. | |
setTime(00, 00, 00, 29, 01, 2015); //set the system time to 23h31m30s on 13Feb2009 | |
if (!RTC.set(now())) //set the RTC from the system time | |
Serial.println(F("Time is set successful!")); | |
else | |
{ | |
Serial.println(F("Time is NOT set. ERROR!")); | |
fehler = 1; | |
} | |
} | |
void printTime() | |
{ | |
tmElements_t tm; | |
RTC.read(tm); | |
if ( RTC.read(tm) ) { //(returns zero if successful) Reads the current date and time from the RTC and returns it as a tmElements_t structure | |
Serial.println(F("Can´t read Time. ERROR!")); | |
fehler = 1; | |
} | |
if(tm.Hour < 10) { | |
Serial.print(F("0")); | |
lcd.print(F("0")); | |
} | |
lcd.print(tm.Hour, DEC); | |
lcd.print(':'); | |
Serial.print(tm.Hour, DEC); | |
Serial.print(':'); | |
if(tm.Minute < 10) { | |
Serial.print(F("0")); | |
lcd.print(F("0")); | |
} | |
lcd.print(tm.Minute, DEC); | |
Serial.print(tm.Minute,DEC); | |
Serial.print(':'); | |
if(tm.Second < 10) { | |
Serial.print(F("0")); | |
} | |
Serial.println(tm.Second,DEC); | |
} | |
void setInterruptAlarm() | |
{ | |
//RTC.alarm(ALARM_1);//reset Interrupt Pin of RTC (reienfolge Okay???) | |
//Set Alarm1 for 12:34:56 on Sunday -> ALM1_MATCH_DAY, 56, 34, 12, dowSunday | |
RTC.setAlarm(ALM1_MATCH_MINUTES, 00, 2, 1, 1);//RTC.setAlarm(alarmType, seconds, minutes, hours, dayOrDate); | |
RTC.alarmInterrupt(ALARM_1, true); //assert the INT pin when Alarm1 occurs | |
Serial.println(F("Automatic RTC-Alarm is set!")); | |
RTC.alarm(ALARM_1);//reset Interrupt Pin of RTC (reienfolge Okay???) | |
} | |
void irhandlerINT0() { | |
detachInterrupt(0); | |
} | |
void irhandlerINT1() | |
{ | |
pulses++; | |
} | |
void enterSleep() | |
{ | |
delay(200); | |
attachInterrupt(0, irhandlerINT0, LOW); //Call ISR-Routine when Pin2 drops LOW | |
Serial.println(F("Going to sleep!")); | |
setPortExpCh(SensorRelais, true); | |
_index=0; | |
delay(200); | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here | |
sleep_enable(); // enables the sleep bit | |
sleep_mode(); // here the device is actually put to sleep!! | |
// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP and interruptSR is finished | |
sleep_disable(); | |
delay(200); // interruptSR code will not be executed | |
// during normal running time. | |
Serial.println(F("Just woke up")); | |
delay(500); | |
setPortExpCh(SensorRelais, false); | |
delay(200); | |
lcd.begin(16,2); | |
delay(200); | |
printLCD(lcdTEXT[_index]); | |
sleepTime = millis(); | |
} | |
float getLiter(){ | |
return (pulses*2.5/1000.0); | |
} | |
int getFeuchtigkeit(int AnalogPin) { | |
int Messwert = 0; | |
Messwert = analogRead(AnalogPin); | |
Messwert=int(100-(Messwert*0.09794)); | |
return Messwert; | |
} | |
void beep(unsigned char delayms, int Time1){ | |
long Time2 = millis(); | |
while(millis() - Time2 < Time1) { | |
analogWrite(LS_Pin, 100); // Almost any value can be used except 0 and 255 | |
// experiment to get the best tone | |
delay(delayms); // wait for a delayms ms | |
analogWrite(LS_Pin, 0); // 0 turns it off | |
delay(delayms); // wait for a delayms ms | |
} | |
} | |
void setPortExpToOutput() | |
{ | |
Wire.beginTransmission(Addr); | |
Wire.write(IODIR); | |
Serial.println(F("SetOutput")); | |
Wire.write(Ausgang_All); | |
Wire.endTransmission(); | |
/*Alle Outputs HIGH setzen weil Relais-Modul lowaktiv ist!*/ | |
Wire.beginTransmission(Addr); | |
Wire.write(GPIO); | |
Wire.write(0xFF); | |
Wire.endTransmission(); | |
} | |
void setPortExpCh(int channel, boolean val) | |
{ | |
int var1 = 0; | |
long t1 = 0; | |
Wire.beginTransmission(Addr); //starts talking to slave device | |
Wire.write(GPIO); //selects the GPIO pins | |
Wire.endTransmission(); //stops talking to device | |
Wire.requestFrom(Addr, 1); // requests one byte of data from MCP23017 | |
t1 = millis(); | |
while(!Wire.available()){ | |
if(millis() - t1 > 3000){ | |
Serial.println(F("Wire not available")); | |
break; | |
} | |
} | |
var1=Wire.read(); // store the incoming byte into var1 | |
Wire.beginTransmission(Addr); //starts talking to slave device | |
Wire.write(GPIO); //selects the GPIO pins | |
if(val) | |
{ Wire.write(var1|(1<<channel)); } //Set Channel HIGH | |
else | |
{ Wire.write(var1&=~(1<<channel)); } //Set Channel LOW | |
Wire.endTransmission(); | |
} | |
void feuchtigkeit() | |
{ | |
int Messwert = 0; | |
setPortExpCh(SensorRelais, LOW); //Spannungsversorgung für Sensoren anschalten | |
lcd.clear(); | |
lcd.setCursor(0,0); | |
lcd.print(F("Feuchtigkeit")); | |
lcd.setCursor(0,1); | |
lcd.print(F("bestimmen")); | |
delay(10000); | |
for(int i = 0; i<4; i++) //4 Sensoren abfragen | |
{ | |
Messwert = getFeuchtigkeit(i); | |
bewaesserungsArray[i] = 0; | |
if(Messwert<grenzwertArray[i][1]) //trocken | |
{bewaesserungsArray[i]=minLiter;} | |
if(Messwert<grenzwertArray[i][0]) //sehr Trocken | |
{bewaesserungsArray[i]=maxLiter;} | |
} | |
setPortExpCh(SensorRelais, HIGH); //Spannungsversorgung für Sensoren abschalten | |
bewaesserungsArray[4]=0; //Schlauch deaktivieren | |
} | |
void giessen() | |
{ | |
attachInterrupt(1,irhandlerINT1,RISING); | |
for(int i = 0; i<5; i++) | |
{ | |
Serial.print(F("bewässerungsarray[i]")); | |
Serial.println(bewaesserungsArray[i]); | |
if(bewaesserungsArray[i]>0) | |
{ | |
lcd.clear(); | |
lcd.setCursor(0, 0); | |
if(i == 0) {lcd.print(F("Feld A"));} | |
if(i == 1) {lcd.print(F("Feld B"));} | |
if(i == 2) {lcd.print(F("Feld C"));} | |
if(i == 3) {lcd.print(F("Feld D"));} | |
if(i == 4) {lcd.print(F("Schlauch"));} | |
lcd.print(F(" giessen"));//achtung 16 zeichen | |
pulses = 0; | |
setPortExpCh(i,LOW); | |
beep(50,400); | |
setPortExpCh(Pumpe,LOW); | |
long Time = millis(); | |
while(getLiter() < bewaesserungsArray[i])//UND NICHT STOP!!!??? | |
{ | |
lcd.setCursor(0, 1); | |
lcd.print(getLiter()); //aufruf zu oft? | |
lcd.print(" von "); | |
lcd.print(bewaesserungsArray[i]); | |
lcd.print(" Lit."); | |
delay(500); | |
if(millis() - Time > 60000 && getLiter() < 1) { //nach 60 sec weniger als 1l Durchfluss? -> Fehlerzustand | |
fehler = 1; | |
break; | |
} | |
} | |
setPortExpCh(Pumpe,HIGH); //Pumpe deaktivieren | |
delay(200); | |
setPortExpCh(i,HIGH); //Ventil deaktivieren | |
bewaesserungsArray[i]=0;//Rücksetzen für nächsten durchlauf | |
} | |
} | |
if(digitalRead(minFuellstand) == LOW) | |
{ | |
beep(50,400); | |
lcd.clear(); | |
lcd.setCursor(0, 0); | |
lcd.print(F("Fass fuellen.")); | |
setPortExpCh(Fass,LOW); | |
delay(200); | |
setPortExpCh(Pumpe,LOW); | |
pulses = 0; | |
long Time = millis(); | |
while(digitalRead(maxFuellstand) == LOW)//UND NICHT STOP!!!??? | |
{ | |
lcd.setCursor(0, 1); | |
lcd.print(getLiter()); | |
lcd.print(F(" Lit.")); | |
if(millis() - Time > 30000 && getLiter() < 1) { //nach 30 sec weniger als 1l Durchfluss? | |
fehler = 1; | |
break; | |
} | |
} | |
setPortExpCh(Pumpe,HIGH); | |
delay(200); | |
setPortExpCh(Fass,HIGH); | |
} | |
detachInterrupt(INT1); //INT1 zum zählen des Durchfluss deaktivieren | |
setPortExpCh(SensorRelais, HIGH); //LCD deaktivieren (GP7) SensorRelais | |
} | |
void setup() | |
{ | |
pinMode(2, INPUT); // Pin 2 is input to which an switch (Best.) AND an RTC is connected = INT0 | |
digitalWrite(2,HIGH); //activate internal Pull-Up resistor | |
pinMode(3, INPUT); // Pin 3 is input to which an switch (Hoch) AND an Durchflusssensor is connected = INT1 | |
digitalWrite(3,HIGH); //activate internal Pull-Up resistor | |
pinMode(8, INPUT); // Pin 8 -> Füllstand Min | |
digitalWrite(8, HIGH); //activate internal Pull-Up resistor | |
pinMode(9, INPUT); // Pin 9 -> Füllstand Min | |
digitalWrite(9, HIGH); //activate internal Pull-Up resistor | |
pinMode(LS_Pin, OUTPUT); // Pin 10 -> PWM Speaker | |
digitalWrite(LS_Pin, LOW); | |
pinMode(13, INPUT); // Pin 13 is input to which an switch (Runter) | |
digitalWrite(13, HIGH); //activate internal Pull-Up resistor | |
Serial.begin(9600); | |
Wire.begin(); | |
setTime(); //just use it once to set the right time then comment it out | |
setInterruptAlarm(); | |
setPortExpToOutput(); | |
setPortExpCh(7,false); | |
delay(200); | |
lcd.begin(16,2); | |
lcd.print(F("LCD bereit")); | |
beep(50,2000); | |
printLCD(lcdTEXT[_index]); | |
} | |
void loop() | |
{ | |
if(RTC.alarm(ALARM_1)) { | |
autModus=1; | |
} | |
if(autModus==1) { | |
Serial.println(F("autModus")); | |
lcd.clear(); | |
lcd.setCursor(0,0); | |
lcd.print(F("Automatikmodus")); | |
beep(50,500); | |
delay(200); | |
feuchtigkeit(); | |
giessen(); | |
autModus=0; | |
setInterruptAlarm(); | |
enterSleep(); | |
} | |
if(fehler == 0) | |
{ | |
if(millis() - sleepTime > 60000) { | |
enterSleep(); | |
} | |
if (Serial.available() > 0) { | |
// read the incoming byte: | |
_eingabe = Serial.read(); | |
delay(200); | |
} | |
//Entprellen BestButton | |
taster_val = digitalRead(BestButton); // Wert auslesen | |
if (taster_val != oldvalB) | |
{ | |
// normale Bearbeitung: losgelassen / gedrückt etc... | |
if(taster_val == false) { | |
Serial.println(F("Bestaetigen")); | |
_eingabe = OK; | |
} | |
oldvalB = taster_val; | |
delay(10); // 10 millisekunden warten, eine Änderung danach wird wieder eine echte sein. | |
} | |
//Entprellen RunterButton | |
taster_val = digitalRead(RunterButton); // Wert auslesen | |
if (taster_val != oldvalR) | |
{ | |
// normale Bearbeitung: losgelassen / gedrückt etc... | |
if(taster_val == false) { | |
Serial.println(F("RUNTER")); | |
_eingabe = RUNTER; | |
} | |
oldvalR = taster_val; | |
delay(10); // 10 millisekunden warten, eine Änderung danach wird wieder eine echte sein. | |
} | |
//Entprellen HochButton | |
taster_val = digitalRead(HochButton); // Wert auslesen | |
if (taster_val != oldvalH) | |
{ | |
// normale Bearbeitung: losgelassen / gedrückt etc... | |
if(taster_val == false) { | |
Serial.println(F("HOCH")); | |
_eingabe = HOCH; | |
} | |
oldvalH = taster_val; | |
delay(10); // 10 millisekunden warten, eine Änderung danach wird wieder eine echte sein. | |
} | |
switch(_eingabe){ | |
case HOCH: | |
if(_index == 0){ | |
enterSleep(); //Powerdown | |
}else if(_index == 1){ | |
_index--; | |
}else if(_index > 1){ | |
if(_index & 1){ | |
_index -= 2; | |
}else{ | |
_index -= 1; | |
lcd.noCursor(); | |
_cursor = 1; | |
} | |
} | |
break; | |
case RUNTER: | |
//Cursor zurücksetzen | |
lcd.noCursor(); | |
if(_index & 1){ | |
_cursor = 1; | |
} | |
if(_index == 0){ | |
_index++; | |
}else if(_index < (MAX_INDEX-1)){ | |
if(_index & 1){ | |
_index += 2; | |
}else{ | |
int i = 0; | |
if(_index == 2) {i=0;} //[Feld A] | |
if(_index == 4) {i=1;} //[Feld B] | |
if(_index == 6) {i=2;} //[Feld C] | |
if(_index == 8) {i=3;} //[Feld D] | |
if(_index == 10) {i=4;} //[Schlauch] | |
switch (_cursor) { | |
case 1: bewaesserungsArray[i]= minLiter; | |
break; | |
case 2: bewaesserungsArray[i]= maxLiter; | |
break; | |
case 3: bewaesserungsArray[i]= 0; | |
break; | |
} | |
_index += 1; | |
} | |
} | |
break; | |
case OK: | |
if(_index <(MAX_INDEX-1)){ | |
if(_index == 0){ | |
_index++; | |
}else{ | |
if(_index & 1){//"Feld X gießen?" -> Okay | |
_index++; | |
lcd.cursor(); | |
}else{ //"Feld X: min max aus" -> Okay | |
if(_cursor < 3){ | |
_cursor++; | |
}else{ | |
_cursor = 1; | |
} | |
switch (_cursor) { | |
case 1: lcd.setCursor(0, 1); //Cursor Min | |
break; | |
case 2: lcd.setCursor(6, 1); //Cursor Max | |
break; | |
case 3: lcd.setCursor(12, 1); //Cursor Aus | |
break; | |
} | |
} | |
} | |
}else if(_index == (MAX_INDEX-1)) { | |
Serial.println(F("giessen() aufruf")); | |
_eingabe = '\0'; | |
giessen(); //Giessen starten | |
enterSleep(); | |
} | |
break; | |
default: | |
if(_eingabe != '\0') { | |
Serial.println(F("Falschen Buchstaben erhalten!")); | |
lcd.clear(); | |
lcd.setCursor(0, 1); // bottom left | |
lcd.print(F("Falsche Eingabe!")); | |
delay(1000); | |
lcd.clear(); | |
printLCD(lcdTEXT[_index]); | |
} | |
} | |
/*LCD nach einer Minute ohne Eingabe deaktivieren!*/ | |
if(_eingabe != '\0') { | |
sleepTime = millis(); | |
_eingabe = '\0'; | |
if(alt_index != _index) { | |
alt_index = _index; | |
printLCD(lcdTEXT[_index]); | |
} | |
} | |
} | |
else if ( fehler == 1) | |
{ | |
Serial.println(F("LOOP ERROR = true")); | |
for(int i = 0; i<7 ; i++) { | |
setPortExpCh(i,true); | |
} | |
if ( RTC.alarm(ALARM_2) ) { //has Alarm2 triggered? resets the alarm flag in the RTC | |
Serial.println(F("Alarm2 has triggert!!!")); | |
setPortExpCh(SensorRelais, false); | |
delay(200); | |
lcd.clear(); | |
lcd.setCursor(0,0); | |
lcd.print(F("Fehler")); | |
lcd.setCursor(0,1); | |
lcd.print(F("aufgetreten!!!")); | |
beep(100,4000); | |
setPortExpCh(SensorRelais, true); | |
enterSleep(); | |
} | |
//Set Alarm2 for every minute | |
RTC.setAlarm(ALM2_EVERY_MINUTE, 1, 1, 1); | |
RTC.alarmInterrupt(ALARM_2, true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment