Unilein
Fachgebiet Rauchentwicklung
      
Beiträge: 818
Registriert seit: Apr 2014
Bewertung:
5
| |
Hey ho!
Das Frühjahr ist da und ich habe im vergangenen Jahr zusammen mit meiner Frau ein neues Gewächshaus gebaut. Es liegt also nah, dass auch das Thema "Bewässerung" wieder hoch blubbert.
2017 habe ich an dem Thema, obwohl damals angekündigt, nicht gearbeitet. Da gab es andere Dinge zu tun.
Aber jetzt ist 2019... Gerade mal 5 Jahre nach dem Projektstart in 2014.
Ich habe mein Modul von damals aus dem Schrank gepopelt und einem kurzen Test unterzogen. Die Elektronik funktioniert noch. Die zum Modul gehörigen Ventil, die das Wasser in die richtige Richtung lenken, habe ich auch noch. Ob die noch einwandfrei funktionieren, muss ich noch testen.
Das Programm auf dem Mikrocontroller (ATMega168) hat einen kleinen Fehler. Wenn Ventil 1 auslösen soll, löst auch Ventil 2 aus. Da ist wohl eine Variable falsch angesprochen oder so. Das Programm muss ich mir also auch noch einmal ansehen.
Das Programm ist in C mit dem Visual Studio von Atmel (heute Microchip) geschrieben. Ich habe schon damals den Controller ohne Arduino benutzt.
Hier mal der Programmcode von damals:
/*
* Gewächshausbewässerung
*
* Created: 01.07.2014 11:13:08
* Author: Martin de Hoogh
Versionierung:
07.06.2014, 0.1 alpha
- Festlegung der Ports und Pins
- Aufbau des Initialisierungsbilds
- Aufbau der Grundstruktur der Interruptroutine
- Aufbau der Grundstruktur der Hauptschleife
15.06.2014, 0.7 alpha
- ISR für PCINT0 (bislang ohne Funktion).
- Korrekte Zeitanzeige im Display
- Umsetzung der Ventil- und Pumpensteuerung (ohne Einstellmöglichkeit)
- Statusanzeige der Pumpe und der Ventile auf dem Hauptschirm
- Anzeige der Zeitdauern bis zur nächsten Öffnung für jedes Ventil
- Bitweise Ansteuerung des PORTC (Pumpe & Ventile)
27.06.2014, 0.9 alpha
- ISR für PCINT0 entfernt (nicht sinvoll nutzbar)
- ISR für Timer der Tasten an Pin 14,15 und 16 des ATMega
- Aufbau der Untermenüs für diverse Einstellungen
- Einstellen der Uhrzeit
- Speichern der eingestellten Uhrzeit im EEprom
29.06.2014, 1.0 alpha
- EEProm: Schreiben und lesen der Voreinstellungen
- Einstellen der Intervalle der Ventile
- Einstellen der Dauern der Ventilöffnung
06.07.14, 1.0 Beta
- Abschluß der Umstellung von Arduino auf C
- Korrektur des Timerinterrupts
- Abfrage, ob Laufdauer eines Ventil = 0, dann Ventil stillegen
- Standardwerte vorgeben, wenn Nichts im EEProm
23.07.14, 1.1 Beta
- ClkDiv/8 gesetzt und Programm für Betrieb auf 1MHz umgestellt
- Kontrastanpassung Display (zu hell)
- Behebung "Hyroglyphen" auf dem Display
- Anzeige der Temperatur und Feuchtigkeit reaktiviert
*/
#define F_CPU 1000000
#ifndef F_CPU
#define F_CPU 1000000 // processor clock frequency
#warning kein F_CPU definiert
#endif
// Includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <util/delay.h>
//#include "dht11.c" // Bibliothek für Temperatur- und Feuchtigkeitssensor
//True & False
#define TRUE (1 == 1)
#define FALSE (1 != 1)
// ===============================================
// Vorgaben für Intervalle & Dauern
// ===============================================
#define STD_INT_VALVE1 120 // Vorgabe für Ventil 1
#define STD_INT_VALVE2 121 // Vorgabe für Ventil 2
#define STD_INT_VALVE3 180 // Vorgabe für Ventil 3
#define STD_DUR_VALVE1 60 // Dauer für Ventil 1
#define STD_DUR_VALVE2 30 // Dauer für Ventil 2
#define STD_DUR_VALVE3 20 // Dauer für Ventil 3
// ===============================================
// Interrupteingang für INT0 (Pin 4 des ATMega328)
// ===============================================
#define PIN_INT0 PORTD2
// ===============================================
// EEProm-Adressen (Voreinstellungen)
// ===============================================
#define EP_HOUR 0x0100
#define EP_MINUTE 0x0101
#define EP_INTVALVE1 0x0102
#define EP_INTVALVE2 0x0104
#define EP_INTVALVE3 0x0106
#define EP_DURVALVE1 0x0108
#define EP_DURVALVE2 0x010A
#define EP_DURVALVE3 0x010C
// ===============================================
// Variable für die Tastenabfrage + Entprellung
// ===============================================
#define KEY_DDR DDRB
#define KEY_PORT PORTB
#define KEY_PIN PINB
#define KEY0 0 // Pin 14
#define KEY1 1 // Pin 15
#define KEY2 2 // Pin 16
#define ALL_KEYS (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
#define REPEAT_MASK 0 // (1<<KEY1 | 1<<KEY2) // repeat: key1, key2
#define REPEAT_START 50 // nach 500ms
#define REPEAT_NEXT 20 // alle 200ms
// ===============================================
// Makros für Bit-Operationen
// <a href="http://www.avrfreaks.net/index.php?name=pnphpbb2&file=viewtopic&t=37871" target="_blank" class="mycode_url">http://www.avrfreaks.net/index.php?name=...ic&t=37871</a>
// ===============================================
#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))
// ===============================================
// Datenport für DHT11
// Die Pin-Angaben beziehen sich auf den ATMega328P
// ===============================================
#define DHT11_DATA_PIN PORTD1 // Port D, Bit 1, = Pin 3
// ===============================================
// Datenport für Leistungstransistoren
// Die Pin-Angaben beziehen sich auf den ATMega328P
// ===============================================
// Pumpe = PORTC5 Pin 28 (Pumpe)
// Ventil 1 = PORTC4 Pin 27 (Ventil 1)
// Ventil 2 = PORTC3 Pin 26 (Ventil 2)
// Ventil 3 = PORTC2 Pin 25 (Ventil 3)
// Normale Variable
uint8_t hh,mm,ss; // Uhrzeit
uint8_t err = 0,t = 0,h = 0; // Fehlercode, Temperatur, Feuchtigkeit
uint8_t v = 1;
uint8_t valve[4];
uint8_t high,low;
uint8_t l = 0;
char temperature[4]; // Temperatur
char humidity[4]; // Feuchtigkeit
char tmpstr[12]; // Temporäre Zeichenkette
char time[] = "00:00:00\0"; // Zeit als String
//float temp, humi; // Daten vom Sensor
unsigned char temp, humi; // Daten vom Sensor
uint8_t ss_valve1,ss_valve2,ss_valve3; // Zähler für die Betriebsdauer der einzelnen Ventile
short flag_valve1=0; // Status Ventil 1
short flag_valve2=0; // Status Ventil 2
short flag_valve3=0; // Status Ventil 3
uint8_t MIN_HUM; // Luftfeuchtigkeit
uint8_t MAX_TEMP; // Temperatur
uint8_t DUR_VALVE1; // Dauer für Ventil 1
uint8_t DUR_VALVE2; // Dauer für Ventil 2
uint8_t DUR_VALVE3; // Dauer für Ventil 3
uint8_t INT_VALVE1; // Intervall für Ventil 1
uint8_t INT_VALVE2; // Intervall für Ventil 2
uint8_t INT_VALVE3; // Intervall für Ventil 3
//
volatile uint8_t key_state; // Tastenstatus entprellt und umgekehrt: bit = 1: key pressed
volatile uint8_t key_press; // Tastendruck registriert
volatile uint8_t key_rpt; // Taste lange gedrückt und Wiederholung
void setWelcomeScr(void);
void setTimeScr(void);
void setIntervalScr(void);
void setDurationScr(void);
void setMenuScr(void);
void setMainScr(void);
void crtClkStr(void);
void setup(void);
void setup(void) {
// Zunächst für alle nicht benötigten Ports die Pulldownwiderstände aktivieren
// um den Stromverbrauch zu reduzieren und um die Ports in einen definierten
// Status zu bringen.
// Das Ganze erfolgt über direkte Ansprache der Pins
// Steuerport für die Leistungsstufe initialisieren
// Die Pins 28,27,26 und 25 (Port C5-C3) auf Ausgang
// Die Pins 24 und 23 auf Eingang
DDRC = 0xB00111100;
PORTC = 0; // Alle Pins von Port C auf low
// Interrupteingang (INT0) auf Input stellen
DDRD = 0xB0000000; // Den ganzen Port erstmal auf Eingang
PORTD = 0; // Alle Pins auf Low
// Die 3 Pins mit den Tastern auf Input, die Pull-Ups einschalten
KEY_DDR &= ~ALL_KEYS; // Tastenports auf Input stellen
KEY_PORT |= ALL_KEYS; // die Pullups einschalten
// LCD-Display initialisieren und Bildschirm löschen
LCDInit(); //Init the LCD
LCDClear();
// Begrüssungsbildchen anzeigen
setWelcomeScr();
// Hauptschirm anzeigen
setMainScr();
// Interrupt-Serviceroutine einrichten
// Ereignisse an INT0 (Pin 4 des ATMega328)
// Bei Unterbrechung an INT0 wird "clock" aufgerufen
EIMSK |= (1<<INT0); // Auf INT0 lauschen
EICRA |= (1<<ISC01)|(1<<ISC00); // Bei steigender Flanke reagieren
// Den Timer für die Tastenabfrage einschalten
TCCR0B = (1<<CS02)|(1<<CS00); // divide by 1024
TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); // preload for 10ms
TIMSK0 |= 1<<TOIE0; // enable timer interrupt
// Intervalle der Ventile lesen
INT_VALVE1 = eeprom_read_byte (EP_INTVALVE1) + (256 * eeprom_read_byte ((EP_INTVALVE1 + 1))); ss_valve1 = INT_VALVE1; valve[1] = INT_VALVE1;
INT_VALVE2 = eeprom_read_byte (EP_INTVALVE2) + (256 * eeprom_read_byte ((EP_INTVALVE2 + 1))); ss_valve2 = INT_VALVE2; valve[2] = INT_VALVE2;
INT_VALVE3 = eeprom_read_byte (EP_INTVALVE3) + (256 * eeprom_read_byte ((EP_INTVALVE3 + 1))); ss_valve3 = INT_VALVE3; valve[3] = INT_VALVE3;
if (INT_VALVE1 == 255) { INT_VALVE1 = STD_INT_VALVE1; }
if (INT_VALVE2 == 255) { INT_VALVE2 = STD_INT_VALVE2; }
if (INT_VALVE3 == 255) { INT_VALVE3 = STD_INT_VALVE3; }
// Zeitdauern der Ventile lesen
DUR_VALVE1 = eeprom_read_byte (EP_DURVALVE1);
DUR_VALVE2 = eeprom_read_byte (EP_DURVALVE2);
DUR_VALVE3 = eeprom_read_byte (EP_DURVALVE3);
if (DUR_VALVE1 == 255) { DUR_VALVE1 = STD_DUR_VALVE1; }
if (DUR_VALVE2 == 255) { DUR_VALVE2 = STD_DUR_VALVE2; }
if (DUR_VALVE3 == 255) { DUR_VALVE3 = STD_DUR_VALVE3; }
// Letzte Uhrzeit aus dem EEProm lesen
hh=eeprom_read_byte ( EP_HOUR ); // Stunden aus dem EEprom lesen
mm=eeprom_read_byte ( EP_MINUTE ); // Minuten aus dem EEprom lesen
if (hh == 255) hh = 12;
if (mm == 255) mm = 0;
crtClkStr();
l=251;
// Interrupts zulassen
sei();
}
int main(void)
{
setup();
while(1)
{
char valvestr[5];
// Zeit anzeigen
crtClkStr();
gotoXY(3*5,0); LCDString(time);
// Temperatur und Feuchtigkeit auslesen und anzeigen
getDHT11();
gotoXY(20,1); LCDString(temperature);
gotoXY(65,1); LCDString(humidity);
// in etwa jede Sekunde die Restzeit für ein anderes Ventil anzeigen
l++;
if (l>20) {
if (v == 1) {
gotoXY(0,2); LCDString("V1: ");
gotoXY(28,2); LCDString(" Min");
gotoXY(28,2); itoa(valve[1],valvestr,10); LCDString(valvestr);
gotoXY(0,3); LCDString("D1: ");
gotoXY(28,3); LCDString(" Sek");
gotoXY(28,3); itoa(DUR_VALVE1,valvestr,10); LCDString(valvestr);
}
if (v == 2) {
gotoXY(0,2); LCDString("V2: ");
gotoXY(28,2); LCDString(" Min");
gotoXY(28,2); itoa(valve[2],valvestr,10); LCDString(valvestr);
gotoXY(0,3); LCDString("D2: ");
gotoXY(28,3); LCDString(" Sek");
gotoXY(28,3); itoa(DUR_VALVE2,valvestr,10); LCDString(valvestr);
}
if (v == 3) {
gotoXY(0,2); LCDString("V3: ");
gotoXY(28,2); LCDString(" Min");
gotoXY(28,2); itoa(valve[3],valvestr,10); LCDString(valvestr);
gotoXY(0,3); LCDString("D3: ");
gotoXY(28,3); LCDString(" Sek");
gotoXY(28,3); itoa(DUR_VALVE3,valvestr,10); LCDString(valvestr);
}
l =0;
v++;
if (v > 3) { v=1; }
}
// Auf dem Schirm die optischen Flags setzen
if (flag_valve1 == TRUE || flag_valve2 == TRUE || flag_valve3 == TRUE ) { gotoXY(20,5); LCDString("#"); }
else { gotoXY(20,5); LCDString("$"); }
if (flag_valve1 == TRUE) { gotoXY(35,5); LCDString("#"); }
else { gotoXY(35,5); LCDString("$"); }
if (flag_valve2 == TRUE) { gotoXY(49,5); LCDString("#"); }
else { gotoXY(49,5); LCDString("$"); }
if (flag_valve3 == TRUE) { gotoXY(63,5); LCDString("#"); }
else { gotoXY(63,5); LCDString("$"); }
// Hier zeigen wir temporär die aktuelle Rest-Betriebsdauer im Zyklus von Ventil 1 auf dem Display an
//itoa(bit_get(PORTB0,BIT(0)),valvestr,10);
//gotoXY(0,3);
//LCDString(valvestr);
// Die rote Taste abfragen und falls gedrückt, zum Menü verzweigen
if( get_key_press( 1<<KEY0 )) { setMenuScr(); }
}
}
// ===============================================
// Willkommensbildchen
// (Ein wenig Speicher verschwenden)
// ===============================================
void setWelcomeScr(void) {
gotoXY(0,0);
LCDString("============");
LCDString("| Waterboy |");
LCDString("|©2014 by|");
LCDString("| Martin |");
LCDString("============");
gotoXY(0,0);
_delay_ms(3000);
LCDClear();
}
// ===============================================
// Uhrzeit einstellen
// ===============================================
void setTimeScr(void) {
short y = 1;
char h[2],m[2];
LCDClear();
gotoXY(0,0);
LCDString("-<UHRZEIT >-");
gotoXY(0,1); LCDString(" Stunden: ");
gotoXY(0,2); LCDString(" Minuten: ");
gotoXY(0,3); LCDString(" Exit ");
gotoXY(14*5,1); itoa(hh,h,10); LCDString(h); // Stunden anzeigen
gotoXY(14*5,2); itoa(mm,m,10); LCDString(m); // Minuten anzeigen
PORTB = 0x0;
// Cursorsteuerung im Menü
// Der Zähler (y) dient nach Drücken der roten Taste als Entscheidungsvariable
// Stunden = Menüpunkt 1, Minuten = Menüpunkt 2
while (!get_key_press( 1<<KEY0 )) {
// rauf im Menü
if (get_key_press( 1<<KEY1)) {
gotoXY(0,y);
LCDString(" ");
y--;
if (y < 1) {
y=3;
}
}
// runter im Menü
if (get_key_press( 1<<KEY2)) {
gotoXY(0,y);
LCDString(" ");
y++;
if (y > 3) {
y=1;
}
}
gotoXY(0,y);
LCDString(">");
}
// Stunden oder Minuten markieren
gotoXY(12*5,y); LCDString(">");
// Einstellen der Uhrzeit
// Bestätigung wieder mit der roten Taste
if (y != 3) {
while (!get_key_press( 1<<KEY0 )) {
// rauf zählen
if (get_key_press( 1<<KEY1)) {
// Wenn es Stunden sein sollen
gotoXY(14*5,y); LCDString(" ");
if (y==1) {
hh++;
if (hh>23) { hh = 0; }
}
// Sonst Minuten
if (y==2) {
mm++;
if (mm>59) { mm=0; }
}
}
// runter zählen
if (get_key_press( 1<<KEY2)) {
// Wenn es Stunden sein sollen
gotoXY(14*5,y); LCDString(" ");
if (y==1) {
hh--;
if (hh<0) { hh = 23; }
}
// Sonst Minuten
if (y==2) {
mm--;
if (mm<0) { mm=59; }
}
}
gotoXY(14*5,y);
if (y==1) {
itoa(hh,h,10); LCDString(h); // Stunden anzeigen
}
if (y==2) {
itoa(mm,m,10); LCDString(m); // Minuten anzeigen
}
}
gotoXY(12*5,y); LCDString(" ");
}
// Uhrzeit sichern
eeprom_write_byte (EP_HOUR, hh); // Stunden ins EEProm
eeprom_write_byte (EP_MINUTE, mm); // Minuten ins EEProm
setMenuScr();
}
// ===============================================
// Bewässerungsintervalle einstellen
// ===============================================
void setIntervalScr(void) {
short y = 1;
char v1[3],v2[3],v3[3];
LCDClear();
gotoXY(0,0);
LCDString("-<INTERVAL>-");
LCDString(" Vnt 1: ");
LCDString(" Vnt 2: ");
LCDString(" Vnt 3: ");
LCDString(" Exit ");
gotoXY(11*5,1); itoa(INT_VALVE1,v1,10); LCDString(v1); // Stunden anzeigen
gotoXY(11*5,2); itoa(INT_VALVE2,v2,10); LCDString(v2); // Minuten anzeigen
gotoXY(11*5,3); itoa(INT_VALVE3,v3,10); LCDString(v3); // Minuten anzeigen
PORTB = 0x0;
// Cursorsteuerung im Menü
// Der Zähler (y) dient nach Drücken der roten Taste als Entscheidungsvariable
while (!get_key_press( 1<<KEY0 )) {
// rauf im Menü
if (get_key_press( 1<<KEY1)) {
gotoXY(0,y);
LCDString(" ");
y--;
if (y < 1) {
y=4;
}
}
// runter im Menü
if (get_key_press( 1<<KEY2)) {
gotoXY(0,y);
LCDString(" ");
y++;
if (y > 4) {
y=1;
}
}
gotoXY(0,y);
LCDString(">");
}
// Ventil markieren
gotoXY(9*5,y); LCDString(">");
// Einstellen der Intervalle der Ventile
// Bestätigung wieder mit der roten Taste
if (y != 4) {
while (!get_key_press( 1<<KEY0 )) {
// rauf zählen
if (get_key_press( 1<<KEY1)) {
// Intervall für Ventil 1
gotoXY(11*5,y); LCDString(" ");
if (y==1) {
INT_VALVE1++;
if (INT_VALVE1>1440) { INT_VALVE1 = 0; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 2
gotoXY(11*5,y); LCDString(" ");
if (y==2) {
INT_VALVE2++;
if (INT_VALVE2>1440) { INT_VALVE2 = 0; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 3
gotoXY(11*5,y); LCDString(" ");
if (y==3) {
INT_VALVE3++;
if (INT_VALVE3>1440) { INT_VALVE3 = 0; } // Intervalle größer 1440 vermeiden
}
}
// runter zählen
if (get_key_press( 1<<KEY2)) {
// Intervall für Ventil 1
gotoXY(11*5,y); LCDString(" ");
if (y==1) {
INT_VALVE1--;
if (INT_VALVE1<0) { INT_VALVE1 = 1440; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 2
gotoXY(11*5,y); LCDString(" ");
if (y==2) {
INT_VALVE2--;
if (INT_VALVE2<0) { INT_VALVE2 = 1440; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 3
gotoXY(11*5,y); LCDString(" ");
if (y==3) {
INT_VALVE3--;
if (INT_VALVE3<0) { INT_VALVE3 = 1440; } // Intervalle größer 1440 vermeiden
}
}
gotoXY(11*5,y);
if (y==1) {
itoa(INT_VALVE1,v1,10); LCDString(v1); // Ventil 1
}
if (y==2) {
itoa(INT_VALVE2,v2,10); LCDString(v2); // Ventil 2
}
if (y==3) {
itoa(INT_VALVE3,v3,10); LCDString(v3); // Ventil 3
}
}
gotoXY(9*5,y); LCDString(" ");
}
// Intervalle sichern
high = INT_VALVE1 / 256; low = INT_VALVE1 - high * 256;
eeprom_write_byte (EP_INTVALVE1, low); // Dauer Ventil 1 ins EEProm
eeprom_write_byte (EP_INTVALVE1 + 1, high); // Dauer Ventil 1 ins EEProm
high = INT_VALVE2 / 256; low = INT_VALVE2 - high * 256;
eeprom_write_byte (EP_INTVALVE2, low); // Dauer Ventil 2 ins EEProm
eeprom_write_byte (EP_INTVALVE2 + 1, high); // Dauer Ventil 2 ins EEProm
high = INT_VALVE3 / 256; low = INT_VALVE3 - high * 256;
eeprom_write_byte (EP_INTVALVE3, low); // Dauer Ventil 3 ins EEProm
eeprom_write_byte (EP_INTVALVE3 + 1, high); // Dauer Ventil 3 ins EEProm
setMenuScr();
}
// ===============================================
// Bewässerungsdauern einstellen
// ===============================================
void setDurationScr(void) {
char d1[3],d2[3],d3[3];
short y=1;
LCDClear();
gotoXY(0,0);
LCDString("-< DAUERN >-");
LCDString(" Vnt 1: ");
LCDString(" Vnt 2: ");
LCDString(" Vnt 3: ");
LCDString(" Exit ");
gotoXY(11*5,1); itoa(DUR_VALVE1,d1,10); LCDString(d1); // Stunden anzeigen
gotoXY(11*5,2); itoa(DUR_VALVE2,d2,10); LCDString(d2); // Minuten anzeigen
gotoXY(11*5,3); itoa(DUR_VALVE3,d3,10); LCDString(d3); // Minuten anzeigen
PORTB = 0x0;
// Cursorsteuerung im Menü
// Der Zähler (y) dient nach Drücken der roten Taste als Entscheidungsvariable
while (!get_key_press( 1<<KEY0 )) {
// rauf im Menü
if (get_key_press( 1<<KEY1)) {
gotoXY(0,y);
LCDString(" ");
y--;
if (y < 1) {
y=1;
}
}
// runter im Menü
if (get_key_press( 1<<KEY2)) {
gotoXY(0,y);
LCDString(" ");
y++;
if (y > 4) {
y=4;
}
}
gotoXY(0,y);
LCDString(">");
}
// Einstellen der Zeitdauern der Ventile
// Bestätigung wieder mit der roten Taste
if (y != 4) {
while (!get_key_press( 1<<KEY0 )) {
// rauf zählen
if (get_key_press( 1<<KEY1)) {
// Intervall für Ventil 1
gotoXY(11*5,y); LCDString(" ");
if (y==1) {
DUR_VALVE1++;
if (DUR_VALVE1>120) { DUR_VALVE1 = 0; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 2
gotoXY(11*5,y); LCDString(" ");
if (y==2) {
DUR_VALVE2++;
if (DUR_VALVE2>120) { DUR_VALVE2 = 0; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 3
gotoXY(11*5,y); LCDString(" ");
if (y==3) {
DUR_VALVE3++;
if (DUR_VALVE3>120) { DUR_VALVE3 = 0; } // Intervalle größer 1440 vermeiden
}
}
// runter zählen
if (get_key_press( 1<<KEY2)) {
// Intervall für Ventil 1
gotoXY(11*5,y); LCDString(" ");
if (y==1) {
DUR_VALVE1--;
if (DUR_VALVE1<0) { DUR_VALVE1 = 120; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 2
gotoXY(11*5,y); LCDString(" ");
if (y==2) {
DUR_VALVE2--;
if (DUR_VALVE2<0) { DUR_VALVE2 = 120; } // Intervalle größer 1440 vermeiden
}
// Intervall für Ventil 3
gotoXY(11*5,y); LCDString(" ");
if (y==3) {
DUR_VALVE3--;
if (DUR_VALVE3<0) { DUR_VALVE3 = 120; } // Intervalle größer 1440 vermeiden
}
}
gotoXY(11*5,y);
if (y==1) {
itoa(DUR_VALVE1,d1,10); LCDString(d1); // Ventil 1
}
if (y==2) {
itoa(DUR_VALVE2,d2,10); LCDString(d2); // Ventil 2
}
if (y==3) {
itoa(DUR_VALVE3,d3,10); LCDString(d3); // Ventil 3
}
}
gotoXY(9*5,y); LCDString(" ");
}
// Zeitdauern sichern
eeprom_write_byte (EP_DURVALVE1, DUR_VALVE1); // Dauer Ventil 1 ins EEProm
eeprom_write_byte (EP_DURVALVE2, DUR_VALVE2); // Dauer Ventil 2 ins EEProm
eeprom_write_byte (EP_DURVALVE3, DUR_VALVE2); // Dauer Ventil 3 ins EEProm
setMenuScr();
}
// ===============================================
// Anzeige des Hauptmenüs
// ===============================================
void setMenuScr(void) {
short y = 1;
LCDClear();
gotoXY(0,0);
LCDString("-< SETUP >-");
LCDString(" Uhrzeit ");
LCDString(" Intervalle ");
LCDString(" Dauern ");
LCDString(" Exit ");
gotoXY(0,0);
PORTB = 0x0;
// Cursorsteuerung im Menü
// Der Zähler (y) dient nach Drücken der roten Taste als Entscheidungsvariable
while (!get_key_press( 1<<KEY0 )) {
// rauf im Menü
if (get_key_press( 1<<KEY1)) {
gotoXY(0,y); LCDString(" ");
y--;
if (y < 1) {
y=4;
}
}
// runter im Menü
if (get_key_press( 1<<KEY2)) {
gotoXY(0,y); LCDString(" ");
y++;
if (y > 4) {
y=1;
}
}
gotoXY(0,y); LCDString(">");
}
// Jetzt wurde die rote Taste gedrückt --> Es geht weiter
switch (y) {
case 1: setTimeScr(); break;
case 2: setIntervalScr(); break;
case 3: setDurationScr(); break;
case 4: setMainScr();
}
}
// ===============================================
// Hauptschirm
// Anzeige Statusdaten
// ===============================================
void setMainScr(void) {
LCDClear();
gotoXY(2*5,0); LCDString("[");
gotoXY(75,0); LCDString("]");
gotoXY(0,1); LCDString("T:");
gotoXY(45,1); LCDString("H:");
gotoXY(0,4); LCDString("---P-1-2-3--");
gotoXY(0,5); LCDString("S: ");
}
// ===============================================
// Umwandlung der Zähler für Sekunden, Minuten und
// Stunden in einen String, der so angezeigt werden
// kann
// ===============================================
void crtClkStr(void) {
char h[]="00" ,m[]="00" ,s[]="00" ;
itoa(hh,h,10); // Stunden
itoa(mm,m,10); // Minuten
itoa(ss,s,10); // Sekunden
if (hh<10) { time[0] = '0'; time[1] = h[0]; }
else { time[0] = h[0]; time[1] = h[1]; }
if (mm<10) { time[3] = '0'; time[4] = m[0]; }
else { time[3] = m[0]; time[4] = m[1]; }
if (ss<10) { time[6] = '0'; time[7] = s[0]; }
else { time[6] = s[0]; time[7] = s[1]; }
}
// =============================================== =============================================== =============================================== ===============================================
// === Interrupts
// =============================================== =============================================== =============================================== ===============================================
// ===============================================
// Interrupt-Service Routine für INT0 (Pin 4)
// Hier wird die interne Uhr, die ihren Takt über
// den quarzgesteuerten Taktgeber am Pin 4 des
// ATMega328 bekommt, hochgezählt.
// Die Routine simuliert lediglich eine Uhr und
// zählt die Intervalle für die einzelnen Ventile
// runter
// ===============================================
ISR(INT0_vect) {
//void clock(void) {
//char h[]="00" ,m[]="00" ,s[]="00" ;
PORTD |= (0 << PIN_INT0); // wieder auf Low
// Ventil 1 ist offen, jetzt solange warten, bis maximale Zeit erreicht, dann wieder schließen
if (flag_valve1 == TRUE) {
ss_valve1--;
if (ss_valve1 < 1) {
flag_valve1 = FALSE;
ss_valve1 = DUR_VALVE1;
bit_clear(PORTC,BIT(5));
bit_clear(PORTC,BIT(4));
}
}
// Ventil 2 ist offen, jetzt solange warten, bis maximale Zeit erreicht, dann wieder schließen
if (flag_valve2 == TRUE) {
ss_valve2--;
if (ss_valve2 < 1) {
flag_valve2 = FALSE;
ss_valve2 = DUR_VALVE2;
bit_clear(PORTC,BIT(5));
bit_clear(PORTC,BIT(3));
}
}
// Ventil 3 ist offen, jetzt solange warten, bis maximale Zeit erreicht, dann wieder schließen
if (flag_valve3 == 1) {
ss_valve3--;
if (ss_valve3 < 1) {
flag_valve3 = FALSE;
ss_valve3 = DUR_VALVE3;
bit_clear(PORTC,BIT(5));
bit_clear(PORTC,BIT(2));
}
}
ss++; // Sekunden rauf
// 60 Sekunden sind um...
if (ss > 59) {
ss = 0;
mm++; // Minuten rauf
// Die Intervalle für die Ventile herunterzählen
// aber nur, wenn die Laufdauer für ein Ventil nicht 0 ist
if ( DUR_VALVE1 != 0) { valve[1]--; }
if ( DUR_VALVE2 != 0) { valve[2]--; }
if ( DUR_VALVE3 != 0) { valve[3]--; }
// Für Ventil 1 ist die Zeit gekommen, bitte einschalten
if (valve[1] < 1) {
valve[1] = INT_VALVE1;
bit_set(PORTC,BIT(5));
bit_set(PORTC,BIT(4));
flag_valve1 = TRUE; // Flag für Zähler Ventil 1 + Pumpe
}
// Für Ventil 2 ist die Zeit gekommen, bitte einschalten
if (valve[2] < 1) {
valve[2] = INT_VALVE2;
bit_set(PORTC,BIT(5));
bit_set(PORTC,BIT(3));
flag_valve2 = TRUE; // Flag für Zähler Ventil 2 + Pumpe
}
// Für Ventil 3 ist die Zeit gekommen, bitte einschalten
if (valve[3] < 1) {
valve[3] = INT_VALVE3;
bit_set(PORTC,BIT(5));
bit_set(PORTC,BIT(2));
flag_valve3 = TRUE; // Flag für Zähler Ventil 3 + Pumpe
}
}
if (mm > 59) {
mm = 0;
hh++;
}
if (hh > 23) {
hh = 0;
}
}
// ===============================================
// Interrupt-Service Routine für TIMER1
// Es werden die Pins 14,15 und 16 abgefragt
// Atmega328 Port B (0-2)
//
// Die Routine fragt den Status der Pins ab und
// gibt den Status zurück
//
// Die Tasten werden bei der Abfrage entprellt
//
// Die Basis hierzu hat Peter Dannegger entwickelt
// ===============================================
ISR( TIMER0_OVF_vect ) // alle 10 ms
{
static uint8_t ct0, ct1, rpt;
uint8_t i;
TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); // preload for 10ms
i = key_state ^ ~KEY_PIN; // Tastenstatus geändert? ?
ct0 = ~( ct0 & i ); // reset oder zählen ct0
ct1 = ct0 ^ (ct1 & i); // reset oder zählen ct1
i &= ct0 & ct1; // Zählen bis zum Überlauf ?
key_state ^= i; // Dann den Prellstatus ändern
key_press |= key_state & i; // 0->1: Tastendruck registrieren
if( (key_state & REPEAT_MASK) == 0 ) // Wiederholfunktion prüfen
rpt = REPEAT_START; // Pause beginnen
if( --rpt == 0 ){
rpt = REPEAT_NEXT; // Pause wiederholen
key_rpt |= key_state & REPEAT_MASK;
}
}
// ===============================================
// Prüfen ob eine Taste gedrückt wurde. Jeder Tastendruck
// wird nur EINMAL gemeldet.
// ===============================================
int get_key_press( int key_mask )
{
cli(); // read and clear atomic !
key_mask &= key_press; // read key(s)
key_press ^= key_mask; // clear key(s)
sei();
return key_mask;
}
// ===============================================
// Prüfen ob eine Taste solange gedrückt wurde, dass
// die Tastenwiederholfunktion aktiviert wird
// Es wird sozusagen simuliert, dass der Benutzer
// die Taste mehrfach drückt und wieder loslässt.
// ===============================================
uint8_t get_key_rpt( uint8_t key_mask )
{
cli(); // read and clear atomic !
key_mask &= key_rpt; // read key(s)
key_rpt ^= key_mask; // clear key(s)
sei();
return key_mask;
}
// ===============================================
// Prüfen ob eine Taste gerade JETZT gedrückt wurde.
// Jeder Tastendruck wird nur EINMAL gemeldet.
// ===============================================
uint8_t get_key_state( uint8_t key_mask )
{
key_mask &= key_state;
return key_mask;
}
// ===============================================
// Prüfen ob eine Taste KURZ gedrückt wurde.
// ===============================================
uint8_t get_key_short( uint8_t key_mask )
{
cli(); // Interrupt unterdrücken
return get_key_press( ~key_state & key_mask );
}
// ===============================================
// Prüfen ob eine Taste LANG gedrückt wurde.
// ===============================================
uint8_t get_key_long( uint8_t key_mask )
{
return get_key_press( get_key_rpt( key_mask ));
}
// =============================================== =============================================== =============================================== ===============================================
// =============================================== =============================================== =============================================== ===============================================
// ===============================================
// Werte des DHT11-Sensors lesen
// ===============================================
void getDHT11() {
//if (
dht11(&humi, &temp); // == 0)
{
t = &temp;
h = &humi;
itoa(t,temperature,10);
itoa(h,humidity,10);
}
}
Zu der reinen Steuerung der Bewässerung hatte ich damals noch einen Temperatur- und Feuchtigkeitssensor vom Typ DHT111 eingebaut. Außerdem ein LCD-Display, auf dem Zeiten, Intervalle und Bewässerungsdauer angezeigt werden.
Ich würde sagen: Viel Spaß beim lesen. Ich bin für weitere Anregungen offen. Sofern ich die Schaltung noch anpassen sollte, werde ich sie dann aber auch als Platine bestellen und ordentlich aufbauen.
Grüße
Uni
(Dieser Beitrag wurde zuletzt bearbeitet: 13.04.2019, 17:41 von Unilein.)
|