/* Schaltprogramm für den ATTiny 85. Der Empfänger wird vom Pin 2 gelesen, die Ausgänge sind auf Pin 0 und 1. Über den Pin 3/4 wird gelesen, ob der jeweilige Kanal im Impulsbetrieb oder Dauerbetrieb geschaltet werden soll. Impulsbetrieb: einmaliges Umlegen des Hebels schaltet ein bzw. aus Dauerbetrieb: das Relais ist solange geschlossen, wie der Hebel in die entsprechende Richtung gelegt wird. Progbrammablauf: Der Nullpunkt wird zunächst durch interpolation der ersten 10 Werte vom Empfänger festgestellt. Fehlerhafte Werte, also Werte ausserhalb von 900-2100 werden ignoriert. Werden mehr als 3 fehlerhafte Werte hintereinander gefunden, werden die Ausgänge auf null geschaltet. (Failsafe) Die Schaltschwelle für den normalbetrieb ist auf 250ms festgelegt. */ //const byte RC_INT = 0; // das ist INT 0 aber Pin 2!!!! const byte PIN_RC = 2; // das ist INT 0 aber Pin 2!!!! // Ausgänge const byte CAN_1 = 0; const byte CAN_2 = 1; // Eingänge const byte PIN_IMPULS_1 = 3; const byte PIN_IMPULS_2 = 4; // Maximale Anzahl der Fehler const byte MAX_ERRORS = 3; // Konstanten für die RC Erkennung const int MIN_RC_VALUE = 900; const int MAX_RC_VALUE = 2100; /* Konstante für die Erkennung des Schaltbefehls. Bei Kanal 1 wäre das Nullpunkt + SWITCH_STEP bei Kanal 2 entsprechend Nullpunkt - SWITCH_STEP */ const int SWITCH_STEP = 250; // letzter Wert vom Empfänger volatile unsigned long RcValue; // Anzahl der tolerierten Fehler byte error = MAX_ERRORS; // Größe des Pufferspeichers const byte stackSize = 10; // Ringspeicher mit den letzten 10 Werten vom Empfänger (Fehlerwerte werden direkt ausgeblendet.) int stack[stackSize]; // Laufvariable des Ringspeichers byte stackIndex = 0; // Impulseinstellung pro Kanal boolean impuls_1; boolean impuls_2; // Speicher für alte Werte pro Kanal boolean oldValue_can1 = 0; boolean oldValue_can2 = 0; // Zwischenspeicher int myRcValue; int maxSwitch; int minSwitch; // Nullpunktbestimmung boolean initNP; void setup() { // Kanäle auf Ausgang, und dann deaktivieren pinMode(CAN_1, OUTPUT); pinMode(CAN_2, OUTPUT); digitalWrite(CAN_1, LOW); digitalWrite(CAN_2, LOW); // Eingang für Impuls 1 pinMode(PIN_IMPULS_1, INPUT); digitalWrite(PIN_IMPULS_1, HIGH); // Eingang für Impuls 2 pinMode(PIN_IMPULS_2, INPUT); digitalWrite(PIN_IMPULS_2, HIGH); // Eingang für RC pinMode(PIN_RC, INPUT); digitalWrite(PIN_RC, HIGH); initNP = true; error = MAX_ERRORS; } void loop() { // Lesen der aktuellen Impuls-Einstellungen von den Kanälen impuls_1 = digitalRead(PIN_IMPULS_1) == 0; impuls_2 = digitalRead(PIN_IMPULS_2) == 0; // Aktuellen RC-Wert lesen RcValue = pulseIn(PIN_RC, HIGH, 100000); // Wert innerhalb der Toleranzgrenze if ((RcValue > MIN_RC_VALUE) && (RcValue < MAX_RC_VALUE)) { // Fehlerspeicher zurück setzen error = MAX_ERRORS; // Wert in den Ringpuffer schreiben stack[stackIndex%stackSize] = RcValue; stackIndex++; // den aktiven RC Wert holen myRcValue = getRcValue(); // Nullpunktsbestimmung ? if (initNP) { // Schon alle Werte gelesen? if (stackIndex == stackSize) { // die ersten 10 Werte dienen der Nullpunkt bestimmung int nullpoint = myRcValue; initNP = false; // Schaltschwellen definieren maxSwitch = nullpoint + SWITCH_STEP; minSwitch = nullpoint - SWITCH_STEP; } } else { // Kanal 1 auf Impuls? if (impuls_1) { doImpuls1(); } else { // Ausgang schalten. digitalWrite(CAN_1, myRcValue > maxSwitch); } // Kanal 2 auf Impuls? if (impuls_2) { doImpuls2(); } else { // direkt schalten digitalWrite(CAN_2, myRcValue < minSwitch); } // ein bisschen verzögern delay(100); } } else { // Fehlerfall if (error == 0) { // failsafe ... digitalWrite(CAN_1, LOW); digitalWrite(CAN_2, LOW); } else { // Fehler zählen error--; } } } // Impulsschalten für Kanal 1 void doImpuls1() { // Änderung am Empfängerwert ? boolean newValue = myRcValue > maxSwitch; if (oldValue_can1 != newValue) { // neuen Wert schreiben, aber nur an der positiven Flanke if (newValue) { digitalWrite(CAN_1, !digitalRead(CAN_1 )); } oldValue_can1 = newValue; } } // Impulsschalten für Kanal 2 void doImpuls2() { // Änderung am Empfängerwert boolean newValue = myRcValue < minSwitch; if (oldValue_can2 != newValue) { // Nur Schalten bei negativer Flanke if (newValue) { digitalWrite(CAN_2, !digitalRead(CAN_2 )); } oldValue_can2 = newValue; } } /* Bestimmung des durchschmittlichen RC-Wertes. Es werden zunächst alle Werte aufsummiert. Der höchste und der Niedrigste werden jedoch ignoriert. Dann wird der Mittelwert gebildet. */ int getRcValue() { int all = 0; int minValue = stack[0]; int maxValue = stack[0]; all = stack[0]; for (int i = 1; i < stackSize; i++) { int value = stack[i]; // Neuer Höchstwert ? if (value > maxValue) { // neuen speichern maxValue = value; } // Neuer Niedrigstwert? if (value < minValue) { // neuen speichern minValue = value; } all += value; } // Höchst und Niedrigstwert wieder abziehen all -= minValue; all -= maxValue; // Mittelwert bilden all = all / (stackSize - 2); return all; }