Ein freundliches Hallo an Alle
Ich habe heute ein Projekt fertiggestellt, was gut zu laufen scheint. Aber gerade auf lange Sicht bin ich mir bei solchen Dingen meist unsicher, daher wäre es mir recht, wenn Code und Schaltplan nicht nur von meinen Augen begutachtet sind.
Zum Projekt: Mein Vater hat einen Hühnerstall, und die Klappe hängt an einem Garagentoröffner, dessen Elektronik versagt hat. Daher sollte ich die Elektronik ersetzen.
Funktionen: Der Schlitten betätigt 2 Endlagenschalter, so ist die Position i.d.R. bekannt. Eine RG-LED zeigt an, ob die Klappe oben (Grün), unten (rot), in Bewegung (gelb) ist, oder ob ein Fehler vorliegt (rot blinkend). Eine Zeitschaltuhr wird 2x am Tag für eine Minute aktiviert. Einerseits versorgt sie den Motor mit Strom, andererseits gibt sie über Spannungsteiler ein Signal an den Arduino, welcher dann die Klappe hoch- oder runterfährt.
Hier der Code:
//Stand: 21.06.2017
//Programm zur Steuerung einer Klappe am Hühnerstall
//geschrieben von Carsten Lehmann (DerLehmi)
#include <Bounce2.h>
//#define DEBUG
#define ledG 5 //Grüne LED
#define ledR 6 //Rote LED
#define tasterO 11 //Endpositionstaster Oben
#define tasterU 12 //Endpositionstaster Unten
#define relaisA 4 //Klappe runterfahren
#define relaisB 3 //Klappe hochfahren
#define eingang A3 //Eingang für Startsignal
bool flanke=false; //wenn Eingang neu erkannt
bool beheben=false; //wenn Taster zum Beheben der Fehlerposition betätigt
Bounce TasterO=Bounce();
Bounce TasterU=Bounce();
int state=0; //Statusvariable (0=Wartestatus; 1=Betriebsmodus; 2=Blockiermodus; 3=Fehlermodus)
unsigned long actual_Milliseconds=0;
unsigned long zeitspeicher_notAus=0;
unsigned long zeitspeicher_signal=4294787295;
void setup() {
#ifdef DEBUG
Serial.begin(9600);
while(!Serial);
Serial.println("Start: Hühnerklappe");
#endif
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
pinMode(ledG, OUTPUT);
pinMode(ledR, OUTPUT);
pinMode(relaisA, INPUT_PULLUP); //verhindert ungewollte Initialisierung auf LOW (HIGH-aktiv)
pinMode(relaisA, OUTPUT);
pinMode(relaisB, INPUT_PULLUP); //verhindert ungewollte Initialisierung auf LOW (HIGH-aktiv)
pinMode(relaisB, OUTPUT);
pinMode(tasterO, INPUT_PULLUP);
TasterO.attach(tasterO);
TasterO.interval(15);
pinMode(tasterU, INPUT_PULLUP);
TasterU.attach(tasterU);
TasterU.interval(15);
pinMode(eingang, INPUT);
TasterO.update();
TasterU.update();
fehlerTest();
if(state!=3){ //Anzeige der Klappenposition
if(TasterO.read()){
digitalWrite(ledR, HIGH); //Klappe unten (Rot)
#ifdef DEBUG
Serial.println("Klappe ist unten");
#endif
}else{
digitalWrite(ledG, HIGH); //Klappe oben (Grün)
#ifdef DEBUG
Serial.println("Klappe ist oben");
#endif
}
emptyCap();
}
#ifdef DEBUG
Serial.println("Ende des Setups");
#endif
}
void loop() {
actual_Milliseconds=millis();
TasterO.update();
TasterU.update();
if(state==0){ //Wartestatus
stopMotor();
fehlerTest();
if(actual_Milliseconds-zeitspeicher_signal>30000){ //im Wartestatus Abfrage aller 30 Sekunden
if(digitalRead(eingang)){
state=1; //Betriebsstatus setzen
#ifdef DEBUG
Serial.println("Status --> 1");
#endif
flanke=true;
}
zeitspeicher_signal=actual_Milliseconds;
}
}else if(state==1){ //Betriebsstatus
if(flanke){ //wenn Startvorgang
if(!TasterO.read()){
digitalWrite(relaisA, LOW); //Klappe runterfahren
digitalWrite(ledR, HIGH); //in Betrieb: LED Gelb
#ifdef DEBUG
Serial.println("Klappe wird heruntergefahren");
#endif
}else{
digitalWrite(relaisB, LOW); //Klappe hochfahren
digitalWrite(ledG, HIGH); //in Betrieb: LED Gelb
#ifdef DEBUG
Serial.println("Klappe wird hochgefahren");
#endif
}
flanke=false; //Schlitten in Betrieb
zeitspeicher_notAus=actual_Milliseconds;
}else{ //wenn Motor läuft
if(!digitalRead(relaisA)){
if(TasterU.fell()){ //Zielposition (unten) erreicht
state=2;
#ifdef DEBUG
Serial.println("Status --> 2 (Unten erreicht)");
#endif
digitalWrite(ledG, LOW);
}
}else{
if(TasterO.fell()){ //Zielposition (oben) erreicht
state=2;
#ifdef DEBUG
Serial.println("Status --> 2 (Oben erreicht)");
#endif
digitalWrite(ledR, LOW);
}
}
if((actual_Milliseconds-zeitspeicher_notAus)>6000){ //wenn Schlitten blockiert
state=3;
#ifdef DEBUG
Serial.println("Status --> 3 (Schlitten blockiert)");
#endif
}
}
}else if(state==2){ //Blockiermodus (keine Flankenerkennung)
stopMotor();
fehlerTest();
if(actual_Milliseconds-zeitspeicher_signal>80000){ //wenn Blockierzeit vorbei
emptyCap();
state=0;
#ifdef DEBUG
Serial.println("Status --> 0");
#endif
}
}else if(state==3){ //Fehlermodus
if(TasterO.fell() || TasterU.fell()){
beheben=true;
}
if(!beheben){
stopMotor();
if(digitalRead(ledG))
digitalWrite(ledG, LOW);
if((actual_Milliseconds-zeitspeicher_notAus)>300){ //LED blinkt rot
digitalWrite(ledR, !digitalRead(ledR));
zeitspeicher_notAus=actual_Milliseconds;
}
}else if(TasterO.fell() && digitalRead(relaisB) && digitalRead(relaisA)){ //Zielposition oben anfahren
digitalWrite(relaisB, LOW);
#ifdef DEBUG
Serial.println("Oben wird angefahren");
#endif
}else if(TasterU.fell() && digitalRead(relaisA) && digitalRead(relaisB)){ //Zielposition unten anfahren
digitalWrite(relaisA, LOW);
#ifdef DEBUG
Serial.println("Unten wird angefahren");
#endif
}else if(TasterO.fell() && !digitalRead(relaisB)){ //Zielposition oben erreicht
digitalWrite(relaisB, HIGH);
state=0;
beheben=false;
if(digitalRead(ledR))
digitalWrite(ledR, LOW);
digitalWrite(ledG, HIGH);
delay(5000); //Wartezeit zum Abklemmen der Versorgung für Motor
emptyCap();
#ifdef DEBUG
Serial.println("Oben erreicht");
#endif
}else if(TasterU.fell() && !digitalRead(relaisA)){ //Zielposition unten erreicht
digitalWrite(relaisA, HIGH);
state=0;
beheben=false;
digitalWrite(ledR, HIGH);
delay(5000); //Wartezeit zum Abklemmen der Versorgung für Motor
emptyCap();
#ifdef DEBUG
Serial.println("Unten erreicht");
#endif
}
}
}
void fehlerTest(){
if(TasterO.read()==TasterU.read()){ //Test, ob Schlitten eindeutige Lage hat
state=3; //Fehlerstatus
#ifdef DEBUG
Serial.println("Status --> 3 (Fehler gefunden)");
#endif
zeitspeicher_notAus=actual_Milliseconds;
}
}
void stopMotor(){ //Motor stoppen
if(!digitalRead(relaisA)){
digitalWrite(relaisA, HIGH);
}
if(!digitalRead(relaisB)){
digitalWrite(relaisB, HIGH);
}
}
void emptyCap(){ //kurzzeitiges Ansteuern des Motors, um Kondensator zu entladen
digitalWrite(relaisA, HIGH);
digitalWrite(relaisB, LOW);
delay(200);
digitalWrite(relaisB, HIGH);
#ifdef DEBUG
Serial.println("Kondensator entladen");
#endif
}
Und hier der Schaltplan: