/* ******************************************************************* Autor: Beck Martin (mit Vorlagen von Tobias Schneider) Taktfrequenz: 8 MHz Chip: Atmel atMega 8 Datum: August 2015 Bezeichnung: 2 Kanal 20 Funktionen Multiswitch - 2k20fms Hintergund: Grund für dieses Prgramm war die fehlende kostenguenstige Moeglichkeit mir nur 2 Schaltknueppeln (jeweils 3 Wege Schalter) die 20 Funktionen meines meines Schleppschiffs = Rettungsschiffs zu steuern. Funktionsbeschreibung: Wenn ein Schalter von 0 = Neutralstellung in eine Endlage = 100 oder -100 gebracht wird, wird dies als Schaltimpuls gewertet und dabei entweder als "lang" oder "kurz" gewertet. Voreingestellt ist hier 500 ms = 0,5 Sekunden, was eine vernünftige Schaltfrequenz sein dürfte. Beispiel: - Schalter vom RC Sender auf 100 % für eine kurze Zeit von 0,35 s schaltet Ausgang 1 - Schalter vom RC Sender auf -100 % für eine kurze Zeit von 0,35 s schaltet Ausgang 2 - Schalter vom RC Sender auf 100 % für eine lange Zeit von >0,35 s schaltet Ausgang 3 - Schalter vom RC Sender auf -100 % für eine lange Zeit von >0,35 s schaltet Ausgang 4 Der Zustand bleibt bestehen (Memory) bis erneut der entsprechende Ausgang geschalten wurde. Wahlweise kann der Ausgang auch "tastend" sein, was jedoch nur bei den "direkten" Schaltzustaenden ohne Kombination wirklich sinnvoll ist. Ausgelegt ist die Schaltung für 2 Schalter mit je 2 Tastfunktionen (oben / unten) Sie mueßte jedoch auch mit Schaltern funktionieren, wurde jedoch nicht getestet. Mein Test: Graupner MX-20 (Schalterumbau) mit 6 Kanalempfaenger Futaba FX-30 (Schalterumbau) mit 12 Kanalempfaenger ******************************************************************* Wichtiger Hinweis zum Schluß: __ -- Die vorliegende Software ist für private Zwecke frei verwendbar, -- __ __ -- jedoch ist eine kommerzielle Verwendung, egal welcher Art nicht gestattet. -- __ ******************************************************************* +------------+ (PCINT14/RESET) PC6 -| 1 28 |- PC5 (ADC5/SCL/PCINT13) (PCINT16/RXD) PD0 -| 2 27 |- PC4 (ADC4/SDA/PCINT12) (PCINT17/TXD) PD1 -| 3 26 |- PC3 (ADC3/PCINT11) PCINT18/INT0) PD2 -| 4 25 |- PC2 (ADC2/PCINT10) (PCINT19/OC2B/INT1) PD3 -| 5 24 |- PC1 (ADC1/PCINT9) (PCINT20/XCK/T0) PD4 -| 6 23 |- PC0 (ADC0/PCINT8) VCC -| 7 22 |- GND GND -| 8 21 |- AREF (PCINT6/XTAL1/TOSC1) PB6 -| 9 20 |- AVCC (PCINT7/XTAL2/TOSC2) PB7 -| 10 19 |- PB5 (SCK/PCINT5) (PCINT21/OC0B/T1) PD5 -| 11 18 |- PB4 (MISO/PCINT4) (PCIN T22/OC0A/AIN0) PD6 -| 12 17 |- PB3 (MOSI/OC2A/PCINT3) (PCINT23/AIN1) PD7 -| 13 16 |- PB2 (SS/OC1B/PCINT2) (PCINT0/CLKO/ICP1) PB0 -| 14 15 |- PB1 (OC1A/PCINT1) +------------+ Verwendung in diesem Programm: +------------+ n.b.--- <- PC6 -| 1 28 |- PC5 -> A_6 A_7 <- PD0 -| 2 27 |- PC4 -> A_5 A_8 <- PD1 -| 3 26 |- PC3 -> A_4 * E_1 -> PD2 -| 4 25 |- PC2 -> A_3 * E_2 -> PD3 -| 5 24 |- PC1 -> A_2 A_9 <- PD4 -| 6 23 |- PC0 -> A_1 VCC -| 7 22 |- GND GND -| 8 21 |- AREF A_19 <- PB6 -| 9 20 |- AVCC A_20 <- PB7 -| 10 19 |- PB5 -> A_18 A_10 <- PD5 -| 11 18 |- PB4 -> A_17 A_11 <- PD6 -| 12 17 |- PB3 -> A_16 A_12 <- PD7 -| 13 16 |- PB2 -> A_15 A_13 <- PB0 -| 14 15 |- PB1 -> A_14 +------------+ ******************************************************************* */ // ******************************************************************* // Hardwarespezifische Parameter - nur bei Bedarf und bewußt aendern!! - Bei Veraenderungen wird // das Programm ggf. in dieser Form unbrauchbar und muß abgeaendert werden!! // ******************************************************************* // // allgemeine und Chip spezifische Parameter // // ******************************************************************* // --- Hardware definieren #define F_CPU 8000000 // 8000000UL // --- notwendige Hilfsdateien einbeinden #include #include #include #include // ******************************************************************* // // selbst zu definierende Eingaenge, Ausgaenge und Parameter // // ******************************************************************* // --- Die Eingaenge --- selbst zu definieren #define TASTERPORT PINC #define TASTERBIT PINC1 #define E_1_Bit PD2 // Eingangssignal 1 vom Empfaenger (Kanal 4) #define E_1_Pin PIND // PIN des Eingangssignals 1 vom Empfaenger (Kanal 4) #define E_1_Port PORTD // Port des Eingangssignals 1 vom Empfaenger (Kanal 4) #define E_2_Bit PD3 // Eingangssignal 2 vom Empfaenger (Kanal 5) #define E_2_Pin PIND // PIN des Eingangssignals 2 vom Empfaenger (Kanal 5) #define E_2_Port PORTD // Port des Eingangssignals 2 vom Empfaenger (Kanal 5) #define E_DirReg DDRD // Richtungsregister des Eingangssignals 1 und 2 vom Empfaenger (Kanal 4 und 5) // --- Die Ausgaenge --- selbst zu definieren -- ggf. im Hauptprogramm Ports anpassen #define A_1 PC0 // Vor Rueck auf Rechts Links -> umschalten (an / aus) #define A_2 PC1 // Schraube auf Geblaese -> umschalten (an / aus) #define A_3 PC2 // Rettungsmaßnahme einholen -> ein / aus = automatischer Stop #define A_4 PC3 // Rettungsmaßnahme 1 Abschuß -> ein / aus = automatischer Stop #define A_5 PC4 // Rettungsmaßnahme 2 Abschuß -> ein / aus = automatischer Stop #define A_6 PC5 // Licht innen (unten) -> an /aus // #define A_21 PC6 // -- nicht belegt da Reset #define A_7 PD0 // Rauchgenerator -> an / aus - oder mit Fuellstandssensor bei "an") #define A_8 PD1 // Ankerwinde -> auf / ab / Freier Fall (= Tastsignal auf Tiny übergeben) #define A_9 PD4 // Sound Voegel / Geraeusche -> an / aus #define A_10 PD5 // Fahrtmusik von MP3 Spieler -> an = Tastsignal an Tiny - Fahrtmusik / Diverse Musik / aus #define A_11 PD6 // Nebelhorn - Sound (PIN = "tastend") MP3 Spieler -> an / aus #define A_12 PD7 // Licht Abschleppbereich (Heck) und Arbeitsbereich (Bug) -> an / aus #define A_13 PB0 // Positionslichter -> an / aus ("an" mit Helligkeitssensor) #define A_14 PB1 // Licht Suchscheinwerfer -> an / aus #define A_15 PB2 // Licht Steuerhaus -> an / aus #define A_16 PB3 // Licht Steuerkonsole -> an / aus #define A_17 PB4 // Querstahlruder -> an = Motor Querstahlruder Bug + Heck => Loeschmonitor A19 und A20 aus! / aus -> A19 mögl. ein #define A_18 PB5 // Loeschwasserpumpe -> an = Servo 1 = Monitor 1 drehen + Servo 2 = Monitor 2 drehen - nur wenn A18 und A20 aus! / aus #define A_19 PB6 // Servo fuer Rettungsmaßnahme rechts / links -> nur wenn A18 aus und A19 aus !! #define A_20 PB7 // Kontroll LED für Microkontroller IC Feedback automatisch und Ton Feedback für Steuersignal (mit Jumper Signal ein / aus) #define A_1_6_Port PORTC // Port des Ausgangssignals 1 bis 6 #define A_7_12_Port PORTD // Port des Ausgangssignals 7 bis 12 #define A_13_20_Port PORTB // Port des Ausgangssignals 16 bis 20 // --- Parameter --- selbst zu definieren volatile unsigned int schaltdauer = 350; // x10 ms; // Zeit bis zum Wechsel des Schaltzustandes in ms für "langen Schaltzustand" // Wert als vielfaches von 10 // ******************************************************************* // // diverse sonstige Variablen im Programm // // ******************************************************************* volatile unsigned int impuls_E1= 0; // Impuls Signal Eingang 1 volatile unsigned int impuls_E2= 0; // Impuls Signal Eingang 2 volatile unsigned int signal_1 = 0; // Impulslänge Signal Eingang 1 volatile unsigned int signal_2 = 0; // Impulslänge Signal Eingang 2 volatile unsigned int schaltzeit_cnt = 0; // Zaehler für Schaltzeit volatile unsigned int schaltzeit_cnt1 = 0; // Zaehler für Schaltzeit E1 volatile unsigned int schaltzeit_cnt2 = 0; // Zaehler für Schaltzeit E1 volatile unsigned char aus_E1 = 0; // Aus Signal E1 kommend volatile unsigned char aus_E2 = 0; // Aus Signal E2 kommend volatile unsigned char schaltzustand = 0; // Allgemeiner Schaltzustand volatile unsigned char schaltzustand_1 = 0; // Schaltzusand E1 / E2 (je max. 255 Stück!!) volatile unsigned char schaltzustand_2 = 0; // volatile unsigned int schaltzustand_ausgabe = 0; // Ausgabe des Schaltzustandes für Hauptprogramm volatile unsigned int schaltzyklus_cnt = 0; // Zaehler für komplette Schaltzyklen volatile unsigned int schalt_cnt_1_o = 0; // Zaehler fuer Schaltzustaende E1_oben volatile unsigned int schalt_cnt_1_u = 0; // Zaehler fuer Schaltzustaende E1_unten volatile unsigned int schalt_cnt_2_o = 0; // Zaehler fuer Schaltzustaende E2_oben volatile unsigned int schalt_cnt_2_u = 0; // Zaehler fuer Schaltzustaende E2_unten volatile unsigned int schaltzeit = 0; volatile unsigned int mid_1 = 0; // signal_mittelwert_1 / 2 volatile unsigned int mid_2 = 0; volatile unsigned char i1; // Zählvariable Signal 1 / 2 volatile unsigned char i2; volatile unsigned char wechselabwarten_1 = 0; // warten auf mittelstellung_1 / 2 volatile unsigned char wechselabwarten_2 = 0; volatile unsigned char t1 = 0; // Merker fuer Schalter als TipTaster 1 - 10 volatile unsigned char t2 = 0; volatile unsigned char t3 = 0; volatile unsigned char t4 = 0; volatile unsigned char t5 = 0; volatile unsigned char t6 = 0; volatile unsigned char t7 = 0; volatile unsigned char t8 = 0; volatile unsigned char t9 = 0; volatile unsigned char t10 = 0; volatile unsigned int t_zaehler = 0; // Zaehler fuer TipTaster Merker volatile unsigned char ton = 0; // Merker fuer Signalhorn / Warnton volatile unsigned int ton_zaehler = 0; // Zaehler fuer Signalhorn / Warnton volatile unsigned char sound = 0; volatile unsigned int soundpresc = 0; volatile unsigned char watch = 0; volatile unsigned int fail = 0; // ******************************************************************* // // Unterprogramme (void), Timer und Interrupts // // ******************************************************************* // Interrupts ISR (TIMER1_COMPA_vect) // 100.000 Hz = 10.000 mySekundy { if(PIND & (1< an E1 = Kanal 1 empfangen { impuls_E1++; } else if(impuls_E1!=0) { if(impuls_E1>255) signal_1=0; else signal_1=impuls_E1; impuls_E1=0; } if(PIND & (1< an E2 = Kanal 2 empfangen { impuls_E2++; } else if(impuls_E2!=0) { if(impuls_E2>255) signal_2=0; else signal_2=impuls_E2; impuls_E2=0; } watch = 1; //Signal fuer Hauptschlaeife, den (Wach)Hund zu fuettern fail++; //Zeitramen fuer Plausibilitaetstest erhoehen // --- noch implementieren } ISR (TIMER2_OVF_vect) //Alle 10 ms { schaltzeit_cnt++; TCNT2 = 178; // = 0b10110010 = 0xB2 // TCNT2 = 0x06; // = 6 OCR2 = 77 ; // = 0b01001101 = 0x4D } // ******************************************************************* // Timer void startTimer1() // alle 10 uSec = 100.000 Hz { TCNT1 = 0b1111111111110110; TCCR1B |= (1 << CS11) | (1 << WGM12); // | (1 << CS10) //Timer1 CTC /8 OCR1B = 0x0009; TIMSK |= (1 << OCIE1A) | (1< stopt Timer1 } void stopTimer2() { TCCR2 = 0b00000000; // Prescaler auf 0 -> stopt Timer2 } // ******************************************************************* // Unterprogramme void reset_zaehler () { schalt_cnt_1_u = 0; schalt_cnt_1_o = 0; schalt_cnt_2_u = 0; schalt_cnt_2_o = 0; schaltzustand = 0; schaltzustand_1 = 0; schaltzustand_2 = 0; schaltzeit_cnt = 0; schaltzeit_cnt1 = 0; schaltzeit_cnt2 = 0; } // ******************************************************************* // // Hauptprogramm // // ******************************************************************* int main(void) // Hauptprogramm Start { cli(); // Interrupts aus für Initialisierung // ******************************************************************* // Ports definieren und ggf. vorbelegen DDRC = 0b11111111; // Alles Ausgänge PORTC = 0b00000000; //Alles aus DDRB = 0b11111111; // Alles Ausgänge PORTB = 0b00000000; //Alles aus // Port D mit Eingangsbits 2k20f Programm vorbelegen DDRD = 0b11110011; // Alles Ausgänge PORTD = 0b00000000; //Alles aus // A_13_20_Port = (1<mid_1+20 && !wechselabwarten_1) //Knueppel nach unten und vorher in Mittelstellung? { schaltzeit_cnt1 =0; schaltzeit_cnt = 0; startTimer2(); while((signal_1>mid_1+20) && !wechselabwarten_1) //Knueppel nach unten und vorher in Mittelstellung? { schaltzeit_cnt1 = schaltzeit_cnt; if (schaltzeit_cnt1 >= schaltzeit) // war Schaltzeit lang ? { schaltzeit_cnt1 = 0; // Zuweisung Schaltzustand schaltzustand_1 = 1; } } stopTimer2(); wechselabwarten_1 = 1; schalt_cnt_1_u++; // Anzahl der Schaltvorgaenge if ((1= schaltzeit) { schaltzeit_cnt1 = 0; // Zuweisung Schaltzustand schaltzustand_1 = 3; } else { schaltzeit_cnt1 = 0; } } if(signal_1>mid_1-10 && signal_1mid_2+20 && !wechselabwarten_2) //Knueppel nach unten und vorher in Mittelstellung? { schaltzeit_cnt2 =0; schaltzeit_cnt = 0; startTimer2(); while((signal_2>mid_2+20) && !wechselabwarten_2) // Schaltzeit abwarten { schaltzeit_cnt2 = schaltzeit_cnt; if (schaltzeit_cnt2 >= schaltzeit) // war Schaltzeit lang ? { schaltzeit_cnt2 = 0; // Zuweisung Schaltzustand schaltzustand_2 = 1; } } stopTimer2(); wechselabwarten_2 = 1; schalt_cnt_2_u++; // Anzahl der Schaltvorgaenge if ((1= schaltzeit) // war Schaltzeit lang ? { schaltzeit_cnt2 = 0; // Zuweisung Schaltzustand schaltzustand_2 = 3; } else { schaltzeit_cnt2 = 0; // Zaehler Schaltzeit ruecksetzen } } if(signal_2>mid_2-10 && signal_2