Skip to content

Instantly share code, notes, and snippets.

/Giessomat Secret

Created January 18, 2016 15:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/9dc7c6319224941b2e40 to your computer and use it in GitHub Desktop.
Save anonymous/9dc7c6319224941b2e40 to your computer and use it in GitHub Desktop.
//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