Die Lokation
BruScheiKa bedeutet Brunzen Scheissen Kaufen. Früher war in dem Klohäuschen ein Kiosk integriert. [ Bildergalerie ]
Die Funktion der Elektronik
Angeschlossene Komponenten
![]() |
Zwei Figuren mit steuerbaren Augen, Mund und zwei Händen. | ![]() |
3 Münzprüfer mit je zwei Sensoren für unterschiedliche Münzen. An jedem Münzprüfer befindet sich eine LED |
Blockschaltbild
ISP-Programmieradapter
Belegung Stecker IR-Empfänger
|
Belegung Stecker Servos
Belegung Stecker Münzer
LED und Sensoren gegen GND
Belegung Stecker CD-Spieler
Belegung Stecker Relais
Relais mit Freilaufdiode gegen +5V |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
µController ATmega16
| Belegung | Bedeutung | Pin | Â Â Â Â Â Â Â Â Â Â Â | Pin | Bedeutung | Belegung |
|---|---|---|---|---|---|---|
| M1 LED Gn Links | (XCK/T0) PB0 | 1 | A T M E G A 6 4 4 |
40 | PA0 (ADC0) | Audio Li |
| M2 LED Rt Rechts | (T1) PB1 | 2 | 39 | PA1 (ADC1) | Audio Re | |
| M1 Sk | (INT2/AIN0) PB2 | 3 | 38 | PA2 (ADC2) | CD1 | |
| M1 Sg / LCD-RS | (OC0/AIN1) PB3 | 4 | 37 | PA3 (ADC3) | CD2 | |
| M2 Sk / LCD-D4 | (SS) PB4 | 5 | 36 | PA4 (ADC4) | CD3 | |
| M2 Sg / LCD-D5 | (MOSI) PB5 | 6 | 35 | PA5 (ADC5) | CD4 | |
| M3 Sk / LCD-D6 | (MISO) PB6 | 7 | 34 | PA6 (ADC6) | CD5 | |
| M3 Sg / LCD-D7 | (SCK) PB7 | 8 | 33 | PA7 (ADC7) | CD6 | |
| 10K Ohm -> VCC | /RESET | 9 | 32 | AREF | ||
| VCC | 10 | 31 | GND | |||
| GND | 11 | 30 | AVCC | |||
| XTAL2 | 12 | 29 | PC7 (TOSC2) | Servo 8 | ||
| XTAL1 | 13 | 28 | PC6 (TOSC1) | Servo 7 | ||
| (RXD) PD0 | 14 | 27 | PC5 (TDI) | Servo 6 | ||
| (TXD) PD1 | 15 | 26 | PC4 (TDO) | Servo 5 | ||
| IR-Empfänger | (INT0) PD2 | 16 | 25 | PC3 (TMS) | Servo 4 | |
| LCD-E | (INT1) PD3 | 17 | 24 | PC2 (TCK) | Servo 3 | |
| M3 LED | (OC1B) PD4 | 18 | 23 | PC1 (SDA) | Servo 2 | |
| Relais1 | (OC1A) PD5 | 19 | 22 | PC0 (SCL) | Servo 1 | |
| Relais2 | (ICP1) PD6 | 20 | 21 | PD7 (OC2) | Relais3 |
Teilfunktionen
8 Servos ansteuern
Die Pulsweite soll in 10 µs Servo-Schritten verstellbar sein. Hier die naheliegenden Kombinationen:
| CPU Frequenz | Vorteiler | µs pro Zahl | Bewertung |
|---|---|---|---|
| 1 MHz | 1:1 | 1 | Int. Oszillator ist vorkalibriert, Standard, Multiplikation mit 10 notwendig |
| 4 MHz | 1:8 | 2 | Mehraufwand bei Kalibrierung, Multiplikation mit 5 notwendig |
| 8 MHz | 1:8 | 1 | Mehraufwand bei Kalibrierung, Multiplikation mit 10 notwendig |
![]() |
Gewählt 8 MHz mit Vorteiler 1:8, zum Multiplizieren mit 10 gibt es ja beim Mega16 praktische Befehle.
Um die 20 ms = 20 000 µs zu zählen brauchen wir den 16 Bit Timer1. Betriebsart Clear Timer on Compare Mode . Der Timer zählt von 0 bis zu einem einstellbaren TOP Wert und springt dann wieder auf 0. Ein Ausgang kann beim Sprung von TOP auf 0 gesetzt und bei Erreichen eines einstellbaren Wertes OCR1A wieder rückgesetzt werden. ICR1 als TOP weil nicht verändert mit Wert 19 999 für 20 ms Wiederholungsintervall, OCR1A = Servo-Schritt * 10. Bei Erreichen von OCR1A wird ein Interrupt ausgelöst. |
Einstellungen bei Initialisierung
| Register | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Beschreibung |
|---|---|---|---|---|---|---|---|---|---|---|
| TCCR1A | Bedeutung | COM1A1 | COM1A0 | COM1B1 | COM1B0 | FOC1A | FOC1B | WGM11 | WGM10 | |
| Wert | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Waveform Generation Mode: CTC mit ICR1 als TOP |
|
| TCCR1B | Bedeutung | ICNC1 | ICES1 | - | WGM13 | WGM12 | CS12 | CS11 | CS10 | |
| Wert | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | Vorteilung Timer mit CPU-CLK / 8 | |
| TIMSK | Bedeutung | OCIE2 | TOIE2 | TICE1 | OCIE1A | OCIE1B | TOIE1 | OCIE0 | TOIE0 | Input Capture Interrupt Enable (ICF1) |
| Wert | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | Output Compare Interrupt Enable |
Audio in Mundbewegung wandeln
- Vorteiler (Prescaler) für Takt an Wandler (soll im Bereich 50kHz..200kHz liegen) einstellen. Mögliche Teilungen 2,4,8,16,32,64,128. Gewählt 128 = > 8 MHz / 128 = 62,5 kHz
- Referenzspannung für Wandler ist AREF
- Stetige, Kontinuierliche Wandlung mit Interruptauslösung
- Auflösung 10Bit aber nur 8 Bit verwendet
Einstellungen bei Initialisierung
| Register | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Beschreibung |
|---|---|---|---|---|---|---|---|---|---|---|
| ADMUX | Bedeutung | REFS1 | REFS0 | ADLAR | MUX4 | MUX3 | MUX2 | MUX1 | MUX0 | Interne 2,56V Referenzspannung, Wert ist linksbüdig in ADCH:ADCL |
| Wert | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | Linker Kanal an PC0 (ADC0) | |
| ADCSRA | Bedeutung | ADEN | ADSC | ADATE | ADIF | ADIE | ADPS2 | ADPS1 | ADPS0 | Wandler an, Auto Trigger Enable, Interrupt frei |
| Wert | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | Vorteiler auf CLK /1 28 | |
| SFIOR | Bedeutung | ADTS2 | ADTS1 | ADTS0 | - | ACME | PUD | PSR2 | PSR10 | Free Running Mode |
| Wert | 0 | 0 | 0 |
Handbewegungen erzeugen
Ablaufsteuerung des Automaten Münzeinwurf
![]() |
![]() |
| Ablauf bei grosser Münze | Prellen des Sensors am Anfang |
|---|
IR Empfänger
| OUT | 1 | Oben (Linse) |
| GND | 2 | |
| VCC | 3 |
Gebräuchliche Codes[IR Code Knowledgebase] [SFH 5110-38]
Â
Verbesserungen ToDo
- Redesign der Servoansteuerung, Problem mit negativen Zahlen und Nullpunkt
- Schwätzo soll schneller Servos bewegen
- IR Empfang
- 6 Kanäle
- Während Vorstellung eingeworfene Münzen sollen neue Sequenz starten
Prototyp Platine mit LCD-Anzeige
Typischer Anschlußbelegung eines Displays [LCD-Modul am AVR] [AVR-GCC-Tutorial/LCD-Ansteuerung]
| Pin | Bezeichnung | Beschreibung | Belegung | Steckerpin |
| 1 | GND | Masse | GND | 1 |
| 2 | VCC | Spannungsversorgung +5V | +5V | 2 |
| 3 | VEE | Kontrast Poti 0..0,5V | GND | |
| 4 | RS | Register Select, 1=Daten schreiben / 0=Kommando senden. | RS | 3 |
| 5 | R/W | 1=Read / 0=Write zum lesen / schreiben in das Display RAM | GND | |
| 6 | Enable | Fallende Flanke -> Übertragen des Kommandos oder der Daten, H-Pegel -> Lesen von Daten aus dem Display | E | 4 |
| 7 | DB0 | Datenbus Bit0 LSB | NC | |
| 8 | DB1 | Datenbus Bit1 | NC | |
| 9 | DB2 | Datenbus Bit2 | NC | |
| 10 | DB3 | Datenbus Bit3 | NC | |
| 11 | DB4 | Datenbus Bit4 | D4 | 5 |
| 12 | DB5 | Datenbus Bit5 | D5 | 6 |
| 13 | DB6 | Datenbus Bit6 | D6 | 7 |
| 14 | DB7 | Datenbus Bit7 MSB | D7 | 8 |
| GND | 9 | |||
| IR-Sensor | 10 |
![]() |
|
Schlimmer C-Quellcode
// BruScheiKa V 1.1 beta (c) Oliver Mezger 12.5.2010 #include <avr/io.h> // Definitionen laden #include <util/delay.h> // Delay-Bibliothek laden #include <avr/interrupt.h> #include "lcd-routines.h" #include <stdlib.h> #define HardWareTest 0 #define vuTest 1 // Zuordnungen zu Ports #define RelaisIn PIND #define RelaisOut PORTD #define RelaisDdr DDRD #define MuenzIn PINB #define MuenzOut PORTB #define MuenzDdr DDRB #define CDIn PINA #define CDOut PORTA #define CDDdr DDRA #define ServosIn PINC #define ServosOut PORTC #define ServosDdr DDRC // Automatenspezifische Einstellungen #define F1Augen 0 #define F1Mund 1 #define F1Rumpf 2 #define F1Hand 3 #define F2Augen 4 #define F2Mund 5 #define F2Rumpf 6 #define F2Hand 7 #define M1Led 0 // an Muenz #define M2Led 1 // an Muenz #define M3Led 4 // an Relais #define M1Sk 2 #define M1Sg 3 #define M2Sk 4 #define M2Sg 5 #define M3Sk 6 #define M3Sg 7 #define CD1 2 #define CD2 3 #define CD3 4 #define CD4 5 #define CD5 6 #define CD6 7 #define Relais1 5 // Summe an sobald Automat laueft #define Relais2 6 // Tisch hebt sich links #define Relais3 7 // Tisch hebt sich rechts // Figur 1 Mann links aus Sicht der Zuschauer #define F1AugenMitte 150 #define F1AugenRechts 199 #define F1AugenLinks 101 #define F1MundAuf 102 #define F1MundZu 142 #define F1RumpfVorne 100 #define F1RumpfHinten 200 #define F1HandOben 100 #define F1HandUnten 200 // Figur 2 Frau rechts aus Sicht der Zuschauer #define F2AugenMitte 150 #define F2AugenRechts 200 #define F2AugenLinks 100 #define F2MundAuf 118 #define F2MundZu 152 #define F2RumpfRechts 200 #define F2RumpfLinks 100 #define F2HandOben 100 #define F2HandUnten 200 #define anfangWarten 15 // 25 Sekunden warten bis Sprache kommt #define schnauzAus 10 // 10 Sekunden bis Auschalten nach Stille // Reihenfolge der Sequenzen {tisch,kindertraum,geleitschutz} const unsigned char R2an[] ={108,0,0}; // Tisch links const unsigned char R2aus[] ={120,0,0}; const unsigned char R3an[] ={0,0,116}; // Tisch rechts const unsigned char R3aus[] ={0,0,123}; typedef enum {stop,mitte,rechts,links,vorne,hinten,oben,unten,bewegen,bewegen2} bewegungen; //volatile unsigned char test = 3; volatile unsigned char sprachSituation=0; //links,rechts volatile bewegungen F1Zustand[3] ={bewegen,bewegen,bewegen}; //Augen,Neigung,Hand volatile bewegungen F2Zustand[3] ={mitte,stop,stop}; //Augen,Drehung,Hand volatile unsigned char servosAn=0,aktServo=0, servo[8]={150,150,150,150,150,150,150,150}; //100 = 1000ms,200 = 2000ms volatile unsigned int systemZeit =0; // Inkrement alle 20ms durch Timer1 volatile unsigned int sekundenUhr = 0; // Inkrement jede Sekunde volatile unsigned char lebensTakt = 0; // Takt für Lebenssteuerung der Figuren volatile unsigned char keyEnter = 0,keyExit =0; // Ergebnisse Muenzpruefung volatile char ausTimer = 0; void setF1(bewegungen a,bewegungen b, bewegungen c){ F1Zustand[0] = a; F1Zustand[1] = b; F1Zustand[2] = c; } void F1leben(){ // Mann Links const unsigned char F1RumpfSpeed = 1; const unsigned char F1HandSpeed =2; const bewegungen Augenbewegung[] ={mitte,mitte,mitte,links,links,mitte,rechts,mitte,mitte,rechts,links,links,links}; // max 16 Eintraege static unsigned char augenposition = 0; static unsigned char richtungen = 0; // Bit 0 Rumpf, Bit 1 Hand bewegungen n; unsigned char i; if (F1Zustand[0] == bewegen){ augenposition++; i = augenposition >>4; if (i >= sizeof(Augenbewegung)){ augenposition = 0; i =0; } n = Augenbewegung[i]; } else n = F1Zustand[0]; switch(n){ case stop: break; case mitte: servo[F1Augen] = F1AugenMitte; break; case rechts: servo[F1Augen] = F1AugenRechts; break; case links: servo[F1Augen] = F1AugenLinks; break; default:; } switch(F1Zustand[1]){ // Rumpf case stop: break; case vorne: if (F1RumpfVorne > servo[F1Rumpf]) servo[F1Rumpf]+=F1RumpfSpeed; else if (F1RumpfVorne < servo[F1Rumpf]) servo[F1Rumpf]-=F1RumpfSpeed; break; case hinten: if (F1RumpfHinten > servo[F1Rumpf]) servo[F1Rumpf]+=F1RumpfSpeed; else if (F1RumpfHinten < servo[F1Rumpf]) servo[F1Rumpf]-=F1RumpfSpeed; break; case bewegen: if (richtungen&1){ if (F1RumpfVorne > servo[F1Rumpf]) servo[F1Rumpf]+=F1RumpfSpeed; else if (F1RumpfVorne < servo[F1Rumpf]) servo[F1Rumpf]-=F1RumpfSpeed; else richtungen &= 0b11111110; } else{ if (F1RumpfHinten > servo[F1Rumpf]) servo[F1Rumpf]+=F1RumpfSpeed; else if (F1RumpfHinten < servo[F1Rumpf]) servo[F1Rumpf]-=F1RumpfSpeed; else richtungen |= 1; } break; default:; } switch(F1Zustand[2]){ // Hand case stop: break; case oben: if (F1HandOben > servo[F1Hand]) servo[F1Hand]+=F1HandSpeed; else if (F1HandOben < servo[F1Hand]) servo[F1Hand]-=F1HandSpeed; break; case unten: if (F1HandUnten > servo[F1Hand]) servo[F1Hand]+=F1HandSpeed; else if (F1HandUnten < servo[F1Hand]) servo[F1Hand]-=F1HandSpeed; break; case bewegen: if (richtungen&2){ if (F1HandOben > servo[F1Hand]) servo[F1Hand]+=F1HandSpeed; else if (F1HandOben < servo[F1Hand]) servo[F1Hand]-=F1HandSpeed; else richtungen &= 0b11111101; } else{ if (F1HandUnten > servo[F1Hand]) servo[F1Hand]+=F1HandSpeed; else if (F1HandUnten < servo[F1Hand]) servo[F1Hand]-=F1HandSpeed; else richtungen |= 2; } break; default:; } } void setF2(bewegungen a,bewegungen b, bewegungen c){ F2Zustand[0] = a; F2Zustand[1] = b; F2Zustand[2] = c; } void F2leben(){ const unsigned char F2RumpfSpeed = 2; const unsigned char F2HandSpeed =2; const bewegungen Augenbewegung[] ={mitte,mitte,links,rechts,rechts,mitte,mitte,rechts,links}; // max 15 Eintraege static unsigned char augenposition = 0; static unsigned char richtungen = 0; // Bit 0 Rumpf, Bit 1 Hand bewegungen n; unsigned char i; if (F2Zustand[0] == bewegen){ // Augen augenposition++; i = augenposition >>4; if (i >= sizeof(Augenbewegung)){ augenposition = 0; i =0; } n = Augenbewegung[i]; } else n = F2Zustand[0]; switch(n){ case stop: break; case mitte: servo[F2Augen] = F2AugenMitte; break; case rechts: servo[F2Augen] = F2AugenRechts; break; case links: servo[F2Augen] = F2AugenLinks; break; default:; } switch(F2Zustand[1]){ // Rumpf case stop: break; case rechts: if (F2RumpfRechts > servo[F2Rumpf]) servo[F2Rumpf]+=F2RumpfSpeed; else if (F2RumpfRechts < servo[F2Rumpf]) servo[F2Rumpf]-=F2RumpfSpeed; break; case links: if (F2RumpfLinks > servo[F2Rumpf]) servo[F2Rumpf]+=F2RumpfSpeed; else if (F2RumpfLinks < servo[F2Rumpf]) servo[F2Rumpf]-=F2RumpfSpeed; break; case bewegen: if (richtungen&1){ if (F2RumpfRechts > servo[F2Rumpf]) servo[F2Rumpf]+=F2RumpfSpeed; else if (F2RumpfRechts < servo[F2Rumpf]) servo[F2Rumpf]-=F2RumpfSpeed; else richtungen &= 0xfe; } else{ if (F2RumpfLinks > servo[F2Rumpf]) servo[F2Rumpf]+=F2RumpfSpeed; else if (F2RumpfLinks < servo[F2Rumpf]) servo[F2Rumpf]-=F2RumpfSpeed; else richtungen |= 1; } break; default:; } switch(F2Zustand[2]){ // Hand case stop: break; case oben: if (F2HandOben > servo[F2Hand]) servo[F2Hand]+=F2HandSpeed; else if (F2HandOben < servo[F2Hand]) servo[F2Hand]-=F2HandSpeed; break; case unten: if (F2HandUnten > servo[F2Hand]) servo[F2Hand]+=F2HandSpeed; else if (F2HandUnten < servo[F2Hand]) servo[F2Hand]-=F2HandSpeed; break; case bewegen: if (richtungen&2){ if (F2HandOben > servo[F2Hand]) servo[F2Hand]+=F2HandSpeed; else if (F2HandOben < servo[F2Hand]) servo[F2Hand]-=F2HandSpeed; else richtungen &= 0b11111101; } else { if (F2HandUnten > servo[F2Hand]) servo[F2Hand]+=F2HandSpeed; else if (F2HandUnten < servo[F2Hand]) servo[F2Hand]-=F2HandSpeed; else richtungen |= 2; } default:; } } void vuMeter(unsigned char n){ // Anzeige des Pegels int vu; if (n<8){ if (n<2){ if (n<1) vu = 0; else vu = 1; } else{ if (n<4) vu = 3; else vu = 7; } } else{ if (n<16) vu = 15; else if (n<32) vu = 31; else vu = 63; } vu = ~vu; CDOut = (CDOut & 0b00000111) | (vu<<3); // Bit 7..3 } #define anzahlSamples 40 #define sprechSchwelle 4 #define servoInkrement 5 #define defaultAudio 5 unsigned char maxAudioF1 = defaultAudio; unsigned char maxAudioF2 = defaultAudio; ISR(ADC_vect){ static unsigned char wert = 0, i=0; unsigned char n; n = ADCH; // ADC auslesen if (i<=1); // Messung verwerfen else if (i<anzahlSamples){ // Maximum aus den Messungen if (n>wert) wert = n; }else if (i==anzahlSamples){ // Ausgeben F1 und Kanal umschalten // Achtung es muss gelten Mundzu > Mundauf if (wert > maxAudioF1) maxAudioF1 = wert; if (wert > (maxAudioF1>>3)){ n = servo[F1Mund] - servoInkrement; if (n<F1MundAuf) servo[F1Mund]=F1MundAuf; else servo[F1Mund]= n; sprachSituation |= 1; ausTimer =0; } else { n = servo[F1Mund] + servoInkrement; if (n>F1MundZu) servo[F1Mund]=F1MundZu; else servo[F1Mund]= n; } if (vuTest) vuMeter(wert); wert = 0; ADMUX |= 1; // Kanal 1 } else if (i<=anzahlSamples+2); // Messung verwerfen else if (i<2*anzahlSamples){ // Maximum aus 18..23 if (n>wert) wert = n; }else{ // Ausgeben F2 und Kanal umschalten // Achtung es muss gelten Mundzu > Mundauf if (wert > maxAudioF2) maxAudioF2 = wert; if (wert > (maxAudioF2>>3)){ n = servo[F2Mund] - servoInkrement; if (n<F2MundAuf) servo[F2Mund]=F2MundAuf; else servo[F2Mund]= n; sprachSituation |= 2; ausTimer = 0; } else { n = servo[F2Mund] + servoInkrement; if (n>F2MundZu) servo[F2Mund]=F2MundZu; else servo[F2Mund]= n; } if (vuTest) vuMeter(wert); wert = 0; ADMUX &= 0xfe; // Kanal 0 i = 0; } i++; } /*ISR(ADC_vect){ static unsigned char wert = 0, i=0; char n; n = ADCH; // ADC auslesen if (i<=1); // Messung verwerfen else if (i<anzahlSamples){ // Maximum aus den Messungen 1..5 if (n>wert) wert = n; }else if (i==anzahlSamples){ // Ausgeben und Kanal umschalten // Achtung es muss gelten Mundzu > Mundauf if (wert >sprechSchwelle){ n = servo[F1Mund] - servoInkrement; if (n<F1MundAuf) servo[F1Mund]=F1MundAuf; else servo[F1Mund]= n; sprachSituation |= 1; ausTimer =0; } else { n = servo[F1Mund] + servoInkrement; if (n>F1MundZu) servo[F1Mund]=F1MundZu; else servo[F1Mund]= n; } if (vuTest) vuMeter(wert); wert = 0; ADMUX |= 1; // Kanal 1 } else if (i<=anzahlSamples+2); // Messung verwerfen else if (i<2*anzahlSamples){ // Maximum aus 18..23 if (n>wert) wert = n; }else{ // Ausgeben und Kanal umschalten // Achtung es muss gelten Mundzu > Mundauf if (wert >sprechSchwelle){ n = servo[F2Mund] - servoInkrement; if (n<F2MundAuf) servo[F2Mund]=F2MundAuf; else servo[F2Mund]= n; sprachSituation |= 2; ausTimer = 0; } else { n = servo[F2Mund] + servoInkrement; if (n>F2MundZu) servo[F2Mund]=F2MundZu; else servo[F2Mund]= n; } if (vuTest) vuMeter(wert); wert = 0; ADMUX &= 0xfe; // Kanal 0 i = 0; } i++; } */ ISR(TIMER1_CAPT_vect){ // ISR wird alle 20ms aufgerufen static unsigned char su=0,lt=0; // interne Zaehler fuer Takte if (servosAn){ ServosOut = 1; // Servo1 an OCR1A= servo[0]*10+TCNT1; // Zeitmarke setzen } systemZeit++; su++; lt++; if (su >= 50){ su=0; sekundenUhr++; ausTimer++; } if (lt >= 3){ lt =0; lebensTakt++; } aktServo =0; // wieder Start mit Servo 0 } ISR(TIMER1_COMPA_vect){ // ISR fuer die Flankensteuerung der Servos if (servosAn && aktServo < 8){ aktServo++; ServosOut = 1 << aktServo; // neuen Servo an //OCR1A= (((servo[aktServo]<<1)+servo[aktServo])<<1)+1000+TCNT1; // Zeitmarke setzen OCR1A= servo[aktServo]*10+TCNT1; // Zeitmarke setzen } } void keyCheck(){ static unsigned char keyOld = 0; // alter Zustand unsigned char keyTest,tmp; keyEnter = 0, keyExit = 0; keyTest = ~MuenzIn >> 2 & 0b00111111;// Einlesen und zurechtschieben if (keyOld != keyTest){ // hat sich was getan _delay_ms(5); // Prellen abwarten tmp = (~MuenzIn >> 2)&0b00111111; // nochmal Einlesen und zurechtschieben if (tmp == keyTest){ // ist es stabil? keyEnter = (~keyOld) & keyTest; // steigende Flanke !alt und neu keyExit = keyOld & (~keyTest); // fallende Flanke alt und !neu keyOld = keyTest; } } } void testeHardware(){ unsigned int altSekundenUhr =0; char komponente =0; while(1){ if (altSekundenUhr != sekundenUhr){ // warten bis Sekunde rum ist altSekundenUhr = sekundenUhr; switch(komponente){ case 0: MuenzOut |= 1<<M1Led; break; case 1: MuenzOut &= ~(1<<M1Led); MuenzOut |= 1<<M2Led; break; case 2: MuenzOut &= ~(1<<M2Led); RelaisOut |= 1<<M3Led; break; case 3: RelaisOut &= ~(1<<M3Led); RelaisOut |= 1<<Relais1; break; case 4: RelaisOut &= ~(1<<Relais1); RelaisOut |= 1<<Relais2; break; case 5: RelaisOut &= ~(1<<Relais2); RelaisOut |= 1<<Relais3; break; case 6: RelaisOut &= ~(1<<Relais3); CDOut &= ~(1<<CD1); break; case 7: CDOut |= 1<<CD1; CDOut &= ~(1<<CD2); break; case 8: CDOut |= 1<<CD2; CDOut &= ~(1<<CD3); break; case 9: CDOut |= 1<<CD3; CDOut &= ~(1<<CD4); break; case 10:CDOut |= 1<<CD4; CDOut &= ~(1<<CD5); break; case 11:CDOut |= 1<<CD5; CDOut &= ~(1<<CD6); break; case 12:CDOut |= 1<<CD6; break; default: komponente = -1; } komponente++; } } } int main(){ CDDdr = 0b11111100; CDOut = 0b11111100; // Steuerung mit negativer logik ServosDdr = 0xff; // Alle auf Ausgang MuenzDdr = 0b00000011; // RelaisDdr = 0b11110000; // drei Realais und M3Led ADMUX = 0b11100000; // Interne Ref, linksbuendig, ADC1 ADCSRA = 0b11111111; // ADWandler Free Running, Interrupt frei CLK/128 ICR1 = 19999; // Signal alle 20 ms TCCR1A = 0b00000000; // Timer1 CTC Mode TCCR1B = 0b00011010; // Keine Vorteilung Timer mit CPU-CLK / 8 TIMSK = 0b00110000; // ICF1 und OC1A Interrupt Enable lcd_init(); lcd_string("BruScheiKa"); sei(); // globale Interruptfreigabe unsigned char altLebensTakt =0; unsigned int altSekundenUhr =0; unsigned char n=0,f1Laber=0,f2Laber=0; if (HardWareTest) testeHardware(); typedef enum {blinken,anfang,startdelay,vorstellung,ende} automatenstatustyp; automatenstatustyp automatenstatus = blinken; typedef enum {tisch,kindertraum,geleitschutz} sequenztyp; const char sqt1[] = "Tisch"; const char sqt2[] ="Kindertraum"; const char sqt3[] ="Geleitschutz"; const char *sequenzName[] = {sqt1,sqt2,sqt3}; sequenztyp sequenz = tisch; schedul: while(automatenstatus == blinken){ // Warten auf Geld servosAn=0; keyCheck(); // Muenzeinwurf ueberpruefen if (keyEnter){ if (keyEnter&0b00000011) sequenz = tisch; // Muenze an M1 else if (keyEnter&0b00001100) sequenz = kindertraum; // Muenze an M2 else if (keyEnter&0b00110000) sequenz = geleitschutz; // Muenze an M3 automatenstatus = anfang; lcd_clear(); lcd_string("Anfang "); lcd_string(sequenzName[sequenz]); break; } if (altSekundenUhr != sekundenUhr){ // Blinken der LED altSekundenUhr = sekundenUhr; if (sekundenUhr&1){ n = ~MuenzIn>>2; // Muenzer einlesen if ((n & 0b11) ==0) // keine Verstopfung bei M1 MuenzOut |= 1; if ((n & 0b1100) ==0) // keine Verstopfung bei M2 MuenzOut |= 2; if ((n & 0b110000) ==0) // keine Verstopfung bei M3 RelaisOut |= 1<<M3Led; } else{ // LED ausschalten MuenzOut &= ~(3); // M1Led und M2Led RelaisOut &= ~(1<<M3Led); } } } if (automatenstatus == anfang){ // Anfang servosAn=1; altSekundenUhr=sekundenUhr=0; automatenstatus = startdelay; RelaisOut |= 1<<Relais1; // Summenrelais an switch (sequenz){ case tisch: CDOut &= ~(1<<CD1); // CD1 an negative Logik break; case kindertraum: CDOut &= ~(1<<CD2); // CD2 an negative Logik //CDOut &= ~(1<<CD1); // CD1 an negative Logik break; case geleitschutz: CDOut &= ~(1<<CD3); // CD3 an negative Logik //CDOut &= ~(1<<CD1); // CD1 an negative Logik break; } } while(automatenstatus == vorstellung || automatenstatus == startdelay){ if (automatenstatus == startdelay){ if (sekundenUhr > anfangWarten){ automatenstatus = vorstellung; ausTimer = 0; maxAudioF1 = defaultAudio; // Lautstaerke auf Standard setzen maxAudioF2 = defaultAudio; lcd_clear(); lcd_string("Vorstellung "); //lcd_string(sequenzName[sequenz]); } } else if (ausTimer > schnauzAus) automatenstatus = ende; // wenn ruhe dann Ende if (altSekundenUhr != sekundenUhr){ // bei sekundenwechsel altSekundenUhr = sekundenUhr; if (R2an[sequenz]>0 && sekundenUhr == R2an[sequenz]) RelaisOut |= 1<<Relais2; if (R2aus[sequenz]>0 && sekundenUhr == R2aus[sequenz]) RelaisOut &= ~(1<<Relais2); if (R3an[sequenz]>0 && sekundenUhr == R3an[sequenz]) RelaisOut |= 1<<Relais3; if (R3aus[sequenz]>0 && sekundenUhr == R3aus[sequenz]) RelaisOut &= ~(1<<Relais3); } if (altLebensTakt !=lebensTakt){ altLebensTakt =lebensTakt; if (automatenstatus == startdelay || lebensTakt&1) RelaisOut |= 1<<M3Led; else RelaisOut &= ~(1<<M3Led); //MuenzOut = (MuenzOut & 0b11111100) | sprachSituation; if (sprachSituation &1) f1Laber = 15; // wenn 1 dann Delay setzen else if (f1Laber>0){ // Nachlauf zum ueberbruecken von Sprechpausen f1Laber--; sprachSituation |= 1; } if (sprachSituation &2) f2Laber = 15; // wenn 1 dann Delay setzen else if (f2Laber>0){ f2Laber--; sprachSituation |= 2; } MuenzOut = (MuenzOut & 0b11111100) | sprachSituation; switch (sprachSituation){ case 0: // keiner spricht setF1(bewegen,bewegen,bewegen); // Augen Rumpf (vorne hinten) Hand setF2(bewegen,bewegen,bewegen); // Augen Rumpf (rechts links) Hand break; case 1: // links spricht Mann sitzt links setF1(bewegen,bewegen,bewegen); setF2(bewegen,rechts,bewegen); break; case 2: // rechts spricht Frau steht rechts setF1(mitte,hinten,unten); setF2(bewegen,links,stop); break; case 3: // beide sprechen setF1(rechts,bewegen,bewegen); setF2(links,links,stop); break; } sprachSituation = 0; F1leben(); F2leben(); } } if (automatenstatus == ende){ // Ende der Vorstellung servosAn=0; ServosOut=0; // wirklich ausschalten automatenstatus = blinken; RelaisOut &= 0b00011111; // Summenrelais aus CDOut = 0b11111100; // alle CDs aus Steuerung mit negativer logik char Buffer[20]; lcd_clear(); lcd_string("AudioF1 "); itoa(maxAudioF1, Buffer, 10 ); lcd_string( Buffer ); lcd_setcursor( 0, 2 ); lcd_string("AudioF2 "); itoa(maxAudioF2, Buffer, 10 ); lcd_string( Buffer ); } goto schedul; return 0; }








