;****** NeoMat 1.2 (c) Oliver Mezger 22.02.2007. .include "2313def.inc" .equ papagei = 1 .equ epromVirgin = 99 .equ epromSerLLow = 100 .equ epromSerLHigh = 101 .equ epromSerRLow = 102 .equ epromSerRHigh = 103 ;********* Hardware-Verbindungen ;*** PortD .equ rAb = 6 ;Ausgang des AB-Relais .equ sLi = 5 ;Eingang Servo links .equ sRi = 4 ;Eingang Servo rechts .equ tPr = 3 ;Eingang Programmier-Taste .equ tSp = 2 ;Taster Spanisch / + .equ tEn = 1 ;Taster Englisch / - .equ tDe = 0 ;Taster Deutsch / mode ;*** PortB .equ lGr = 7 ;LED Green / Spanisch .set lRe = 6 ;LED Red / Englisch .set lYe = 5 ;LED Yellow / Deutsch .equ rSp = 4 ;Relais Spanisch .equ rEn = 3 ;Relais Englisch .equ rDe = 2 ;Relais Deutsch .equ sLo = 1 ;Pin von linkem Servo-Ausgang .equ sRo = 0 ;Pin von rechtem Servo-Ausgang ;********* Software .equ servosAn = 0 ;MerkerBit 0 für Servos .def merker = R1 ;MerkerRegister .def stat = R3 ;Speichern des Status während Interrupt .def itempL = R4 ;Temoräre Register für Interrupts .def itempH = R5 .def sLlow = R6 ;Linkes Servo Mund ganz zu .def sLhigh = R7 ;Linkes Servo Mund ganz auf .def sRlow = R8 ;Rechtes Servo Mund ganz zu .def sRhigh = R9 ;Rechtes Servo Mund ganz auf .def temp = R16 ;Temp-Register zum Arbeiten .def temp2 = R17 .def servoL = R18 ;Position von ServoL .def servoR = R19 ;Position von ServoR .def itemp = R20 ;Temoräre Register für Interrupts .def keystat = R21 ;Alle Taster die gedrückt sind .def keytest = R22 ;Test gedrückte Taster .def keyenter = R23 ;Taster, die gerade gedrückt wurden .def keyexit = R24 ;Taster, die gerade losgelassen wurden .def mode = R25 ;Zustand / Betriebsmodus .def epromAdr = R26 .def epromData = R27 .def blinkdivider = R28 .def blinkcounter = R29 .set cpuclock = 6000 ;Frequenz 6 MHz .set mothercycle = cpuclock *20 / 8 ;Ziel: 20 mSec Zyklus bei 1/8 cputakt .set servoMi = cpuclock/49 ;Mittelstellung der Servos bei ca 0.8 mSec ; ***** Feste Einstellungen fuer Servoendpositonen, bis Reset-Problem geloest ist .set servoLo = cpuclock/57 ;MundZu .set servoHi = cpuclock/42 ;MundAuf .set wait20mc = cpuclock / 50 ;Justage der 20msec Zählschleife .set wait12mc = cpuclock / 80 ;Justage der 12msec Zählschleife .set blinkrate = 20 ;20 mSec * blinkrate .set time10 = 1000 / 2 / blinkrate ;Zeit 10sec mit Blinkzähler .set time6 = 600 / 2 / blinkrate ;Zeit 6sec mit Blinkzähler .set time4 = 400 / 2 / blinkrate ;Zeit 4sec mit Blinkzähler .set time2 = 200 / 2 / blinkrate ;Zeit 2sec mit Blinkzähler rjmp init ;Reset reti ;IRQ0 reti ;IRQ1 reti ;T1 Capture rjmp T1_Comp ;T1 Compare rjmp T1_Over ;T1 Overflow reti ;T0 Overflow init: ldi temp,0xff out DDRB,temp ;PortB als Ausgang ldi temp, 0x00 out PORTB,temp ;PortB auf 0 ldi temp,0b11000000 ;PortD7,D6 als Ausgang out DDRD,temp ;PortD0..D5 als Eingang ldi temp,0b00111111 out PORTD,temp ;Alle Pull-Up an ldi temp,RAMEND ;Oberste RAM-Adresse holen out SPL, temp ;Stack-Pointer initialisieren ; ***** EEPROM auslesen... rjmp no_eprom ; keine EEPROM_Daten verwenden, solange Resetproblem ldi epromAdr,epromVirgin ;Betrachte das Hymen rcall EERead cpi epromData,'F' ;noch Jungfrau brne no_eprom ;Ja, dann Standartwerte ldi epromAdr,epromSerLLow rcall EERead ;EEProm auslesen mov sLlow,epromData mov servoL,epromData ;Mund zu! ldi epromAdr,epromSerLHigh rcall EERead ;EEProm auslesen mov sLhigh,epromData ldi epromAdr,epromSerRLow rcall EERead mov sRlow,epromData mov servoR,epromData ;Mund zu! ldi epromAdr,epromSerRHigh rcall EERead ;EEProm auslesen mov sRhigh,epromData rjmp timer1_first_set no_eprom: ;ldi temp,servoMi ;Standart-Mittelwert ldi temp,servoLo ;MundZu Wert mov sLlow,temp mov sRlow,temp ldi temp,servoHi ;MundAuf Wert mov sLhigh,temp mov sRhigh,temp ldi servoL,servoLo ldi servoR,servoLo timer1_first_set: ldi temp,High(-mothercycle) out TCNT1H,temp ;Timer1 High laden ldi temp,Low(-mothercycle) out TCNT1L,temp ;Timer1 Low laden ldi temp,2 out TCCR1B,temp ;Timer starten Clock = Systemtakt/8 ldi temp,0x80 ;Timer1 Overflow Interupt Flag out TIMSK,temp ;Timer-Interrupt freigeben clr mode ;Betriebsmodus 0 clr merker ;MerkerRegister löschen ldi keystat,7 ;Sichere Annahme, alle Münzer verstopft sbis PIND,tPr ;Gehe in Tesmode wenn bei Power-On PGRM gedrückt rjmp testmode sei ;Interrupts global freigeben (I-Bit) rjmp main testmode: ;Einfacher Hardware-Test in temp,PIND com temp ;Eingang invertieren bst temp, tPr ;Prog-Taste merken brts progs ;Wenn prog gedrückt cbi PORTD,rAb ;Relais AB löschen rjmp lbl0 progs: sbi PORTD,rAb lbl0: andi temp,0b00000111;Eingangstasten maskieren lsl temp lsl temp mov temp2,temp lsl temp lsl temp lsl temp or temp2,temp out PORTB,temp2 sbi PORTB,lGr rcall wait20ms cbi PORTB,lGr rcall wait20ms rjmp testmode T1_Over: in stat,SREG ;Statusregister retten ldi itemp,High(-mothercycle) out TCNT1H,itemp ;Timer1 High laden ldi itemp,Low(-mothercycle) out TCNT1L,itemp ;Timer1 Low laden inc blinkdivider ; cpi blinkdivider,blinkrate brmi t1over1 clr blinkdivider inc blinkcounter t1over1: sbrs merker,servosAn;wenn keine Servos rjmp t1overout ;zum Ende springen mov itempL,servoL ;Linker Servo rcall T1_timeMark ;Ende Marke setzen sbi PORTB,sLo ;Linger Servo start ldi itemp,0xc0 ;Timer1 Overflow Interupt Flag out TIMSK,itemp ;Timer-Interrupt freigeben t1overout: out SREG,stat ;Statusregister herstellen reti T1_Comp: in stat,SREG ;Statusregister retten sbic PORTB,sLo ;Test, ob ServoL set rjmp serLfin ;Ja, dann zu ServoL-Finish sbic PORTB,sRo ;Test, ob ServoR set rjmp serRfin ;Ja, dann zu ServoR-Finish rjmp T1_fin ; Hier weitere Servos einfügen serLfin: cbi PORTB,sLo ;Bit ServoL clear mov itempL,servoR ;Weiter mit ServoR rcall T1_timeMark ;Ende Marke setzen sbi PORTB,sRo ;ServoR set rjmp T1_fin serRfin: cbi PORTB,sRo ;Bit ServoR clear ldi itemp,0x80 ;Timer1 Overflow Interupt Flag out TIMSK,itemp ;Timer-Interrupt freigeben T1_fin: out SREG,stat ;Statusregister herstellen reti T1_timeMark: clr itempH ; Löschen lsl itempL ;mit 2 multiplizieren rol itempH ;Carry in itempH bewegen lsl itempL ;mit 2 multiplizieren rol itempH ;Carry in itempH bewegen lsl itempL ;mit 2 multiplizieren rol itempH ;Carry in itempH bewegen in itemp,TCNT1L ;Counter1 Low einlesen add itempL,itemp ;Addiere zu Counter1 in itemp,TCNT1H ;Conter1 High einlesen adc itempH,itemp ;Addiere zu Counter1 out OCR1AH,itempH ;ins Compare1 Register schreiben out OCR1AL,itempL ; ret main: ldi temp,0 out PORTB,temp ;erst mal alles aus cbi PORTD,rAb clt ;lösche das T-Flag bld merker,servosAn ;Transferiere T-Flag in Merker, d.h. lösche servosAn main_cycle: rcall keycheck sbrc keyenter,tPr ;wenn Programmtaste gedrückt rjmp progmode_enter ;dann Programmieren rcall betriebsblinken andi keyenter,0b00000111 ;wenn eine Münze brne start_game ;fang an rjmp main_cycle start_game: ldi temp,0 out PORTB,temp ;erst mal alles aus cbi PORTD,rAb clt ;lösche das T-Flag bld merker,servosAn ;Transferiere T-Flag in Merker, d.h. lösche servosAn clr blinkcounter ;Timer auf Null setzen chill: cpi blinkcounter,time2 ;warte bis 2 Sec brlo chill ; um sind sbrc keyenter,tSp ;wenn Spanisch gedrückt sbi PORTB,rSp ;das spanische Relais sbrc keyenter,tEn ;wenn Englisch sbi PORTB,rEn ;das englische Relais sbrc keyenter,tDe ;wenn Deutsch sbi PORTB,rDe ;dann Deutsch .ifdef papagei ;wenn Papagei sbi PORTD,rAB ;dann AB-Relais als Summenrelais .endif clr blinkcounter ;Timer auf Null setzen sbi PORTB,lYe ;Anzeige Zustand 1 start_wait: rcall keycheck sbrc keyenter,tPr ;wenn Programmtaste gedrückt rjmp progmode_enter ;dann Programmieren ;rcall betriebsblinken andi keyenter,0b00000111;wenn eine Münze brne start_game ;fang wieder an cpi blinkcounter,time6 ;warte bis 4 Sec brlo start_wait ;um sind cbi PORTB,lYe ;Anzeige Zustand 2 sbi PORTB,lRe wait_to10: rcall keycheck sbrc keyenter,tPr ;wenn Programmtaste gedrückt rjmp progmode_enter ;dann Programmieren ;rcall betriebsblinken rcall schwaetzo ;nun mit Servos andi keyenter,0b00000111;wenn eine Münze brne start_game ;fang wieder an cpi blinkcounter,time10 ;warte bis 10 Sec brlo wait_to10 ;um sind clr blinkcounter sbi PORTB,lYe ;Anzeige Zustand 3 wait_silence: sbis PIND,sLi ;wenn linker Eingang = 0,dh.wenn Sound clr blinkcounter ;Timer auf Null setzen sbis PIND,sRi ;wenn rechter Eingang = 0 clr blinkcounter ;Timer auf Null setzen rcall keycheck sbrc keyenter,tPr ;wenn Programmtaste gedrückt rjmp progmode_enter ;dann Programmieren ;rcall betriebsblinken cbi PORTB,lGr cpi blinkcounter,0 ;wenn sound brne nosound sbi PORTB,lGr ;leuchte nosound: rcall schwaetzo ;nun mit Servos andi keyenter,0b00000111;wenn eine Münze brne start_game ;fang wieder an cpi blinkcounter,time6 ;warte bis 5 Sec brlo wait_silence ;um sind ;*** Nun AB clr blinkcounter ldi temp,0 out PORTB,temp ;erst mal alles aus clt ;lösche das T-Flag bld merker,servosAn ;Transferiere T-Flag in Merker, d.h. lösche servosAn .ifndef papagei ;wenn normal sbi PORTD,rAb ;das AB-Relais setzen wait_ab: rcall keycheck sbrc keyenter,tPr ;wenn Programmtaste gedrückt rjmp progmode_enter ;dann Programmieren cpi blinkcounter,200 / 2 / blinkrate ;warte bis 2 Sec brlo wait_ab ;um sind .endif rjmp main schwaetzo: ;Steuerung für die Münder set bld merker,servosAn ;Servos an cp sLlow,servoL ;ist Mund zu brsh mundL_zu ;ja, dann tue nix dec servoL ;Mund ist noch auf mundL_zu: cp sRlow,servoR ;ist Mund zu brsh mundR_zu dec servoR ;Mund ist noch auf mundR_zu: sbis PIND,sLi ;wenn linker Eingang = 0,dh.wenn Sound subi servoL,-5 ;Addiere 5 -> Mach Mund auf sbis PIND,sRi ;wenn rechter Eingang = 0 subi servoR,-5 ;Addiere 5 -> Mach Mund auf cp sLhigh,servoL ;ist Mund ganz auf brsh mundL_auf ;nein, dann tue nix mov servoL,sLhigh ;nicht zu sehr aufreissen mundL_auf: cp sRhigh,servoR ;ist Mund ganz auf brsh mundR_auf ;nein, dann tue nix mov servoR,sRhigh ;nicht zu sehr aufreissen mundR_auf: ret betriebsblinken: sbrc blinkcounter,1 ;wenn Bit 1 gesetzt rjmp ma_setled ;setze Leds cbi PORTB,lGr ;sonst lösche ledS cbi PORTB,lRe ;sonst lösche ledE cbi PORTB,lYe ;sonst lösche ledD rjmp ma_ledweiter ma_setled: sbrs keystat,tSp ;ist Taste Spain nicht gedrückt sbi PORTB,lGr ;LED Spain leuchtet sbrs keystat,tEn ;ist Taste Enlish nicht gedrückt sbi PORTB,lRe ;LED English leuchtet sbrs keystat,tDe ;ist Taste Deutsch nicht gedrückt sbi PORTB,lYe ;LED Deutsch leuchtet ma_ledweiter: ret progmode_enter: set ;setze das T-Flag bld merker,servosAn ;Transferiere T-Flag in Merker, d.h. setze servoAn ldi temp,0 out PORTB,temp ;Alle Ausgänge Löschen cbi PORTD,rAb sbi PORTB,lYe clr mode ;Betriebsmodus wird nachher 0 sein sei ;Interrupts an ;**** ServoL-Low mov servoL,sLlow ;Progmode1 enter mov servoR,sRlow ;Mund zu progmode1: sbrc blinkcounter,1 ;wenn Bit 1 gesetzt, langsames Blinken rjmp pr_setled1 ;setze Led cbi PORTB,lGr ;sonst lösche LED rjmp pr_ledweiter1 pr_setled1: sbi PORTB,lGr pr_ledweiter1: rcall keycheck sbrc keyenter,tSp ;Taster Spanisch / + inc servoL sbrc keyenter,tEn ;Taster Englisch / - dec servoL sbrs keyenter,tDe ;wenn progmode nicht verlassen rjmp progmode1 ;weiter verstellen mov sLlow,servoL ;**** ServoL-High cp servoL,sLhigh ;steht Servo schon über dem Maximum brsh progmode2 ;tue nichts mov servoL,sLhigh ;lade Maximum progmode2: sbrc blinkcounter,0 ;wenn Bit 0 gesetzt, schnelleres Blinken rjmp pr_setled2 ;setze Led cbi PORTB,lGr ;sonst lösche LED rjmp pr_ledweiter2 pr_setled2: sbi PORTB,lGr pr_ledweiter2: rcall keycheck sbrc keyenter,tSp ;Taster Spanisch / + inc servoL sbrc keyenter,tEn ;Taster Englisch / - dec servoL sbrs keyenter,tDe ;wenn progmode nicht verlassen rjmp progmode2 ;weiter verstellen mov sLhigh,servoL ;**** ServoR-Low mov servoR,sRlow ;Progmode3 enter cbi PORTB,lGr progmode3: sbrc blinkcounter,1 ;wenn Bit 1 gesetzt, langsames Blinken rjmp pr_setled3 ;setze Led cbi PORTB,lRe ;sonst lösche LED rjmp pr_ledweiter3 pr_setled3: sbi PORTB,lRe pr_ledweiter3: rcall keycheck sbrc keyenter,tSp ;Taster Spanisch / + inc servoR sbrc keyenter,tEn ;Taster Englisch / - dec servoR sbrs keyenter,tDe ;wenn progmode nicht verlassen rjmp progmode3 ;weiter verstellen mov sRlow,servoR ;**** ServoR-High cp servoR,sRhigh ;steht Servo schon über dem Maximum brsh progmode4 ;tue nichts mov servoR,sRhigh ;lade Maximum progmode4: sbrc blinkcounter,0 ;wenn Bit 0 gesetzt, schnelleres Blinken rjmp pr_setled4 ;setze Led cbi PORTB,lRe ;sonst lösche LED rjmp pr_ledweiter4 pr_setled4: sbi PORTB,lRe pr_ledweiter4: rcall keycheck sbrc keyenter,tSp ;Taster Spanisch / + inc servoR sbrc keyenter,tEn ;Taster Englisch / - dec servoR sbrs keyenter,tDe ;wenn progmode nicht verlassen rjmp progmode4 ;weiter verstellen mov sRhigh,servoR ;**** progmode_exit: clt ;lösche das T-Flag bld merker,servosAn ;Transferiere T-Flag in Merker, d.h. lösche servosAn ldi temp,0 out PORTB,temp ;Ausgänge aus cli ;sperre Interrupts wait_to_prog: sbi PORTB,lYe ;gelbe LED an rcall wait20ms rcall wait20ms rcall wait20ms cbi PORTB,lYe rcall wait20ms rcall wait20ms rcall wait20ms rcall keycheck sbrc keyenter,tDe ;wenn Mode-Taste gedrückt rjmp progmode_enter ;noch mal überprüfen sbrs keyenter,tPr ;wenn Programmiertaste nicht gedrückt rjmp wait_to_prog ;aufs Programmieren warten ldi epromAdr,epromSerLLow mov epromData,sLlow rcall EEWrite ;EEProm schreiben ldi epromAdr,epromSerLHigh mov epromData,sLhigh rcall EEWrite ;EEProm schreiben ldi epromAdr,epromSerRLow mov epromData,sRlow rcall EEWrite ;EEProm schreiben ldi epromAdr,epromSerRHigh mov epromData,sRhigh rcall EEWrite ;EEProm schreiben ldi epromAdr,epromVirgin ldi epromData,'F' rcall EEWrite ;EEProm schreiben sei ;Interrupts wieder frei geben rjmp main keycheck: ldi keyenter,0 ldi keyexit,0 in keytest,PIND ;Lade PD com keytest ;invertieren andi keytest,0b00001111 ;Taster Maskieren cpse keystat,keytest ;Test ob Veränderung rjmp keynew ;Veränderung ret ;alles gleich keynew: rcall wait12ms ;etwas warten in temp,PIND ;nochmal einlesen com temp ;invertieren andi temp,0b00001111 ;maskieren cpse keytest,temp ;ist es stabil ret ;war nix, da nicht stabil mov keyenter,keystat com keyenter ;invertieren and keyenter,keytest ;steigende Flanken, !alt & neu mov keyexit,keytest com keyexit ;invertieren and keyexit,keystat ;fallende Flanken, alt & !neu mov keystat,keytest ;alt := neu ret wait20ms: ldi temp,wait20mc ;äusseren Zähler laden: 80 bei 4MHz wl1: ldi temp2,250 ;inneren Zähler laden wl2: nop dec temp2 ;temp2-- brne wl2 ;Sprung wenn nicht null dec temp ;temp-- brne wl1 ;Sprung wenn nicht null ret wait12ms: ldi temp,wait12mc ;äusseren Zähler laden: 50 bei 4MHz wl1b: ldi temp2,250 ;inneren Zähler laden wl2b: nop dec temp2 ;temp2-- brne wl2b ;Sprung wenn nicht null dec temp ;temp-- brne wl1b ;Sprung wenn nicht null ret EEWrite: sbic EECR,EEWE ;falls EEWE nicht log.0 rjmp EEWrite ; weiter warten out EEAR,epromAdr ;Adresse festlegen out EEDR,epromData ;Daten festlegen sbi EECR,EEMWE ;EEMWE-Bit gibt Programmierung frei sbi EECR,EEWE ;EEWE-Bit startet Programmierung ret EERead: sbic EECR,EEWE ;falls EEWE nicht log. 0 rjmp EERead ; weiter warten out EEAR,epromAdr ;Adresse festlegen sbi EECR,EERE ;EERE-Bit setzen: Lesevorgang starten in epromData,EEDR ;Datenbyte einlesen ret