// 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; }
|