; FOXPRO.ASM ; ; ************************************ ; * Fuchsjad-Sender Programmiergerät * ; ************************************ ; ; Autor: Nick Roethe, DF1FO, DF1FO at darc.de ; ; Created 11.1.2007 ; Version 0.0: Code-Import von FJRX2 (LCD-Treiber, Drehgeber) ; 18. 1.07 0.1: Treiber LCD, Drehgeber, Sound laufen ; 2. 2.07 0.2: Serielles Interface eingebaut, Kommunikation mit Fuchs läuft ; 5. 2.07 0.3: Hex-Display und Eingabe, Ser. I/F weiter getestet ; 6. 2.07 0.4: Dezimal-Analyse der Hex-Empfangs-Records ; 7. 2.07 0.5: Timer für Beleuchtungs-LED, Sicher-Schalter ; 8. 2.07 0.6: Sekunden-Update Status-Record + Uhr, TX-Analyse ; 8. 2.07 0.7: Programm-Menü eingebaut, noch ohne Aktionen/Umrechnungen ; 9. 2.07 0.8: Sendezeit jetzt n x 10' (geändert wie im Fuchs) ; 9. 2.07 0.9: Uhrzeit einstellen, Start- und Ende Dezimal ausrechnen ; 11. 2.07 0.A: Programm-Menü vervollständigt ; 12. 2.07 0.B: Menü komplett, Fehlende Funktionen: Fuchs#, Prüfen ; 13. 2.07 1.0: Protokolle für Übertragung <> Fuchs, im Prinzip fertig ; 14. 2.07 1.2: Verfeinerungen Benutzer-I/F ; 14. 2.07 1.3: Sleep-Mode spart 4 mA, Clock-Messpunkt an OC2 ; 22. 2.07 1.4: Fixes TX-Test Dauerfunktion, Switches Degate bei Sicher ; 28. 2.07 1.5: Fix Anzeige Fuchs# (Menüpunkt 3/0) ; 30. 3.07 1.6: Neu: Command 4 Oszillator-Messung, Start-Piepser/-Anzeige ; 2. 4.07 1.7: Neu: UBat-Messung eichen, TX-Analyse unterstützt Command 4 ; 17. 4.07 1.8: Neu: Zielzeitregistrierung angefangen ; 18. 4.07 1.9: Zielzeitregistrierung fertig eingebaut und getestet ; 19. 4.07 2.0: Kleinere Clean-Ups ; 12. 6.07 2.1: Lautprecher ein im Hautmenü, 4 statt 5 Pips vor Start, ; Fuchs# 0..7, Fix für Zielzeit-Log-Entry bei Aufruf Start-Menü ; 27. 6.07 2.2: Zielzeitregistrierungin Mode Start+Ziel, Ändern oder Sicher ; Starttöne nur bei Start + Ändern ; 28. 7.07 2.3: Fix für flackerndes Display (in OUTLCD) ; Zielzeit-Flash von 2 sec auf 5 sec verlängert ; 29. 7.07 2.4: Drehgeber- oder Schalter-Betätigung beendet Flash ; 27. 2.08 2.5: Mode $1* (= Programm) wird bei Sendestart beendet ; 11. 3.08 2.6: Einstellung Modulation (Frequenz, Tastgeschwindigkeit) im Menü Extras ; 12. 3.08 2.7: Verbesserungen TX-Analyse ; 24. 3.08 2.8: Anzeigestrings kompakter, STSI-Makro aus FJRX82 (mit C0, C1) ; Clone-Funktion (Master und Slave) eingebaut, ; Dazu neu: SERFLG Bit 2,3 und PROTO = $31, $41 ; 25. 3.08 2.9: Cleanup Serial Interface Handler, SHIFT0..4 in Registern ; Kürzerer Ton -10s Start Alarm ; 27. 3.08 3.0: Anzeige Fuchs-SW-Level im X-Menü ; 10. 4.08 3.1: Korrektur Cusorposition Fuchs# einstellen ; .equ VERSHI= '3' .equ VERSLO= '1' ; ; **** Specify Device ; .device ATmega8 ; ; ; >> FUSES << : EESAVE = 0 ; =========== CKSEL = 1111, SUT = 11 ; BODEN = 0, BODLVL = 0 ; Brown-Out Erkennung @ 4V ; Ergibt Hex-Pattern D13F ; .listmac ; Macro Expansion Listing On ; .equ NACHLZ =30 ; LED-Beleuchtung Nachleuchtzeit in s ; ; **** I/O Register Definitions .equ SREG =$3f .equ SPH =$3e .equ SPL =$3d .equ GIMSK =$3b .equ GICR =$3b ; new name for GIMSK .equ GIFR =$3a .equ TIMSK =$39 .equ TIFR =$38 .equ SPMCR =$37 .equ I2CR =$36 .equ TWCR =$36 .equ MCUCR =$35 .equ MCUSR =$34 ; For compatibility, .equ MCUCSR =$34 ; keep both names until further .equ TCCR0 =$33 .equ TCNT0 =$32 .equ OSCCAL =$31 .equ SFIOR =$30 .equ TCCR1A =$2f .equ TCCR1B =$2e .equ TCNT1H =$2d .equ TCNT1L =$2c .equ OCR1AH =$2b .equ OCR1AL =$2a .equ OCR1BH =$29 .equ OCR1BL =$28 .equ ICR1H =$27 .equ ICR1L =$26 .equ TCCR2 =$25 .equ TCNT2 =$24 .equ OCR2 =$23 .equ ASSR =$22 .equ WDTCR =$21 .equ UBRRH =$20 ; Note! UCSRC equals UBRRH .equ EEARH =$1f .equ EEARL =$1e .equ EEDR =$1d .equ EECR =$1c .equ PORTB =$18 .equ DDRB =$17 .equ PINB =$16 .equ PORTC =$15 .equ DDRC =$14 .equ PINC =$13 .equ PORTD =$12 .equ DDRD =$11 .equ PIND =$10 .equ SPDR =$0f .equ SPSR =$0e .equ SPCR =$0d .equ UDR =$0c .equ UCSRA =$0b .equ UCSRB =$0a .equ UBRRL =$09 .equ ACSR =$08 .equ ADMUX =$07 .equ ADCSR =$06 .equ ADCH =$05 .equ ADCL =$04 .equ I2DR =$03 .equ I2AR =$02 .equ I2SR =$01 .equ I2BR =$00 .equ TWDR =$03 .equ TWAR =$02 .equ TWSR =$01 .equ TWBR =$00 ; ; **** Index-Register Definitions .def C0 =r8 ; Constant 0 .def C1 =r9 ; Constant 1 .def SHIFT0 =r10 ; 5B Shiftregister for Serial In/Out MSB .def SHIFT1 =r11 ; " .def SHIFT2 =r12 ; " .def SHIFT3 =r13 ; " LSB .def SHIFT4 =r14 ; " Check Byte .def XL =r26 .def XH =r27 .def YL =r28 .def YH =r29 .def ZL =r30 .def ZH =r31 ; ; **** Memory Sizes .equ RAMBEG =$60 ; First SRAM Location .equ RAMEND =$45F .equ FLASHEND =$FFF .equ E2END =$1FF ; ; **** Variablen *************************************************** .DSEG .ORG RAMBEG ; Start of RAM address range ($0060) ; ; ; ++ Zustands-Variablen FLATIM: .BYTE 1 ; Verbleibende Flashtime für Text-Flash (n * 100 ms) LEDTIM: .BYTE 1 ; Verbleibende Background-LED-On-Time (n * 1 s) SOUPNT: .BYTE 2 ; Pointer auf Soundstring LSB,MSB; Fertig bei MSB = 0 OUT4B: .BYTE 4 ; 4 Byte String -> Fuchs IN4B: .BYTE 4 ; 4 Byte String <- Fuchs CURPOS: .BYTE 1 ; Cursorposition 1.Zeile: 0..15, 2: 16..31, Aus: 32 ; Bit 7,6= 00:Underline, 10:dto,blink, 01:Block,blink MODE: .BYTE 1 ; Modus, right nibble is field # 0..n ; left nibble is screen: 0=Hex, 1=Program, ; 2=Fuchs, 3=Start, 4=Extras, 5=Top Menu, 6=Eichen ; 7=Ziel OLDSW: .BYTE 1 ; Vorheriger Zustand Sicher-Schalter 0/8 PROTO: .BYTE 1 ; Protokollsteuerung für IF zum Fuchs (OUT4B > F > IN4B) ; Protokoll wird alle 100 ms abgewickelt ; $01 = OUT4B Senden, -> $00 ; $10 = 'Read FOXID' senden, -> $12 ; $11 = 'Read Status' senden, -> $12 ; $12 = Keine Daten: Fehler, sonst in IN4B ->$00 ; $21 = auf volle Sek. warten, STA senden -> $31 ; $31 = Uhrzeit senden -> $41 ; $41 = Start-/Endezeit senden -> $22 ; $22 = auf halbe Sek. Warten, Read senden -> $23 ; $23 = auf 0,7 Sek. warten, STA gegen IN4B vergleichen -> $00 ; $21 ist Einstieg für Laden, $22 für Prüfen STA0: .BYTE 1 ; Status-Record wie im Fuchs - Definition dort STA1: .BYTE 1 ; " STA2: .BYTE 1 ; " STA3: .BYTE 1 ; " FOXID: .BYTE 1 ; Fuchs-Identität wie im Fuchs (Nr, Modulation) SHOTFG: .BYTE 1 ; Flags für Überprüfung vollständiges Laden bei Clone ; 1.Schuss setzt $60, 2. löscht Bit 5, 3. löscht Bit 6 ; ++ ASCII/BCD-Werte für Anzeigen BCD1: .BYTE 10 ; BCD-Werte für Display Zeile 1 BCD2: .BYTE 10 ; dto Zeile 2 UHRZ: .BYTE 6 ; Uhrzeit Dezimal hhmmss STARTZ: .BYTE 6 ; Startzeit hhmm(ss) ENDEZ: .BYTE 6 ; Endezeit hhmm(ss) NFUCHS: .BYTE 1 ; Zahl der Füchse 2..5 TFUCHS: .BYTE 1 ; Sendezeit / 10s (3 oder 6) AFUCHS: .BYTE 1 ; Aktueller Fuchs (wenn Fuchs Mode = 1) 1..5 AMOD: .BYTE 4 ; Modulation im Format SFFF, S = >/>>, FFF= A1/1k2/800/600 AVERS: .BYTE 1 ; SW-Level Fuchs HL TXSEC: .BYTE 1 ; Fuchssendetimer (wenn Fuchs Mode = 1) Z,E 0..59 ; ++ Analog-Werte UBAT: .BYTE 3 ; Batterie-Spannung in V/mV Z,E,h UBATF: .BYTE 3 ; Batterie-Spannung Fuchs in V/mV Z,E,h CFUB: .BYTE 1 ; Korrekturfaktor für UBAT Skalierung CFUBF: .BYTE 1 ; Korrekturfaktor für UBATF Skalierung ; Der Skalierungsfaktor ist $2000 + (CFUBf * $10) ; Im EEPROM Adr 0,1 wird CFUB,CFUBF exor $80 gesichert ;++ Display-Ansteuerung LCDDAT: .BYTE 32 ; Data to be displayed in LCD CURACT: .BYTE 1 ; Aktuelle Cursorposition (32 bei Flash, CURPOS bei Show) ; ++ Kommunikation mit Int.-Handler SWIFLG: .BYTE 1 ; Switch Flags, Bit 0=Up, 1=Down, 2=Up+Pressed, ; 3=Down+Pressed, 4=Drehdrücker Puls, 5=Zieltaster SERFLG: .BYTE 1 ; Serial I/F Flags: Bit 0 = RX complete, Bit 1 = Start TX ; Vertauschte Checksum (Clone) Bit 2 = RX complete, Bit 3 = Start TX TICK: .BYTE 1 ; 100 ms Timing Flag TACK: .BYTE 1 ; 1 s Timing Flag SOUFRQ: .BYTE 1 ; Frequenz für Lautsprecher-Piepsen Start-Mode ; ; Frequenz ist 2,4kHz / (SOUFRQ/4), 0 = Aus ; ; ++ Interrupt-Handler DEBP1: .BYTE 1 ; Debounce Counter Drehgeber DEBDD: .BYTE 1 ; Debounce Drücker Drehgeber DEBZT: .BYTE 1 ; Debounce Zieltaster TIK4k8: .BYTE 1 ; Zaehlt jede 4,8 kHz bis 4 (1,2 kHz) TIK1K2: .BYTE 1 ; Zaehlt jede 1200 Hz bis 120 (100 msec) TIK10: .BYTE 1 ; Zaehlt jede 100 msec bis 10 (1 s) SERCNT: .BYTE 1 ; Bitzähler für serielles Interface SOUCNT: .BYTE 1 ; Zähler für Lautsprecher-Tongenerator bis 2*SOUFRQ/4 ; ; ++ Zielzeiten-Registrierung ZZDATA: .BYTE 400 ; Registrierung von bis zu 100 Zielzeiten ; Jeder Record hat 4 Bytes: h, m, s, s/10 ; Je Byte 2 BCD: 10er in H, 1er in L Nibble ZZEND: .BYTE 1 ; Zahl der gültigen Entries 0=leer, 100=voll ZZDISP: .BYTE 1 ; Display Fenster Pointer, Bereich 0..ZZEND ; ; ; ********************** ; **** Macro Definitionen ****************************************** ; ********************** ; ; ++++ Store to SRAM Location @0 Immediate Value @1 ; USES R24 ! C0 resp. C1 are registers with Value 0 resp. 1 .MACRO STSI .IF @1==0 sts @0,C0 .ENDIF .IF @1==1 sts @0,C1 .ENDIF .IF @1>1 ldi R24,@1 sts @0,R24 .ENDIF .ENDMACRO ; ; ++++ Show Text String @0 .MACRO SHOW lds ZL,CURPOS ; Cursor-Position übergeben sts CURACT,ZL ldi ZL,low(2*@0) ; Ausgabe-Kommand-String ldi ZH,high(2*@0) rcall LCDSTR ; .. ausführen .ENDMACRO ; ; ++++ Flash Text String @0 for @1*100ms .MACRO FLASH ldi ZL,32 ; Cursor aus sts CURACT,ZL ldi ZL,low(2*@0) ; Ausgabe-Kommand-String ldi ZH,high(2*@0) rcall LCDSTR ; .. ausführen ldi ZL,@1 ; Flash Timer aufsetzen sts FLATIM,ZL ; .ENDMACRO ; ; ++++ Start Sound-String @0 .MACRO SOUND ldi ZL,low(2*@0) ; Sound-String sts SOUPNT,ZL ldi ZH,high(2*@0) sts SOUPNT+1,ZH .ENDMACRO ; ; ++++ High Nibble von @0 erhöhen/erniedrigen nach Bit 2/3 in R17 .MACRO udhi lds R16,@0 ldi R19,$10 sbrc R17,2 ; rechts drehen/drücken add R16,R19 sbrc R17,3 ; links sub R16,R19 sts @0,R16 .ENDMACRO ; ; ++++ Low Nibble von @0 erhöhen/erniedrigen nach Bit 2/3 in R17 .MACRO udlo lds R16,@0 mov R19,R16 andi R19,$F0 sbrc R17,2 ; rechts drehen/drücken inc R16 sbrc R17,3 ; links dec R16 andi R16,$0F or R16,R19 sts @0,R16 .ENDMACRO ; ; ; ******************** ; **** Code starts here ******************************************** ; ******************** .CSEG .ORG 0 ; ; ++++ Interrupt Vectors RJMP START ; 0 Reset RJMP START ; 1 Ext Int 0 RJMP START ; 2 Ext Int 1 RJMP START ; 3 Timer Compare 2 RJMP START ; 4 Timer Overflow 2 RJMP START ; 5 Input Capture 1 RJMP START ; 6 Timer Compare 1A RJMP START ; 7 Timer Compare 1B RJMP START ; 8 Timer Overflow 1 RJMP TIMINT ; 9 Timer Overflow 0 RJMP START ; $A SPI RJMP START ; $B USART Receive Complete RJMP START ; $C USART Data Reg. Empty RJMP START ; $D USART Transmit Complete RJMP START ; $E A/D-Converter RJMP START ; $F EEPROM RJMP START ;$10 Analog Comparator RJMP START ;$11 2-wire I/F RJMP START ;$12 SPM complete ; ; ; ; ***************************** ; **** Main Programm starts here ************************************* ; ***************************** ; ; ++++ Initialize Stackpointer to end of internal RAM START: ldi R16,LOW(RAMEND) out SPL,R16 ldi R16,HIGH(RAMEND) out SPH,R16 ; ; ++++ Initialize Constant Registers ; clr C0 ; Constant 0 clr C1 ; Constant 1 inc C1 ; ; ++++ Initialize RAM area ; clr XH ldi XL,LOW(RAMBEG) STA01: st X+,C0 cpi XL,LOW(RAMEND+1) brne STA01 cpi XH,HIGH(RAMEND+1) brne STA01 ; ; ++++ Initialize Port B Bit 0 as Output - Backlight on ; 1 as Output Sound (=OC1A) ; 2 as Input w/o Pull-Up Serial Link ; 3 as Output Fosc/4 (OC2) (Messpunkt) ; 4..5 used by ISP ldi R16,$0B out DDRB,R16 ldi R16,$00 out PORTB,R16 ; ; ++++ Initialize Port C Bit 0 as Analog In Ubatt Local ; 1 as Analog In Ubatt Remote ; 2 as Input Schalter Sicher w Pull-Up ; 3 as Input P0 w Pull-Up ; 4 as Input P1 w Pull-Up ; 5 as Input D w Pull-Up ldi R16,$00 out DDRC,R16 ldi R16,$3C out PORTC,R16 ; ; ++++ Initialize Port D Bit 0 as Input RXD ; Bit 1 as Output TXD ; Bit 2..7 as Output for Display ldi R16,$FE out DDRD,R16 ldi R16,$00 out PORTD,R16 ; ; ++++ Initialize A/D-Converter LDI R16,$00 ; Select Analog Input 0 OUT ADMUX,R16 LDI R16,$86 ; Enable ADC, Clock Divider 64 = 77 kHz OUT ADCSR,R16 ; = 180 usec Conversion Time ; ; ++++ Intialize Timer/Ctr 0 as 4800 Hz Timing Interrupt (4,9Mhz/256/16) ldi R16,$03 ; Set Clock Divider to 64 out TCCR0,R16 ldi R16,-16 ; Set Counter to Start-Value out TCNT0,R16 ldi R16,$01 out TIMSK,R16 ; Enable Counter 0 Overflow Interrupt ; ; ++++ Intialize Timer/Counter 1 as Variable Osc. for Acoustic S-Meter ; -- CTC-Mode on OC1A Pin, f is 4,91 MHz /2 /OCR1AH_L ldi R16,$00 ; $00 = Sound Off, $40 = On out TCCR1A,R16 ldi R16,$09 out TCCR1B,R16 ldi R16,$0A ; Komparator fuer Counter Reset & Output Toggle out OCR1AH,R16 ldi R16,0 ; $0A00 = 1 kHz Startwert out OCR1AL,R16 ; ; ++++ Intialize Timer/Counter 2 for Fosc/4 Measurement on OC2 ldi R16,$19 ; out TCCR2,R16 ldi R16,$01 out OCR2,R16 ; ; ++++ Initialize some Variables stsi STA0,$05 ; Vorlauf, 5 Füchse stsi STA1,$8B ; 60s, 2 h Gesamtsenden stsi STA2,$0E ; 1 h Vorlauf stsi STA3,$10 stsi MODE,$50 ; Top-Menü stsi LEDTIM,NACHLZ ; LED-Nachleuchtzeit auf Startwert stsi UHRZ+0,1 ; Uhrzeit auf 12:00 stellen stsi UHRZ+1,2 rcall CALSTZ ; Startzeit ausrechnen (Uhr + Vorlauf) rcall CALENZ ; Endezeit ausrechnen (Start + Laufzeit x 10') stsi NFUCHS,5 ; Anzeige 5 Füchse stsi TFUCHS,6 ; Anzeige je 60 sec ; rcall GETEEP ; Voltmeter Eichwerte XFUB/CFUBF aus EEPROM ; STA03: ; ; ++++ Start Interrupt Handler sei ; Global Interrupt enable ; ; ++++ Initialize LCD and show Start Text ldi R25,100 ; Wait 100 ms rcall DELXMS rcall INILCD flash STRPO,20 ldi R25,100 ; Wait 100 ms rcall DELXMS stsi SWIFLG,0 ; Clear any Drehgeber Flags sound SOUPO ; sbic PINC,5 ; Wenn Drehgeber gedrückt rjmp MAIN stsi MODE,$60 ; .. Voltmeter Eichen starten flash STRM61,20 sound SOUALA ; ; ************* ; **** Main Loop *************************************************** ; ************* ; MAIN: ; +++++++++++++++++++++++++++++++++++++++++++++++ ; +++ Sicher-Schalter und LED-Beleuchtung handeln +++++++++++++++ ; +++++++++++++++++++++++++++++++++++++++++++++++ ; Switch Flags werden in R17, Mode in R18 gehalten MAIN1: lds R17,SWIFLG stsi SWIFLG,0 tst R17 ; Wenn irgendein Flag breq M110 stsi LEDTIM,NACHLZ ; .. LED-Nachleuchtzeit auf Startwert stsi FLATIM,0 ; .. und Textflash beenden ; M110: in R16,PINC ; Sicher-Schalter einlesen andi R16,$04 lds R20,OLDSW ; Alten Schalterzustand holen sts OLDSW,R16 ; und neuen alten ablegen cp R16,R20 ; Wenn Schalter geändert breq M116 ; stsi LEDTIM,NACHLZ ; .. LED-Nachleuchtzeit auf Startwert stsi FLATIM,0 ; .. und Textflash beenden ; M116: lds R16,LEDTIM ; Wenn LEDTIM > 0 tst R16 breq M117 cbi PORTB,0 ; .. LED einschalten rjmp M118 M117: sbi PORTB,0 ; .. sonst ausschalten ; M118: sbic PINC,2 ; Wenn Schalter auf Sicher rjmp M399 ; .. kein Switch-Handling ausser Zielzeit ; ; ++++++++++++++++++++++++++++++++++++++++++++++++ ; +++ Modus mit rechts-/linksdrehen weiterschalten ++++++++++++++ ; ++++++++++++++++++++++++++++++++++++++++++++++++ MAIN2: lds R18,MODE mov R19,R18 ; High nibble ist Mode andi R19,$F0 ; Mode und Field trennen andi R18,$0F M200: cpi R19,$00 ; Wenn Mode 0 brne M201 ldi R16,13 ; .. 13 Felder M201: cpi R19,$10 ; Wenn Mode 1 brne M202 ; ldi R16,8 ; .. 8 Felder M202: cpi R19,$20 ; Wenn Mode 2 brne M203 ; ldi R16,5 ; .. 5 Felder M203: cpi R19,$30 ; Wenn Mode 3 brne M204 ; ldi R16,1 ; .. 1 Feld M204: cpi R19,$40 ; Wenn Mode 4 brne M205 ; ldi R16,7 ; .. 7 Felder M205: cpi R19,$50 ; Wenn Mode 5 brne M206 ; ldi R16,4 ; .. 4 Felder M206: cpi R19,$60 ; Wenn Mode 6 brne M207 ; ldi R16,3 ; .. 3 Felder M207: cpi R19,$70 ; Wenn Mode 7 brne M209 ; ldi R16,1 ; .. 1 Feld ; M209: sbrs R17,0 ; Rechts drehen rjmp M21 inc R18 ; Mode hochzählen cp R18,R16 brne M21 clr R18 ; M21: sbrs R17,1 ; Links drehen rjmp M22 dec R18 ; Mode runterzählen cpi R18,$FF brne M22 mov R18,R16 dec R18 ; M22: or R18,R19 ; Mode und Field wieder zusammenbauen sts MODE,R18 ; ; ++++++++++++++++++++++++++ ; +++ Aktionen je nach Modus +++++++++++++++++++++++++++++++++++ ; ++++++++++++++++++++++++++ MAIN3: lds R18,MODE cpi R18,0 ; Mode 0/0: Hex, zum Fuchs Senden brne M301 sbrs R17,4 ; .. und Click rjmp M301 ; M300: sound SOUPAP stsi PROTO,1 ; Senden anfordern ; M301: cpi R18,1 ; Mode 0/1: Hex Sendebyte 0 brne M302 udhi OUT4B+0 ; richtiges Nibble ändern M302: cpi R18,2 ; Mode 0/2 brne M303 udlo OUT4B+0 ; richtiges Nibble ändern M303: cpi R18,3 ; Mode 0/3 brne M304 udhi OUT4B+1 ; richtiges Nibble ändern M304: cpi R18,4 ; Mode 0/4 brne M305 udlo OUT4B+1 ; richtiges Nibble ändern M305: cpi R18,5 ; Mode 0/5 brne M306 udhi OUT4B+2 ; richtiges Nibble ändern M306: cpi R18,6 ; Mode 0/6 brne M307 udlo OUT4B+2 ; richtiges Nibble ändern M307: cpi R18,7 ; Mode 0/7 brne M308 udhi OUT4B+3 ; richtiges Nibble ändern M308: cpi R18,8 ; Mode 0/8: Hex Sendebyte 7 brne M309 udlo OUT4B+3 ; richtiges Nibble ändern ; M309: cpi R18,9 ; Mode 0/9: Hex TX Analyse brne M3091 sbic PINC,5 ; und Drücker gedrückt: TX-Record Analysieren M3091: rjmp M30A rcall TXANA ; M30A: cpi R18,$0A ; Mode 0/10: Hex Fuchs auslesen brne M30B sbrs R17,4 ; .. und Click rjmp M30B stsi PROTO,$11 ; Auslese-Protokoll starten sound SOUPAP ; Piepsen (tief) ; M30B: cpi R18,$0B ; Mode 0/11: Hex RX-Record Analyse brne M30B1 sbic PINC,5 ; und Drücker gedrückt: RX-Record Analysieren M30B1: rjmp M30C rcall RXANA ; M30C: cpi R18,$0C ; Mode 0/12: Hex<> -> Extras brne M310 sbrs R17,4 ; .. und Click rjmp M310 ldi R18,$45 ; Neuer Mode 4/5 sts MODE,R18 sound SOUPIP rjmp M399 ; M310: cpi R18,$10 ; Mode 1/0: Programm Uhrzeit h brne M311 sbrc R17,2 ; Drücken+drehen rcall IUHRZH ; Uhrzeit Stunde ändern sbrc R17,3 rcall DUHRZH sbrc R17,2 rcall INISTZ ; Und Startzeit auf Uhrzeit + 1 Stunde sbrc R17,3 rcall INISTZ ; M311: cpi R18,$11 ; Mode 1/1: Programm Uhrzeit min brne M312 sbrc R17,2 ; Drücken+drehen rcall IUHRZM ; Uhrzeit Minute ändern sbrc R17,3 rcall DUHRZM sbrc R17,2 rcall INISTZ ; Und Startzeit auf Uhrzeit + 1 Stunde sbrc R17,3 rcall INISTZ ; M312: cpi R18,$12 ; Mode 1/2: Programm Uhrzeit sec auf 0 brne M313 sbrc R17,4 ; Klicken rcall CUHRZS ; Uhrzeit Sekunde auf 0 sbrc R17,4 rcall INISTZ ; Und Startzeit auf Uhrzeit + 1 Stunde ; M313: cpi R18,$13 ; Mode 1/3: Programm Fuchsanzahl brne M314 lds R16,STA0 ; Fuchsanzahl holen mov R20,R16 ; .. und von Rest trennen andi R16,$07 andi R20,$F8 dec R16 ; 2..5 in Bereich 0..3 bringen dec R16 sbrc R17,2 ; Drücken+drehen inc R16 ; Fuchsanzahl ändern sbrc R17,3 dec R16 andi R16,$03 inc R16 ; Und STA-Record wieder zusammenbauen inc R16 or R16,R20 sts STA0,R16 ; M314: cpi R18,$14 ; Mode 1/4: Programm 30/60s brne M315 sbrs R17,4 ; Klicken rjmp M315 ; Sendedauer 30/60s toggeln lds R16,STA1 ldi R20,$80 eor R16,R20 sts STA1,R16 ; M315: cpi R18,$15 ; Mode 1/5: Programm Startzeit brne M316 sbrc R17,2 ; Drücken+drehen rcall ISTAZ ; Startzeit in 10-Minuten Schritten ändern sbrc R17,3 rcall DSTAZ ; M316: cpi R18,$16 ; Mode 1/6: Programm Endezeit brne M317 sbrc R17,2 ; Drücken+drehen rcall IENDZ ; Endezeit in 10-Minuten Schritten ändern sbrc R17,3 rcall DENDZ ; M317: cpi R18,$17 ; Mode 1/7: Programm -> Menü brne M320 sbrs R17,4 ; .. und Click rjmp M320 ldi R18,$50 ; Neuer Mode 5/0 sts MODE,R18 sound SOUPIP rjmp M399 ; M320: cpi R18,$20 ; Mode 2/0: Fuchs Laden brne M321 sbrs R17,4 ; .. und Click rjmp M321 stsi PROTO,$21 ; Status Record senden, empfangen und vergleichen sound SOUPIP flash STRWAR,20 ; Anzeige Warten ; M321: cpi R18,$21 ; Mode 2/1: Fuchs prüfen brne M322 sbrs R17,4 ; .. und Click rjmp M322 stsi PROTO,$22 ; Status Record empfangen und vergleichen sound SOUPIP flash STRWAR,20 ; Anzeige Warten ; M322: cpi R18,$22 ; Mode 2/2: Fuchs -> Menü brne M323 sbrs R17,4 ; .. und Click rjmp M323 ldi R18,$51 ; Neuer Mode 5/1 sts MODE,R18 sound SOUPIP rjmp M399 ; M323: cpi R18,$23 ; Mode 2/3: Fuchs -> Extras brne M324 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$46 ; Neuer Mode 4/6 sts MODE,R18 sts FOXID,C0 ; Fuchs ID noch unbekannt ldi R24,'?' sts AFUCHS,R24 sts AMOD+0,R24 sts AMOD+1,R24 sts AMOD+2,R24 sts AMOD+3,R24 sts AVERS,C0 sound SOUPAP rjmp M399 ; M324: cpi R18,$24 ; Mode 2/4: Fuchs Sendertest mit Mod brne M330 sbic PINC,5 ; .. und gedrückt rjmp M330 stsi OUT4B,$40 ; .. Sender einschalten mit Mod stsi PROTO,$01 ; M330: cpi R18,$30 ; Mode 3/0: Start -> Menü brne M340 sbrs R17,4 ; .. und Click rjmp M340 ldi R18,$52 ; Neuer Mode 5/2 sts MODE,R18 sound SOUPIP rjmp M399 ; M340: cpi R18,$40 ; Mode 4/0: Extras Fuchs# brne M341 mov R16,R17 ; Wenn gedrückt+gedreht andi R16,$0C breq M3405 lds R16,FOXID ; Fuchsnummer separieren und einstellen andi R16,$07 sbrc R17,2 inc R16 sbrc R17,3 dec R16 andi R16,$07 ; auf 0..7 begrenzen lds R20,FOXID ; Fuchsnummer in FOXID einsetzen und speichern andi R20,$38 or R20,R16 sts FOXID,R20 ; M3404: rcall DFOXID ; FOXID in Anzeigeformat dekodieren ldi R16,$C0 ; Lade FOXID Kommando bauen sts OUT4B,R16 lds R16,FOXID sts OUT4B+1,R16 stsi PROTO,$01 ; und senden lassen rjmp M3409 ; M3405: sbis PINC,5 ; Wenn Drehgeber nicht gedrückt rjmp M3409 lds R16,PROTO ; tst R16 ; und Proto auf null brne M3409 stsi PROTO,$10 ; Neues Read FOXID ; lds R16,SERFLG ; Wenn Receive complete andi R16,$01 breq M3409 lds R16,IN4B+1 ; Fuchs-ID holen sts FOXID,R16 lds R16,IN4B+2 ; Fuchs-Software-Level holen sts AVERS,R16 stsi SERFLG,0 ; und SERFLG löschen rcall DFOXID ; FOXID in Anzeigeformat dekodieren M3409: rjmp M399 ; M341: cpi R18,$41 ; Mode 4/1: Extras Modulation brne M342 mov R16,R17 ; Wenn gedrückt+gedreht andi R16,$0C breq M3405 lds R16,FOXID ; Modulation separieren und einstellen lsl R16 swap R16 andi R16,$07 sbrc R17,2 dec R16 sbrc R17,3 inc R16 andi R16,$07 ; auf 0..7 begrenzen lds R20,FOXID ; Modulation in FOXID einsetzen und speichern andi R20,$07 lsl R16 lsl R16 lsl R16 or R20,R16 sts FOXID,R20 rjmp M3404 ; Weiter wie bei Mode 4/0 ; M342: cpi R18,$42 ; Mode 4/2: Extras Sendertest brne M343 sbic PINC,5 ; .. und gedrückt rjmp M343 stsi OUT4B,$60 ; .. Sender einschalten ohne Mod stsi PROTO,$01 ; M343: cpi R18,$43 ; Mode 4/3: Extras Sendertest mit Mod. brne M344 sbic PINC,5 ; .. und gedrückt rjmp M344 stsi OUT4B,$40 ; .. Sender einschalten mit Mod stsi PROTO,$01 ; M344: cpi R18,$44 ; Mode 4/4: Oszillator messen brne M345 sbic PINC,5 ; .. und gedrückt rjmp M345 stsi OUT4B,$80 ; .. Oszillator-Mess-Mode starten stsi PROTO,$01 ; M345: cpi R18,$45 ; Mode 4/5: Extras -> Hex<> brne M346 sbrs R17,4 ; .. und Click rjmp M346 ldi R18,$0C ; Neuer Mode 0/12 sts MODE,R18 sound SOUPIP stsi SERFLG,0 ; Evtl nachhängende Flags (von Fuchs#) löschen rjmp M399 ; M346: cpi R18,$46 ; Mode 4/6: Extras -> Fuchs brne M350 sbrs R17,4 ; .. und Click rjmp M350 ldi R18,$23 ; Neuer Mode 2/3 sts MODE,R18 sound SOUPIP stsi SERFLG,0 ; Evtl nachhängende Flags (von Fuchs#) löschen rjmp M399 ; M350: cpi R18,$50 ; Mode 5/0: Menü -> Programm brne M351 sbrs R17,4 ; .. und Click rjmp M351 lds R16,STA0 ; Wenn Fuchsmode = 0 andi R16,$18 brne M3501 ldi R18,$17 ; .. Neuer Mode 1/7 sts MODE,R18 sound SOUPIP rjmp M399 ; M3501: flash STRM11,20 ; .. Sonst Fehlermeldung sound SOUALA rjmp M399 ; M351: cpi R18,$51 ; Mode 5/1: Menü -> Fuchs brne M352 sbrs R17,4 ; .. und Click rjmp M352 ldi R18,$22 ; Neuer Mode 2/2 sts MODE,R18 sound SOUPIP rjmp M399 ; M352: cpi R18,$52 ; Mode 5/2: Menü -> Start brne M353 sbrs R17,4 ; .. und Click rjmp M353 ldi R18,$30 ; Neuer Mode 3/0 sts MODE,R18 sound SOUPIP rcall MSTRT ; Anzeige vorbereiten rjmp M399 ; M353: cpi R18,$53 ; Mode 5/3: Menü -> Ziel brne M360 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$70 ; Neuer Mode 7/0 sts MODE,R18 sound SOUPIP lds R16,ZZEND ; Display-Pointer auf Ende -1 tst R16 breq M3531 dec R16 M3531: sts ZZDISP,R16 rjmp M399 ; M360: cpi R18,$60 ; Mode 6/0: Eichen Voltmeter Bediengerät brne M361 lds R16,CFUB sbrc R17,2 ; Drücken+drehen inc R16 ; Korrekturfaktor ändern sbrc R17,3 dec R16 sts CFUB,R16 ; M361: cpi R18,$61 ; Mode 6/1: Eichen Voltmeter Fuchs brne M362 lds R16,CFUBF sbrc R17,2 ; Drücken+drehen inc R16 ; Korrekturfaktor ändern sbrc R17,3 dec R16 sts CFUBF,R16 ; M362: cpi R18,$62 ; Mode 6/2: Eichen-> Hauptmenü brne M370 sbrs R17,4 ; .. und Click rjmp M370 rcall SAVEEP ; Eichwerte ins EEPROM speichern ldi R18,$50 ; Neuer Mode 5/0 sts MODE,R18 sound SOUOK rjmp M399 ; M370: cpi R18,$70 ; Mode 7/0: Ziel -> Menü brne M399 sbrs R17,4 ; .. und Click rjmp M3701 ldi R18,$53 ; .... Neuer Mode 5/3 sts MODE,R18 sound SOUPIP rjmp M399 M3701: lds R16,ZZDISP sbrs R17,0 ; Drehen ohne Drücken rjmp M3702 lds R18,ZZEND ; .. Display-Pointer ändern cp R16,R18 ; .. im Bereich 0 .. ZZEND breq M3702 inc R16 M3702: sbrs R17,1 rjmp M3703 tst R16 breq M3703 dec R16 M3703: sts ZZDISP,R16 rjmp M399 ; M399: sbrs R17,5 ; Wenn Zieltaster Click rjmp M3999 rcall ZZREG ; .. Zielzeit registrieren rcall ZZCONV ; .. Zielzeiten aus Tabelle holen flash STRM7,50 ; .. und 5 Sekunden zeigen M3999: ; ; ; ++++++++++++++++++++++++++ ; +++ Clonen abhandeln +++++++++++++++++++++++++++++++++++ ; ++++++++++++++++++++++++++ ; MAIN51: lds R16,SERFLG ; Wenn RX complete mit vertauschter Checksum andi R16,$04 breq M519X M511: stsi SERFLG,0 ; .. Semaphore löschen sbic PINC,2 ; Wenn Schalter auf Sicher M519X: rjmp M519 ; .. kein Clonen lds R16,MODE ; Wenn Mode <> Hauptmenü oder Hex andi R16,$F0 breq M512 cpi R16,$50 brne M519X ; .. kein Clonen ; M512: lds R16,IN4B+0 ; .. Command holen andi R16,$E0 brne M515 ; .. Wenn Command 0 = Lade Status stsi SHOTFG,$60 ; .... Schuss-Prüf-Flags auf Startwert $60 lds R16,IN4B+0 ; .... Shiftregister nach Status kopieren sts STA0,R16 andi R16,$07 ; .... NFUCHS setzen sts NFUCHS,R16 lds R16,IN4B+1 sts STA1,R16 ldi R17,3 ; .... TFUCHS setzen sbrc R16,7 ldi R17,6 sts TFUCHS,R17 lds R16,IN4B+2 sts STA2,R16 lds R16,IN4B+3 sts STA3,R16 stsi TIK10,0 ; .... Uhr auf volle Sekunde + 40 ms setzen stsi TIK1K2,50 rjmp M519 ; M515: cpi R16,$20 ; Wenn Command $2x = Read brne M516 lds SHIFT0,STA0 ; .... Status nach SHIFT kopieren lds R16,SHOTFG ; .... Schusszähler dazu, soll $00 sein or SHIFT0,R16 lds SHIFT1,STA1 lds SHIFT2,STA2 lds SHIFT3,STA3 stsi SERFLG,8 ; .... Interrupthandler mit Senden beauftragen rjmp M519 ; M516: lds R16,IN4B+0 ; Wenn Command = $Ex andi R16,$F0 cpi R16,$E0 brne M517 lds R16,IN4B+1 ; .. dann Byte 1..3 in 6B Uhrzeit expandieren rcall UNPK12 sts UHRZ+0,R16 sts UHRZ+1,R17 lds R16,IN4B+2 rcall UNPK12 sts UHRZ+2,R16 sts UHRZ+3,R17 lds R16,IN4B+3 rcall UNPK12 sts UHRZ+4,R16 sts UHRZ+5,R17 lds R16,SHOTFG ; Schuss-Flags Bit 5 löschen andi R16,$40 sts SHOTFG,R16 rjmp M519 ; M517: cpi R16,$F0 ; Wenn Command = $Fx brne M519 lds R16,IN4B ; Untere Hälfte von Byte 0 andi R16,$0F sts AFUCHS,R16 ; .. ist Aktueller Fuchs lds R16,IN4B+1 ; .. Byte 1..3 in 6B Start-/Endezeit expandieren rcall UNPK12 sts STARTZ+0,R16 sts STARTZ+1,R17 lds R16,IN4B+2 rcall UNPK12 sts START+2,R16 sts ENDEZ+0,R17 lds R16,IN4B+3 rcall UNPK12 sts ENDEZ+1,R16 sts ENDEZ+2,R17 lds R16,SHOTFG ; Schuss-Flags Bit 6 löschen andi R16,$20 sts SHOTFG,R16 sound SOUOK ; .... und signalisieren flash STRCLO,20 ; M519: rjmp MAIN4 ; UNPK12: mov R17,R16 ; 1 B in R16 in 2 nibble in R16, R17 expandieren swap R16 andi R16,$0F andi R17,$0F ret ; ; ++++++++++++++++++++++++++++++++++++++++++++ ; ++++ Status/Uhrzeit Update zur vollen Sekunde ++++++++++++++++ ; ++++++++++++++++++++++++++++++++++++++++++++ MAIN4: lds R16,TACK ; 1 s Flag testen tst R16 breq M49 stsi TACK,0 ; lds R16,LEDTIM ; LED-Nachleuchtzeit handeln tst R16 ; Wenn > 0 breq M42 dec R16 ; .. dekrementieren sts LEDTIM,R16 ; M42: lds R16,MODE ; Wenn Modus = Start .. cpi R16,$30 brne M43 rcall MSTRT ; .. Start-Töne und Display erzeugen ; M43: rcall NXTSTA ; Status-Record weiterzählen ; rcall IUHRZS ; Uhrzeit 1s erhöhen ; M49: ; ; ++++++++++++++++++++++++++++++++++ ; ++++ Alles weitere nur alle 100 ms: ++++++++++++++ ; ++++++++++++++++++++++++++++++++++ ; MAIN5: lds R16,TICK ; 100 ms Flag testen tst R16 brne M501 rjmp MAIN7 M501: sts TICK,C0 ; rcall SOUGEN ; Soundgenerator handeln ; ; +++++++++++++++++++++++++++++++++++ ; +++ Batterie-Spannungen A/D-wandlen ++++++++++++++++++++++++++++ ; +++++++++++++++++++++++++++++++++++ ; MAIN52: lds R16,TIK10 ; Jeweils im Wechsel Kanal 0 und 1 andi R16,$01 sbrs R16,0 lds R18,CFUB ; Richtiger Scaling Factor sbrc R16,0 lds R18,CFUBF rcall ANACON ; A/D-wandeln und skalieren nach R16 rcall B3BCD ; Nach BCD wandeln in R1,2,3 lds R16,TIK10 ; Je nach Kanalnummer sbrc R16,0 rjmp M521 sts UBAT,R1 ; .. ist Ergebnis UBat Bediengerät sts UBAT+1,R2 sts UBAT+2,R3 rjmp M529 M521: sts UBATF,R1 ; .. bzw. UBat Fuchs sts UBATF+1,R2 sts UBATF+2,R3 M529: ; ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; +++ Handeln der Übertragung Bediengerät <> Fuchs gemäß PROTO +++ ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MAIN53: lds R16,PROTO cpi R16,$01 ; $01 = OUT4B senden breq M5301 cpi R16,$10 ; $10 = Read FOXID senden breq M5310 cpi R16,$11 ; $11 = Read Status senden breq M5311 cpi R16,$12 ; $12 = Kein Empfang = Fehlermeldung brne M53021 rjmp M5312 M53021: cpi R16,$21 ; $21 = zur vollen Sek. STA senden brne M53031 rjmp M5321 M53031: cpi R16,$31 ; $31 = Uhrzeit senden brne M53041 rjmp M5331 M53041: cpi R16,$41 ; $41 = Start-/Endezeit senden brne M53022 rjmp M5341 M53022: cpi R16,$22 ; $22 = zur halben Sek Read senden brne M53023 rjmp M5322 M53023: cpi R16,$23 ; $23 = Empfangenen Record prüfen brne M53099 rjmp M5323 M53099: stsi PROTO,0 ; Kein gültiger Zustand, löschen rjmp M539 ; und fertug ; M5301: lds SHIFT0,OUT4B+0 ; Command kopieren lds SHIFT1,OUT4B+1 lds SHIFT2,OUT4B+2 lds SHIFT3,OUT4B+3 stsi SERFLG,2 ; TX Start Flag für OUT4B senden stsi PROTO,0 ; und Flag löschen rjmp M539 ; M5310: ldi R24,$A0 ; Read FOXID Command mov SHIFT0,R24 stsi SERFLG,2 ; .. senden stsi PROTO,$12 ; Protokoll weiterschalten rjmp M539 ; M5311: ldi R24,$20 ; Read Status Command mov SHIFT0,R24 stsi SERFLG,2 ; .. senden stsi PROTO,$12 ; Protokoll weiterschalten rjmp M539 ; M5312: lds R16,SERFLG ; Read complete? andi R16,1 brne M5312X flash STRTOT,10 ; .. Nein: Timeout-Message flashen sound SOUPAP ; .. und piepsen sts FOXID,C0 ; Fuchs ID und Anzeigen löschen sts AFUCHS,C0 ldi R24,'?' sts AMOD+0,R24 sts AMOD+1,R24 sts AMOD+2,R24 sts AMOD+3,R24 sts AVERS,C0 M5312X: stsi PROTO,$00 ; Protokoll auf fertig rjmp M539 ; M5321: lds R16,TIK10 ; Warten auf volle Sekunde cpi R16,0 breq M5321A rjmp M539 M5321A: lds R16,STA0 ; Command kopieren andi R16,$1F ; Command 0 mov SHIFT0,R16 lds SHIFT1,STA1 lds SHIFT2,STA2 lds SHIFT3,STA3 stsi SERFLG,2 ; .. Command senden stsi PROTO,$31 ; .. und Protokoll weiter M539X: rjmp M539 ; M5331: ldi R24,$E0 ; Command Lade Uhrzeit (für Clone) senden mov SHIFT0,R24 lds SHIFT1,UHRZ ; 6 Byte Uhrzeit in 3 Byte packen swap SHIFT1 lds R17,UHRZ+1 or SHIFT1,R17 lds SHIFT2,UHRZ+2 swap SHIFT2 lds R17,UHRZ+3 or SHIFT2,R17 lds SHIFT3,UHRZ+4 swap SHIFT3 lds R17,UHRZ+5 or SHIFT3,R17 stsi SERFLG,2 ; Senden stsi PROTO,$41 ; Protokoll weiterschalten rjmp M539 ; M5341: lds R24,AFUCHS ; Command Lade Aktueller Fuchs, Start-, Endezeit senden ori R24,$F0 ; Command mit Aktueller Fuchs zusammenpacken mov SHIFT0,R24 lds SHIFT1,STARTZ ; 6 Byte Start-/Endezeit in 3 Byte packen swap SHIFT1 lds R17,STARTZ+1 or SHIFT1,R17 lds SHIFT2,STARTZ+2 swap SHIFT2 lds R17,ENDEZ or SHIFT2,R17 lds SHIFT3,ENDEZ+1 swap SHIFT3 lds R17,ENDEZ+2 or SHIFT3,R17 stsi SERFLG,2 ; Senden stsi PROTO,$22 ; Protokoll weiterschalten rjmp M539 ; M5322: lds R16,TIK10 ; Warten auf halbe Sekunde cpi R16,5 brne M539Y ldi R24,$20 ; Read Command senden mov SHIFT0,R24 stsi SERFLG,2 ; Senden stsi PROTO,$23 ; Protokoll weiterschalten M539Y: rjmp M539 ; M5323: lds R16,SERFLG ; Read complete? andi R16,1 brne M5323B flash STRTOT,10 ; .. Nein: Timeout-Message flashen sound SOUNOK ; .. und piepsen rjmp M5323X M5323B: lds R16,IN4B ; Ja, Fuchsnummer separieren swap R16 ror R16 andi R16,$07 sts AFUCHS,R16 lds R17,UBATF+1 ; Wenn UBatFuchs = 0 V, d.h. FoxPro angeschlossen tst R17 brne M5323D stsi AFUCHS,'F' ; .. als Fuchs-Nr. 'F' anzeigen tst R16 ; .. die Fuchs# ist Shot-Flags und soll 0 sein brne M5323F M5323D: lds R16,IN4B ; Empfangenen Record mit STA vergleichen andi R16,$1F lds R20,STA0 andi R20,$1F cp R16,R20 brne M5323F lds R16,IN4B+1 lds R20,STA1 cp R16,R20 brne M5323F lds R16,IN4B+2 lds R20,STA2 cp R16,R20 brne M5323F lds R16,IN4B+3 lds R20,STA3 cp R16,R20 brne M5323F flash STROK,20 ; Ergebnis ok anzeigen sound SOUOK rjmp M5323X ; M5323F: flash STRNOK,20 ; Ergebnis nicht ok anzeigen sound SOUNOK ; M5323X: stsi PROTO,$00 ; Protokoll auf fertig rjmp M539 ; M539: ; ; Nur in Mode 0: Piepsen bei RX complete MAIN55: lds R16,MODE ; Wenn Mode = 0 andi R16,$F0 brne M559 lds R16,SERFLG ; und RX complete Flag gesetzt andi R16,$05 breq M559 sts SERFLG,C0 ; .. Flag löschen sound SOUPIP ; Piepsen M559: ; ; ++++++++++++++++++++++++++++++ ; ++++ Je nach Mode Display laden +++++++++++++++++++++++++++++ ; ++++++++++++++++++++++++++++++ MAIN6: lds R17,FLATIM ; Flash-Timer > 0 tst R17 breq M60 dec R17 ; .. dann dekrementieren sts FLATIM,R17 rjmp M6M9 ; .. und Display nicht ändern ; ; ++ Kein Flash: Mode-abhängige Cursor-Position laden M60: ldi ZL,low(2*CURTAB) ; Pointer auf Cursor-Tabelle ldi ZH,high(2*CURTAB) lds R16,MODE ldi R17,32 ; Default-Cursor-Poition: Aus ; M61: lpm ; Get Mode Entry from table adiw ZL,1 ; Increment Pointer mov R18,R0 lpm ; Get Cursor Position entry adiw ZL,1 ; Increment Pointer cpi R18,$FF ; $FF = Tabellenende breq M69 cp R18,R16 ; Aktueller Modus = Tabellenentry? brne M61 ; Nein: weiterscannen mov R17,R0 ; Ja: Cursorposition aus Tabelle übernehmen M69: sts CURPOS,R17 ; ; +++ Zum aktuellen Mode gehörenden Display-String zeigen M6M: lds R16,MODE ; Aktuellen Mode holen andi R16,$F0 sbic PINC,2 ; Wenn Schalter auf Sicher rjmp M6MX ; .. Zustandsanzeige ; M6M0: cpi R16,$00 ; Mode 0 brne M6M1 show STRM0 ; M6M1: cpi R16,$10 ; Mode 1 brne M6M2 rcall CALSTZ ; Startzeit ausrechnen (Uhr + Vorlauf) rcall CALENZ ; Endezeit ausrechnen (Start + Laufzeit x 10') lds R16,STA0 ; Fuchsanzahl aus STA holen andi R16,$07 sts NFUCHS,R16 lds R16,STA1 ; Sendedauer 30/60 s aus STA holen ldi R20,3 sbrc R16,7 ldi R20,6 sts TFUCHS,R20 show STRM1 ; M6M2: cpi R16,$20 ; Mode 2 brne M6M3 show STRM2 ; M6M3: cpi R16,$30 ; Mode 3 brne M6M4 show STRM3 ; M6M4: cpi R16,$40 ; Mode 4 brne M6M5 show STRM4 ; M6M5: cpi R16,$50 ; Mode 5 brne M6M6 show STRM5 ; M6M6: cpi R16,$60 ; Mode 6 brne M6M7 show STRM6 ; M6M7: cpi R16,$70 ; Mode 7 brne M6M9 rcall ZZCONV ; Zielzeiten aus Tabelle holen show STRM7 rjmp M6M9 ; M6MX: stsi CURPOS,32 ; Schalter auf Sicher, Cursor aus lds R16,STA0 ; Fuchsmode holen andi R16,$18 ; und separieren ; M6MX0: cpi R16,$00 ; Fuchs Modus 0 brne M6MX1 show STRMX0 ; M6MX1: cpi R16,$08 ; Fuchs Modus 1 brne M6MX2 lds R20,STA2 ; Aktuellen Fuchs separieren andi R20,$07 sts AFUCHS,R20 show STRMX1 ; M6MX2: cpi R16,$10 ; Fuchs Modus 2 brne M6M9 show STRMX2 ; M6M9: ; ; +++ Ende 100 ms Service MAIN7: ldi R16,$80 ; Sleep Mode enablen out MCUCR,R16 sleep ; .. und schlafen bis zum nächsten 4,8kHz Event ; MAIN99: rjmp MAIN ; ; *************** ; **** Subroutines ************************************************* ; *************** ; ; ################################# ; #### Binär-BCD ´konvertieren ############################### ; ################################# ; ; Byte in R16 in 3 BCD in R1 (H), R2, R3 (L) wandeln B3BCD: push R17 ldi R17,10 clr R1 ; BCD-Startwert 000 clr R2 clr R3 inc R16 ; B3BC1: dec R16 ; Loop bis R16 auf 0 breq B3BC9 inc R3 cp R3,R17 brne B3BC1 clr R3 inc R2 cp R2,R17 brne B3BC1 clr R2 inc R1 rjmp B3BC1 ; B3BC9: pop R17 ret ; ; Bytes in ZH/ZL in 5 BCD in R1 (H), R2, R3, R4, R5 (L) wandeln BB5BCD: push R17 clr R1 ; BCD-Startwert 00000 clr R2 clr R3 clr R4 clr R5 ldi R17,10 adiw ZL,1 ; BB5BC1: sbiw ZL,1 ; Loop bis Z auf 0 breq BB5BC9 inc R5 cp R5,R17 brne BB5BC1 clr R5 inc R4 cp R4,R17 brne BB5BC1 clr R4 inc R3 cp R3,R17 brne BB5BC1 clr R3 inc R2 cp R2,R17 brne BB5BC1 clr R2 inc R1 rjmp BB5BC1 ; BB5BC9: pop R17 ret ; ; #################################### ; #### Zielzeit registrieren und zeigen ############################# ; #################################### ; ; +++ Einen Zielzeit-Entry mit aktueller Zeit nach ZZDATA ZZREG: lds R16,ZZEND ; Pointer auf letzten Entry cpi R16,99 ; Wenn Voll brne ZZREG1 sound SOUALA ; .. Sonderton und abbrechen rjmp ZZREG9 ; ZZREG1: sound SOUPAP ; Normal-Quittungston ldi YL,low(ZZDATA) ; Pointer auf nächsten Entry in ZZDATA bauen ldi YH,high(ZZDATA) ; @ZZDATA + 4 * ZZEND ZZREG2: tst R16 breq ZZREG3 adiw YL,4 dec R16 rjmp ZZREG2 ; ZZREG3: lds R16,ZZEND ; ZZEND inkrementieren inc R16 sts ZZEND,R16 dec R16 ; Display Pointer auf letzte beide Entries sts ZZDISP,R16 ; lds R16,UHRZ ; Uhrzeit komprimieren und in ZZDATA ablegen swap R16 lds R19,UHRZ+1 or R16,R19 st Y+,R16 lds R16,UHRZ+2 swap R16 lds R19,UHRZ+3 or R16,R19 st Y+,R16 lds R16,UHRZ+4 swap R16 lds R19,UHRZ+5 or R16,R19 st Y+,R16 lds R16,TIK10 st Y+,R16 ; ZZREG9: ret ; ; +++ Zielzeitentries ZZDISP und ZZDISP+1 konvertieren für Anzeige ZZCONV: lds R16,ZZDISP dec R16 ldi YL,low(ZZDATA) ; Pointer auf Anzeige-Entry 1 in ZZDATA bauen ldi YH,high(ZZDATA) ; @ZZDATA + 4 * ZZEND ZZCON2: tst R16 breq ZZCON3 adiw YL,4 dec R16 rjmp ZZCON2 ; ZZCON3: ldi ZL,low(BCD1) ; Pointer auf Anzeigewerte Zeile 1 ldi ZH,high(BCD1) lds R16,ZZDISP ; Nummer des Entries rcall ZZCV1L ; 1. Zeile konvertieren ldi ZL,low(BCD2) ; Pointer auf Anzeigewerte Zeile 2 ldi ZH,high(BCD2) lds R16,ZZDISP ; Nummer des 2ten Entries inc R16 rcall ZZCV1L ; 2. Zeile konvertieren ; ret ; ; Werte in R16 und @Y für Anzeige konvertieren nach @Z ZZCV1L: cpi R16,0 ; Wenn Entry-Nummer = 0 brne ZZVC12 ldi R16,'-' ; Pfeile nach unten zeigen rjmp ZZVC13 ; ZZVC12: lds R17,ZZEND ; Wenn Entry-Nummer = ZZEND+1 inc R17 cp R16,R17 brne ZZVC14 ldi R16,'^' ; Pfeile nach oben zeigen ZZVC13: st Z+,R16 st Z+,R16 st Z+,R16 st Z+,R16 st Z+,R16 st Z+,R16 st Z+,R16 st Z+,R16 st Z+,R16 adiw YL,4 ; Y auf nächsten ZZDATA-Entry rjmp ZZCV19 ; ZZVC14: rcall B3BCD ; Nummer des Entries (R16) nach BCD in R2,R3 st Z+,R2 st Z+,R3 rcall ZZCVUN ; Unpack Stunden rcall ZZCVUN ; Unpack Minuten rcall ZZCVUN ; Unpack Sekunden ld R16,Y+ ; Zehntel Sekunden kopieren st Z+,R16 ; ZZCV19: ret ; Ein Byte mit 2 BCD @Y+ entpacken und nach @Z+,@Z+ schreiben ZZCVUN: ld R16,Y+ ; Gepackten Entry holen mov R17,R16 ; .. und entpacken swap R16 andi R16,$0F andi R17,$0F st Z+,R16 st Z+,R17 ret ; ; ################################# ; #### Variablen ändern und anzeigen ############################### ; ################################# ; ; +++ Funktionen zur vollen Sekunde im Start-Modus ; MSTRT: push R17 lds R16,STA0 ; Wenn Fuchsmodus <> Senden andi R16,$18 cpi R16,$08 breq MSTR1 stsi MODE,$52 ; .. zurück ins Menü flash STRM31,20 ; .. und Fehlermeldung sound SOUALA rjmp MSTR9 ; MSTR1: sbic PINC,2 ; Wenn Schalter auf Sicher rjmp MSTR9 ; .. keine Starttöne MSTR2: lds R16,STA2 ; Aktuellen Fuchs separieren andi R16,$07 sts AFUCHS,R16 ; .. und für Anzeige ablegen ; lds R18,NFUCHS ; Restdurchgänge bis Start in R18 sub R18,R16 ; ldi R16,59 ; Restzeit in Sekunden in R16 lds R19,STA1 ; Wenn Durchgang = 30 s andi R19,$80 brne MSTR3 sbrs R18,0 ; .. Dann Restminuten = Restdurchgänge/2 ldi R16,29 lsr R18 MSTR3: lds R17,STA3 ; Aktuelle Sekunde abziehen andi R17,$3F sub R16,R17 mov R17,R16 ; .. und in R17 retten ; sts BCD2,R18 ; Minuten ablegen für Display rcall B3BCD ; Sekunden in Hex wandeln sts BCD2+1,R2 ; .. und ablegen für Display sts BCD2+2,R3 ; cpi R18,1 ; Zur Zeit - 1 min brne MSTR4 cpi R17,0 brne MSTR4 sound SOU1MI ; Vor-Alarm 1 ; MSTR4: cpi R18,0 ; In der letzten Minute brne MSTR9 cpi R17,10 ; Zur Zeit - 10 s brne MSTR41 sound SOU10S ; .. Vor-Alarm 2 rjmp MSTR9 ; MSTR41: cpi R17,0 ; Zur Zeit - 0 s brne MSTR42 sound SOU0S ; .. Startsignal rjmp MSTR9 ; MSTR42: cpi R17,5 ; Zur Zeit - 4,3,2,1 s brcc MSTR9 sound SOUNS ; .. Sekundenpiepser ; MSTR9: pop R17 ret ; ; +++ Uhr um eine Sekunde/Minute/Stunde weiterschalten ; IUHRZS: lds R16,UHRZ+5 ; Sekunden erhöhen inc R16 sts UHRZ+5,R16 cpi R16,10 breq INCU1 INCU19: rjmp INCU9 INCU1: stsi UHRZ+5,0 INCU2: lds R16,UHRZ+4 ;10er Sekunden erhöhen inc R16 sts UHRZ+4,R16 cpi R16,6 brne INCU19 stsi UHRZ+4,0 IUHRZM: lds R16,UHRZ+3 ; Minuten erhöhen inc R16 sts UHRZ+3,R16 cpi R16,10 brne INCU19 stsi UHRZ+3,0 lds R16,UHRZ+2 ;10er Minuten erhöhen inc R16 sts UHRZ+2,R16 cpi R16,6 brne INCU9 stsi UHRZ+2,0 IUHRZH: lds R16,UHRZ+1 ;Stunde erhöhen lds R19,UHRZ cpi R16,3 ;Wenn Stunde = 23 brne INCU5 cpi R19,2 brne INCU5 stsi UHRZ+1,0 ;.. Stunden auf 00 setzen stsi UHRZ,0 rjmp INCU9 INCU5: inc R16 ;.. sonst Stunde erhöhen sts UHRZ+1,R16 cpi R16,10 brne INCU9 stsi UHRZ+1,0 inc R19 ; .... und Stunde 10er erhöhen sts UHRZ,R19 INCU9: ret ; ; +++ Uhrzeit Sekunden auf 0 setzen CUHRZS: stsi UHRZ+5,0 stsi UHRZ+4,0 ret ; ; +++ Uhrzeit um 1 Minute/Stunde verringern DUHRZM: lds R16,UHRZ+3 ;Minuten dec R16 sts UHRZ+3,R16 cpi R16,-1 brne DECU9 stsi UHRZ+3,9 lds R16,UHRZ+2 ;10er Minuten dec R16 sts UHRZ+2,R16 cpi R16,-1 brne DECU9 stsi UHRZ+2,5 DUHRZH: lds R16,UHRZ+1 ;Stunde lds R19,UHRZ cpi R16,0 ;Wenn Stunde = 00 brne DECU5 cpi R19,0 brne DECU5 stsi UHRZ+1,3 ;.. Stunden auf 23 setzen stsi UHRZ,2 rjmp DECU9 DECU5: dec R16 ;.. sonst Stunde runterzählen sts UHRZ+1,R16 cpi R16,-1 brne DECU9 stsi UHRZ+1,9 dec R19 ; .... Stunde 10er sts UHRZ,R19 DECU9: ret ; ; +++ Berechne Dezimale Startzeit aus Uhrzeit + Vorlauf ; CALSTZ: lds ZL,STA3 ; Vorlauf in Sekunden laden lds ZH,STA2 adiw ZL,1 ; Vorlauf erst mal um 1 erhöhen lds R16,UHRZ ; Uhrzeit nach Startzeit kopieren sts STARTZ,R16 lds R16,UHRZ+1 sts STARTZ+1,R16 lds R16,UHRZ+2 sts STARTZ+2,R16 lds R16,UHRZ+3 sts STARTZ+3,R16 lds R16,UHRZ+4 sts STARTZ+4,R16 lds R20,UHRZ+5 ; Sekunden einer in Register halten rjmp CSTZ0 ; CSTZ91: rjmp CSTZ9 ; CSTZ0: sbiw ZL,1 ; Vorlauf um 1 verringern breq CSTZ91 ; .. bis auf 0 inc R20 ; Sekunden Einer erhöhen cpi R20,10 brne CSTZ0 clr R20 lds R16,STARTZ+4 ; 10er Sekunden erhöhen inc R16 sts STARTZ+4,R16 cpi R16,6 brne CSTZ0 stsi STARTZ+4,0 lds R16,STARTZ+3 ; Minuten erhöhen inc R16 sts STARTZ+3,R16 cpi R16,10 brne CSTZ0 stsi STARTZ+3,0 lds R16,STARTZ+2 ; 10er Minuten erhöhen inc R16 sts STARTZ+2,R16 cpi R16,6 brne CSTZ0 stsi STARTZ+2,0 lds R16,STARTZ+1 ; Stunde erhöhen lds R19,STARTZ cpi R16,3 ; Wenn Stunde = 23 brne CSTZ5 cpi R19,2 brne CSTZ5 stsi STARTZ+1,0 ;.. Stunden auf 00 setzen stsi STARTZ,0 rjmp CSTZ0 CSTZ5: inc R16 ;.. sonst Stunde erhöhen sts STARTZ+1,R16 cpi R16,10 brne CSTZ01 stsi STARTZ+1,0 inc R19 ; .... und Stunde 10er erhöhen sts STARTZ,R19 CSTZ01: rjmp CSTZ0 ; CSTZ9: sts STARTZ+5,R20 ; Sekunden Einer ablegen ret ; ; +++ Setze Startzeit auf Startzeit + 1h, abgerundet auf ganze 10' ; INISTZ: ldi XH,high(3600) ; Basis-Delay 3600 sec ldi XL,low(3600) lds R20,UHRZ+5 ; Uhrzeit 1er Sekunden abziehen ldi R21,0 sub XL,R20 sbc XH,R21 lds R16,UHRZ+4 ; Uhrzeit 10er Sekunden * 10 abziehen ldi R20,10 INIST1: tst R16 ; Zeit ist Loopcounter breq INIST2 dec R16 sub XL,R20 ; 10 abziehen sbc XH,R21 rjmp INIST1 INIST2: lds R16,UHRZ+3 ; Uhrzeit 1er Minuten * 60 abziehen ldi R20,60 INIST3: tst R16 ; Zeit ist Loopcounter breq INIST4 dec R16 sub XL,R20 ; 10 abziehen sbc XH,R21 rjmp INIST3 INIST4: sts STA2,XH ; Rechenergebnis ist Vorlauf in STA sts STA3,XL ret ; ;+++ Startzeit um 10' erhöhen ISTAZ: lds XH,STA2 ; Start-Delay aus STA holen lds XL,STA3 ldi R20,High(600) ; 600 addieren ldi R21,low(600) add XL,R21 adc XH,R20 brcs ISTAZ9 ; Wenn Ergebnis nicht über $FFFF überläuft sts STA2,XH ; .. in STA ablegen sts STA3,XL ISTAZ9: ret ; ;+++ Startzeit um 10' verringern DSTAZ: lds XH,STA2 ; Start-Delay aus STA holen lds XL,STA3 ldi R20,High(600) ; 600 abziehen ldi R21,low(600) sub XL,R21 sbc XH,R20 brcs DSTAZ9 ; Wenn Ergebnis > 0 sts STA2,XH ; .. in STA ablegen sts STA3,XL DSTAZ9: ret ; ; +++ Berechne Dezimale Endezeit aus Startzeit + n x 10' ; CALENZ: lds R16,STARTZ ; Startzeit nach Endezeit kopieren sts ENDEZ,R16 lds R16,STARTZ+1 sts ENDEZ+1,R16 lds R16,STARTZ+2 sts ENDEZ+2,R16 lds R16,STARTZ+3 sts ENDEZ+3,R16 lds R20,STA1 ; Zahl der Durchgänge separieren andi R20,$7F inc R20 ; 0 bedeutet 1 Durchgang ; CENZ0: tst R20 ; Durchgänge zählen breq CENZ9 dec R20 lds R16,ENDEZ+2 ; 10er Minuten erhöhen inc R16 sts ENDEZ+2,R16 cpi R16,6 brne CENZ0 stsi ENDEZ+2,0 lds R16,ENDEZ+1 ; Stunde erhöhen lds R19,ENDEZ cpi R16,3 ; Wenn Stunde = 23 brne CENZ5 cpi R19,2 brne CENZ5 stsi ENDEZ+1,0 ;.. Stunden auf 00 setzen stsi ENDEZ,0 rjmp CENZ0 CENZ5: inc R16 ;.. sonst Stunde erhöhen sts ENDEZ+1,R16 cpi R16,10 brne CENZ0 stsi ENDEZ+1,0 inc R19 ; .... und Stunde 10er erhöhen sts ENDEZ,R19 rjmp CENZ0 ; CENZ9: ret ; ; +++ Erhöhe Sendezeit um 10 Minuten IENDZ: lds R16,STA1 ; Sendezeit aus STA holen mov R20,R16 andi R16,$7F inc R16 ; um 1 x 10' erhöhen cpi R16,120 ; auf max 119 = 20h breq IENDZ9 sbrc R20,7 ; STA-Record wieder zusammenbauen ori R16,$80 sts STA1,R16 IENDZ9: ret ; ; +++ Verringere Sendezeit um 10 Minuten DENDZ: lds R16,STA1 ; Sendezeit aus STA holen mov R20,R16 andi R16,$7F tst R16 ; Fall noch nicht auf 0 = 10' breq DENDZ9 dec R16 ; um 1 x 10' verringern sbrc R20,7 ; STA-Record wieder zusammenbauen ori R16,$80 sts STA1,R16 DENDZ9: ret ; ; +++ Status-Record eine Sekunde weiterschalten ; NXTSTA: lds R20,STA0 ; Status-Record laden lds R21,STA1 lds R22,STA2 lds R23,STA3 mov R16,R20 ; Verzweigen, je nach Mode (0,1,2) andi R16,$18 breq NS0 cpi R16,$08 breq NS1 rjmp NS9 ; Bei Mode 2 (Fertig) ist nix mehr zu tun ; ; ++ 1 s Service Mode 0 = Vorlauf NS0: tst R23 ; Zeit runterzählen brne NS01 dec R22 NS01: dec R23 ; brne NS09 ; Wenn Zähler auf 00:00 steht tst R22 brne NS09 ; ori R20,$08 ; Status auf 1 weiterschalten ldi R22,$01 ; STA2,3 auf Anfangsposition ldi R23,$00 sound SOUHI ; Tonsignal stsi LEDTIM,NACHLZ ; LED-Nachleuchtzeit auf Startwert ; lds R16,MODE ; Falls Mode = $1* = Programm andi R16,$F0 cpi R16,$10 brne NS09 stsi MODE,$50 ; .. Neuer Mode $50 = Hauptmenü flash STRM11,20 ; .. Und Fehlermeldung ; NS09: rjmp NS9 ; Fertig mit Mode 0 ; ; ++ 1 s Service Mode 1 = Operate NS1: inc R23 ; Sekunden hochzählen mov R16,R23 ; .. und nach WRK kopieren andi R16,$3F ldi ZL,60 ; Wenn Sekunden-Endwert erreicht sbrs R21,7 ldi ZL,30 cp R16,ZL brne NS15 andi R23,$C0 ; Sekunden auf 0 ; mov R16,R22 ; Aktueller Fuchs nach WRK/2..0 andi R16,$07 mov ZL,R20 ; N Füchse nach ZL andi ZL,$07 cp R16,ZL ; Wenn Aktueller Fuchs < letzter Fuchs breq NS12 inc R22 ; .. Aktuellen Fuchs hochzählen rjmp NS15 NS12: andi R22,$F8 ; .. sonst Aktueller Fuchs = letzter, Fuchs auf 1 ori R22,$01 ; NS15: ldi R16,8 ; mov ZL,R23 ; Falls Sekundenzähler andi ZL,$3F cpi ZL,00 ; .. auf 0 breq NS17 cpi ZL,30 ; .. oder 30 brne NS9 NS17: add R22,R16 ; .... n x 30s-Zähler inkrementieren mov R16,R22 ; Wenn n x 30s-Zähler andi R16,$F0 cpi R16,160 ; auf 20 (x 8) brne NS9 andi R22,$07 ; .. auf 0 setzen ; dec R21 ; .. und Durchlaufzähler dekrementieren mov R16,R21 ; .. Wenn Zähler jetzt auf -1 andi R16,$7F cpi R16,$7F brne NS9 cbr R20,$08 ; .... Mode auf 2 weiterschalten sbr R20,$10 sound SOUHI ; Tonsignal stsi LEDTIM,NACHLZ ; .... LED-Nachleuchtzeit auf Startwert ; NS9: sts STA0,R20 ; Status-Record wieder ablegen sts STA1,R21 sts STA2,R22 sts STA3,R23 ret ; Fertig ; ; RX-Record aus IN4B auflösen und Dezimal anzeigen ; R17 und R18 nicht ändern! RXANA: lds R19,IN4B+0 ; Fuchs-Modus separieren lsr R19 lsr R19 lsr R19 andi R19,$03 lds R16,IN4B+0 ; Fuchs-Nummer separieren swap R16 lsr R16 andi R16,$07 sts BCD1+0,R16 lds R16,IN4B+0 ; Fuchsanzahl separieren andi R16,$07 sts BCD1+1,R16 lds R16,IN4B+1 ; Sendedauer separieren ldi R20,3 sbrc R16,7 ldi R20,6 sts BCD1+2,R20 andi R16,$7F ; Durchgänge separieren inc R16 rcall B3BCD ; nach BCD wandeln sts BCD1+3,R1 sts BCD1+4,R2 sts BCD1+5,R3 cpi R19,0 ; Fuchsmode 0 ? brne RXA1 lds ZH,IN4B+2 ; Restwartezeit lds ZL,IN4B+3 rcall BB5BCD ;..nach BCD wandeln sts BCD2+0,R1 sts BCD2+1,R2 sts BCD2+2,R3 sts BCD2+3,R4 sts BCD2+4,R5 flash STRRA0,2 ; RXA1: cpi R19,1 ; Fuchsmode 1 ? brne RXA2 lds R16,IN4B+2 ; n x 30s-Timer separieren andi R16,$F8 clr ZL ; LSb bedeutet ,0 sbrc R16,3 ldi ZL,5 ; .. bzw ,5 sts BCD2+2,ZL swap R16 ; Obere 4 Bits.. andi R16,$0F rcall B3BCD ; .. BCD wandeln sts BCD2+0,R2 sts BCD2+1,R3 lds R16,IN4B+2 ; Aktueller Fuchs separieren andi R16,$07 sts BCD2+3,R16 lds R16,IN4B+3 ; Sekunde separieren andi R16,$3F rcall B3BCD sts BCD2+4,R2 sts BCD2+5,R3 flash STRRA1,2 ; RXA2: cpi R19,2 ; Fuchsmode 2 ? brne RXA3 flash STRRA2,2 ; RXA3: cpi R19,3 ; Fuchsmode 3 = Antwort auf Lese FOXID ? brne RXA9 lds R16,IN4B+1 ; Byte 1 ist FOXID sts FOXID,R16 rcall DFOXID ; FOXID dekodieren flash STRRA3,2 ; RXA9: ret ; ; TX-Record aus OUT4B auflösen und Dezimal anzeigen ; R17 und R18 nicht ändern! TXANA: lds R19,OUT4B+0 ; Command separieren swap R19 lsr R19 andi R19,$07 ; cpi R19,0 ; Command 0: Load brne TXA01 rjmp TXAC0 TXA01: cpi R19,6 ; Command 6,7: Set Fox ID breq TXA06 cpi R19,7 breq TXA06 ; flash STRTA1,2 ; Sonstige Commands, allgemeine Anzeige rjmp TXA9 ; TXA06: lds R16,OUT4B+0 ; Fuch ID dekodieren andi R16,$37 sts FOXID,R16 rcall DFOXID flash STRTA7,2 TXA09: rjmp TXA9 ; Command 0 = Load Record TXAC0: stsi BCD1+0,'-' ; Keine Fuchsnummer lds R19,OUT4B+0 ; Fuchs-Modus separieren lsr R19 lsr R19 lsr R19 andi R19,$03 lds R16,OUT4B+0 ; Fuchsanzahl separieren andi R16,$07 sts BCD1+1,R16 lds R16,OUT4B+1 ; Sendedauer separieren ldi R20,3 sbrc R16,7 ldi R20,6 sts BCD1+2,R20 andi R16,$7F ; Durchgänge separieren inc R16 rcall B3BCD ; nach BCD wandeln sts BCD1+3,R1 sts BCD1+4,R2 sts BCD1+5,R3 cpi R19,0 ; Fuchsmode 0 ? brne TXA1 lds ZH,OUT4B+2 ; Restwartezeit lds ZL,OUT4B+3 rcall BB5BCD ;..nach BCD wandeln sts BCD2+0,R1 sts BCD2+1,R2 sts BCD2+2,R3 sts BCD2+3,R4 sts BCD2+4,R5 flash STRRA0,2 ; TXA1: cpi R19,1 ; Fuchsmode 1 ? brne TXA2 lds R16,OUT4B+2 ; n x 30s-Timer separieren andi R16,$F8 clr ZL ; LSb bedeutet ,0 sbrc R16,3 ldi ZL,5 ; .. bzw ,5 sts BCD2+2,ZL swap R16 ; Obere 4 Bits.. andi R16,$0F rcall B3BCD ; .. BCD wandeln sts BCD2+0,R2 sts BCD2+1,R3 lds R16,OUT4B+2 ; Aktueller Fuchs separieren andi R16,$07 sts BCD2+3,R16 lds R16,OUT4B+3 ; Sekunde separieren andi R16,$3F rcall B3BCD sts BCD2+4,R2 sts BCD2+5,R3 flash STRRA1,2 ; TXA2: cpi R19,2 ; Fuchsmode 2 ? brne TXA9 flash STRRA2,2 ; TXA9: ret ; ; FOXID dekodieren in Anzeigeformat AFUCHS, AMOD DFOXID: push R16 push R20 push R21 push R22 ; lds R16,FOXID ; Fuchsnummer separieren andi R16,$07 sts AFUCHS,R16 ; .. und speichern ; lds R16,FOXID ; Tastgeschwindigkeits-Symbol ldi R20,'>' ; > bzw. >> sbrs R16,3 ldi R20,$FC sts AMOD,R20 ; .. speichern ; andi R16,$30 ; Modulationsfrequenz separieren DFID0: cpi R16,$00 ; 0 = 1k2 brne DFID1 ldi R20,'1' ldi R21,'k' ldi R22,'2' DFID1: cpi R16,$10 ; 1 = 800 brne DFID2 ldi R20,'8' ldi R21,'0' ldi R22,'0' DFID2: cpi R16,$20 ; 2 = 600 brne DFID3 ldi R20,'6' ldi R21,'0' ldi R22,'0' DFID3: cpi R16,$30 ; 3 = A1 brne DFID9 ldi R20,' ' ldi R21,'A' ldi R22,'1' DFID9: sts AMOD+1,R20 sts AMOD+2,R21 sts AMOD+3,R22 ; pop R22 pop R21 pop R20 pop R16 ret ; ; ############################ ; #### EEPROM-Lesen + Schreiben ######################### ; ############################ ; ; ++++ CFUB/CFUBF ins EEPROM Adr. 0/1 schreiben ; SAVEEP: OUT EEARH,C0 ; High Adresse ist 0 ; SAVEE1: IN R17,EECR ; Wait for EEPROM Ready to write ANDI R17,$02 BRNE SAVEE1 LDI R16,0 ; Low Address OUT EEARL,R16 LDS R16,CFUB ; Variable holen LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 OUT EEDR,R16 CLI ; Interrupt ausschalten LDI R17,$04 LDI R16,$02 OUT EECR,R17 ; Set EEPROM Master Write Enable OUT EECR,R16 ; Set EEPROM Write SEI ; Interrupt wieder an ; SAVEE2: IN R17,EECR ; Wait for EEPROM Ready to write ANDI R17,$02 BRNE SAVEE2 LDI R16,1 ; Low Address OUT EEARL,R16 LDS R16,CFUBF ; Variable holen LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 OUT EEDR,R16 CLI ; Interrupt ausschalten LDI R17,$04 LDI R16,$02 OUT EECR,R17 ; Set EEPROM Master Write Enable OUT EECR,R16 ; Set EEPROM Write SEI ; Interrupt wieder an ; RET ; ; ++++ Alle Parameter aus EEPROM holen +++++++++++++++++++++++++++++++ ; GETEEP: OUT EEARH,C0 ; High Adresse ist 0 ; LDI R16,0 OUT EEARL,R16 LDI R17,$01 OUT EECR,R17 ; Set EEPROM Read Cmd GET1: IN R17,EECR ; Wait for EEPROM Read complete ANDI R17,$01 BRNE GET1 IN R16,EEDR ; Variable lesen LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 STS CFUB,R16 ; Variable ablegen ; LDI R16,1 OUT EEARL,R16 LDI R17,$01 OUT EECR,R17 ; Set EEPROM Read Cmd GET2: IN R17,EECR ; Wait for EEPROM Read complete ANDI R17,$01 BRNE GET2 IN R16,EEDR ; Variable lesen LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 STS CFUBF,R16 ; Variable ablegen ; RET ; ; ; ############################# ; #### Analog-In, Soundgenerator ######################### ; ############################# ; ; **** Einen Analogwert Kanal R16 einlesen und in R16 übergeben ; Scaling Factor in R18 (Definition bei Deklaration CFUB) ; Benutzt R16 - R22 ; ANACON: out ADMUX,R16 ; ADMUX einstellen clr R16 ; Wait a little for I/O to settle AC1: dec R16 brne AC1 sbi ADCSR,6 ; Start ADC AC2: sbis ADCSR,4 ; Wait for ADIF rjmp AC2 sbi ADCSR,4 ; Clear ADIF in R16,ADCL ; Get Conversion Results in R17,ADCH swap R18 ; Scaling Factor expandieren mov R19,R18 andi R18,$F0 ; Low Byte andi R19,$0F ; High Byte ori R19,$20 rcall MPY16U mov R16,R20 ; 8 bit unsigned result tst R21 ; If Result Overflow.. breq AC3 ldi R16,$FF ; .. Set Result to max AC3: ret ; ;++++ Subroutine for 16x16 Bit Unsigned Multiplication ; ; This subroutine multiplies the two 16-bit register variables ; Mp16uH:mp16uL and mc16uH:mc16uL. ; The result is placed in m16u3:m16u2:m16u1:m16u0. ; ; Number of words :14 + return ; Number of cycles :153 + return ; Low registers used :None ; High registers used :7 R16..R22 ; ;++ Subroutine Register Variables ; .def mc16uL =r16 ;multiplicand low byte .def mc16uH =r17 ;multiplicand high byte .def mp16uL =r18 ;multiplier low byte .def mp16uH =r19 ;multiplier high byte ;.def m16u0 =r18 ;result byte 0 (LSB) ;.def m16u1 =r19 ;result byte 1 .def m16u2 =r20 ;result byte 2 .def m16u3 =r21 ;result byte 3 (MSB) .def mcnt16u =r22 ;loop counter ; ;++ Code ; MPY16u: clr m16u3 ;clear 2 highest bytes of result clr m16u2 ldi mcnt16u,16 ;init loop counter lsr mp16uH ror mp16uL ; m16u_1: brcc noad8 ;if bit 0 of multiplier set add m16u2,mc16uL ;add multiplicand Low to byte 2 of res adc m16u3,mc16uH ;add multiplicand high to byte 3 of res noad8: ror m16u3 ;shift right result byte 3 ror m16u2 ;rotate right result byte 2 ror mp16uH ;rotate result byte 1 and multiplier High ror mp16uL ;rotate result byte 0 and multiplier Low dec mcnt16u ;decrement loop counter brne m16u_1 ;if not done, loop more ret ; ; ; ;**** Soundgenerator (Alle 100 ms aufrufen) ; Wenn Soundpointer aktiv: Nächstes Element aus Sound-String holen ; und mit Frequenz 10 kHz/Wert piepsen SOUGEN: lds ZL,SOUPNT ; Sound-Pointer holen lds ZH,SOUPNT+1 tst ZH ; Wenn MSB = 0 breq SOUG9 ; .. dann nichts ausgeben ; lpm ; Get one Byte to R0 adiw ZL,1 ; Increment Z out OCR1AH,R0 ; Variablen Oscillator laden clr R18 out OCR1AL,R18 sts SOUFRQ,R0 ; und F für Start-Lautsprecher bereitstellen tst R0 ; Sonderfall Wert = 0 brne SOUG0 clr ZH ; .. Fertig, SOUPNT MSB auf 0 rjmp SOUG1 ; .. Piepser aus ; SOUG0: dec R0 ; Sonderfall Wert = 1 breq SOUG1 ; .. Piepser bleibt aus ldi R18,$40 ; .. sonst Piepser aktivieren SOUG1: out TCCR1A,R18 ; sts SOUPNT,ZL ; Sound-Pointer retten sts SOUPNT+1,ZH ; SOUG9: ret ; ; ; ################### ; #### LCD-Ansteuerung ############################################### ; ################### ; ; **** Subroutine to Copy String to LCD Data Field ******************* ; ; String pointed to by Z ; Variables are inserted according to second 32 Bytes in Data String ; Also handles leading zero suppression ; LCDSTR: PUSH R0 PUSH R16 PUSH R17 PUSH XL PUSH XH PUSH YL PUSH YH ; ;++++ Make Y pointer to LCD Data Field LDI YH,HIGH(LCDDAT) LDI YL,LOW(LCDDAT) ; ;++++ Copy Data String LCDST1: LPM ; Get one Byte to R0 ADIW ZL,1 ; Increment Z ST Y+,R0 ; Store Byte CPI YL,LOW(LCDDAT)+32 ; Repeat 32 times BRNE LCDST1 ; LDI YH,HIGH(LCDDAT) LDI YL,LOW(LCDDAT) ; ;++++ Insert Variable String LCDST2: LPM ; Get one Byte to R0 ADIW ZL,1 ; Increment Z MOV R16,R0 ; Use High Register supporting Immediate OpCodes ; CPI R16,$FF ; Wenn Byte = $FF BREQ LCDSTA ; dann keine weiteren Variablen = Fertig ; LCDS21: CPI R16,0 ; 0 is next Digit BREQ LCDST5 CPI R16,9 ; 9 is same Digit BRNE LCDST3 DEC XL RJMP LCDST5 ; LCDST3: MOV R16,R0 ; If not 0: <$10 is NOP ANDI R16,$F0 BREQ LCDST9 ; MOV XL,R0 LDI XH,0 ; LCDST5: LD R16,X+ ; Get Variable LD R17,Y ; Wenn L in Data String: CPI R17,'L' BRNE LCD501 ANDI R16,$0F ; .. Get low Nibble (for hex Display) LCD501: CPI R17,'H' ; Wenn H in Data String BRNE LCD502 SWAP R16 ANDI R16,$0F ; .. Get high Nibble (for hex Display) ; LCD502: CPI R16,10 ; Wenn Variable im Bereich 0..9 BRCC LCDS50 ; ORI R16,'0' ; Convert 0..9 to ASCII RJMP LCDS51 LCDS50: CPI R16,16 ; Wenn im Bereich 10..15 BRCC LCDS51 LDI R17,55 ; Convert 10..15 to A..F ADD R16,R17 ; LCDS51: CPI R16,'0' ; Handle leading zero BRNE LCDS52 LD R17,Y ; CPI R17,':' BRNE LCDS52 LDI R16,' ' ; Replace leading zero by Space ; LCDS52: CPI R16,$C0 ; Codes im Bereich $C0-$C7 (Sonderzeichen) BRCS LCDST6 CPI R16,$C8 BRCC LCDST6 ANDI R16,$07 ; .. nach 0..7 umsetzen ; LCDST6: ST Y,R16 ; Insert character ; LCDST9: INC YL ; Increment Write Pointer CPI YL,LOW(LCDDAT)+32 ; Repeat 16 times BRNE LCDST2 ; LCDSTA: POP YH POP YL POP XH POP XL POP R17 POP R16 POP R0 rcall OUTLCD ; Ergebnis anzeigen RET ; ; ; ++++ Initialize the LCD Display INILCD: push R25 ; ldi R25,60 ; Wait 60 msec rcall DELXMS ldi R25,$30 ; Initialize LCD rcall LC1CMD ldi R25,5 ; Wait 5 msec rcall DELXMS ldi R25,$30 ; Initialize LCD rcall LC1CMD ldi R25,$30 ; Initialize LCD rcall LC1CMD ldi R25,$20 ; Auf 4 bit Betrieb schalten rcall LC1CMD ldi R25,$29 ; Function Set rcall LC2CMD ldi R25,$1C ; Internal Osc Frequency rcall LC2CMD ldi R25,$74 ; Contrast Set rcall LC2CMD ldi R25,$52 ; Power/Icon/Contrast Control rcall LC2CMD ldi R25,$69 ; Follower Control rcall LC2CMD ldi R25,$0E ; Display On/Off Control rcall LC2CMD ldi R25,$01 ; Clear Display, Cursor Home rcall LC2CMD ldi R25,2 ; Wait 2 msec rcall DELXMS ldi R25,$06 ; Entry Mode Set rcall LC2CMD ; pop R25 ret ; ; ++++ Copy 32 Bytes from RAM (LCDDAT) to Display OUTLCD: push R16 push R25 push YL push YH ; ldi R25,$80 ;DDRAM-Adress auf 0 rcall LC2CMD ldi YL,LOW(LCDDAT) ;Pointer to Data String clr YH ldi R16,16 ;Loop-Counter, erste Zeile OUTLC1: ld R25,Y+ ;Get one Data Byte rcall LC2DAT ;Write to Display dec R16 ;Decrement Loopcounter brne OUTLC1 ; ldi R16,24 ;Loop-Counter, fortschalten bis 2te Zeile (40) OUTLC0: rcall LC2DAT ;Write to Display dec R16 ;Decrement Loopcounter brne OUTLC0 ; ldi R16,16 ;Loop-Counter, zweite Zeile OUTLC2: ld R25,Y+ ;Get one Data Byte rcall LC2DAT ;Write to Display dec R16 ;Decrement Loopcounter brne OUTLC2 ; ; ++ Cursor setzen ldi R25,$80 ;DDRAM-Adress auf 0 rcall LC2CMD ldi R25,$28 ;Instruction Table 0 rcall LC2CMD lds R16,CURACT ;Cursor-Soll-Position ; ldi R25,$0E ;Underline-Cursor sbrc R16,6 ;Wenn Bit 6 gesetzt ldi R25,$0D ;.. Blockcursor (blinkt) sbrs R16,7 ;Wenn MSb gesetzt rjmp OUTL21 lds YL,TIK10 ;.. Cursor blinken lassen sbrc YL,2 ldi R16,32 ; OUTL21: rcall LC2CMD ;Cursormode einstellen andi R16,$3F sbrs R16,4 ;Wenn >= 16 rjmp OUTLC3 ldi R25,24 ;..dann um 24 erhöhen add R16,R25 OUTLC3: tst R16 breq OUTLC4 dec R16 ldi R25,$14 ;Cursor rechts bis in Soll-Position rcall LC2CMD rjmp OUTLC3 ; OUTLC4: pop YH pop YL pop R25 pop R16 ret ; ; ++ Write Data in R25 (High Nibble) to LCD ( 1 Data Shot) ; LC1DAT: push R25 ; Entry for Data Mode andi R25,$F0 ; ori R25,$04 rjmp LC1CM0 ; LC1CMD: push R25 ; Entry for Command Mode andi R25,$F0 ; LC1CM0: out PORTD,R25 ; Post Data nop nop nop sbi PORTD,3 ; Toggle Enable Bit nop nop nop cbi PORTD,3 ; ldi R25,60 ; Wait 40 usec = 200 cycles LC1CM1: dec R25 brne LC1CM1 ; pop R25 ret ; ; ++ Write Data in R25 as Command to LCD (2 Nibble Shots) LC2CMD: push R25 ; rcall LC1CMD ; Send high nibble swap R25 rcall LC1CMD ; and low nibble ; pop R25 ret ; ; ++ Write Data in R25 as Data to LCD (2 Nibble Shots) LC2DAT: push R25 ; rcall LC1DAT ; Send high nibble swap R25 rcall LC1DAT ; and low nibble ; pop R25 ret ; ; ##################### ;##### Delay-Subroutines #################################### ; ##################### ; ; ++++ Delay x ms, x in R25 (x * 6 * 256 * 3 Cycle / 4,9 MHz) DELXMS: PUSH R16 PUSH R17 PUSH R25 ; DXMS: CLR R16 LDI R17,6 D1MS: INC R16 ; 3 cycle inner loop BRNE D1MS ; " " " " DEC R17 BRNE D1MS DEC R25 BRNE DXMS POP R25 POP R17 POP R16 RET ; ; ++++ Delay x secs, X in R25 DELXS: PUSH R16 PUSH R25 MOV R16,R25 LDI R25,250 ; 250 ms Basis Delay ; DXS: RCALL DELXMS RCALL DELXMS RCALL DELXMS RCALL DELXMS DEC R16 BRNE DXS ; POP R25 POP R16 RET ; ; *********************************** ; ******* 4800 Hz Timer Interrupt Handler ********************************** ; *********************************** ; ; ++++ Increment Timer @0 up to @1 ; If @1 reached: @0 = 0 else: goto @2 .MACRO INCTIM lds R24,@0 ; Timer holen inc R24 ; und inkrementieren sts @0,R24 cpi R24,@1 ; Wenn Endwert erreicht brne @2 clr R24 ; auf 0 setzen sts @0,R24 .ENDMACRO ; TIMINT: push R22 push R23 ; Get some work registers push R24 ; Used also by STSI! in R24,SREG ; Save Statusreg push R24 ; ; ++ 4800Hz Service ldi R22,-16 ; Set Counter to Startvalue (Divide by 64*16) out TCNT0,R22 lds R22,MODE ; Wenn Mode = Start, Ziel (3,7) andi R22,$30 cpi R22,$30 brne TIM10 TIM1: rcall SOUINT ; .. Sound über Serielle Leitung an Lautsprecher rjmp TIM12 ; TIM10: lds R22,TIK4K8 ; Anderer Mode: in jedem 4ten Pass cpi R22,2 ; (zeitversetzt zu DEBNCE) brne TIM11 rcall SEROUT ; .. Handle Serial Send TIM11: rcall SERIN ; In jedem Pass: Handle Serial Receive ; TIM12: inctim TIK4k8,4,TIM99 ; Increment to 0,8 msec ; ; ++ 1200Hz Service rcall DEBNCE ; Debounce Drehgeber inctim TIK1k2,120,TIM99 ; Increment to 100 msec ; ; ++ 100 ms Service sei ; Enable next interrupt stsi TICK,1 ; 100 ms Flag setzen inctim TIK10,10,TIM99 ; Increment to 1 sec ; ; ++ 1 s Service stsi TACK,1 ; 1 s Flag setzen ; ; ++ Conclusion of Interrupt Service ; TIM99: cli ; No interrupts during conclusion pop R24 ; Restore Status Reg out SREG,R24 pop R24 pop R23 pop R22 reti ; Interrupt-Handling beendet ; ; ++++ Sounds über serielle Leitung an Lautsprecher senden ; Frequenz ist 2400 Hz / SOUFRQ SOUINT: push R20 push R21 lds R20,SOUFRQ ; Sollfrequenz holen cpi R20,0 ; Wenn Sollwert = 0 = Sound aus brne SOUIN1 cbi DDRB,2 ; .. Leitungstreiber aus rjmp SOUIN9 ; SOUIN1: lsr R20 ; Sonst Frequenz durch 4 teilen lsr R20 lds R21,SOUCNT ; Zaehlt bis 2 * SOUFRQ inc R21 sts SOUCNT,R21 cp R21,R20 ; Bei 1 * SOUFRQ brne SOUIN2 sbi DDRB,2 ; .. Leitungstreiber ein rjmp SOUIN9 ; SOUIN2: lsl R20 ; Bei 2 * SOUFRQ cp R21,R20 brne SOUIN9 cbi DDRB,2 ; .. Leitungstreiber aus clr R21 ; .. und Counter auf 0 sts SOUCNT,R21 ; SOUIN9: pop R21 pop R20 ret ; ++++ Debounce Drehgeber und Taster ; ; Result in Flag SWIFLG ; This is a Subroutine called by the interrupt handler once per ms ; SWIFLG ist: Bit 0=Up, 1=Down, 2=Up + Pressed, 3=Down + Pressed, ; 4=Drehdrücker Puls ; $00 = none ; SWIFLG wird von Main auf none gesetzt. ; ; ++ Debounce Drehgeber Up/Down (alle 1 ms) ; DEBNCE: PUSH R20 ; Used as Temp Register PUSH R21 ; LDS R20,DEBP1 ; Debounce-Counter SBIC PINC,3 RJMP DEB1 CPI R20,0 ; An unterem Limit? BREQ DEB3 ; Do nothing DEC R20 ; Counter runterzaehlen STS DEBP1,R20 CPI R20,0 ; Jetzt auf Null? BRNE DEB3 SBIC PINC,4 RJMP DEBINC RJMP DEBDEC ; DEB1: CPI R20,4 ; An oberem Limit? BREQ DEB3 INC R20 STS DEBP1,R20 CPI R20,4 ; Jetzt am oberen Limit? BRNE DEB3 SBIC PINC,4 RJMP DEBDEC RJMP DEBINC ; DEBINC: LDI R20,$1 RJMP DEB2 ; DEBDEC: LDI R20,$2 ; DEB2: SBIS PINC,5 ; Wenn Drehgeber gedrückt LSL R20 ; Flags 2 Stellen links schieben SBIS PINC,5 LSL R20 LDS R21,SWIFLG ; Flags speichern OR R21,R20 STS SWIFLG,R21 ; ; ++ Debounce Drehdrücker (alle 1 ms) ; DEB3: LDS R20,DEBDD ; Timer holen SBIS PINC,5 ; Wenn nicht gedrückt RJMP DEB31 ; DEB30: CLR R20 ; Timer auf 0 setzen RJMP DEB39 ; DEB31: CPI R20,20 ; Gedrückt: Counter schon am Limit? BREQ DEB39 ; .. dann nix tun INC R20 ; .. sonst Counter hochzaehlen CPI R20,20 ; .. Wenn Timer jetzt am Limit BRNE DEB39 LDS R21,SWIFLG ; .... dann Drücker-Flag setzen ORI R21,$10 STS SWIFLG,R21 ; DEB39: STS DEBDD,R20 ; .. und Counter retten ; ; ++ Debounce Zieltaster (alle 1 ms) ; DEB4: LDS R20,MODE ; Wenn Mode <> 3 oder 7 (Start oder Ziel) ANDI R20,$30 CPI R20,$30 BRNE DEB4X ; LDS R20,SOUPNT+1 ; oder wenn Sound Generator Aktiv TST R20 BREQ DEB4Y DEB4X: STS DEBZT,C0 ; .. Taster Debounce unterdrücken RJMP DEB9 ; .. und sonst nix tun DEB4Y: LDS R20,DEBZT ; Timer holen SBIS PINB,2 ; Wenn nicht gedrückt RJMP DEB41 ; DEB40: CPI R20,5 ; .. und Timer am Limit BRNE DEB49 LDS R21,SWIFLG ; .... dann Zieltaster-Flag setzen ORI R21,$20 STS SWIFLG,R21 ; CLR R20 ; .. Timer auf 0 setzen RJMP DEB49 ; DEB41: CPI R20,5 ; Gedrückt: Counter schon am Limit? BREQ DEB49 ; .. dann nix tun INC R20 ; .. sonst Counter hochzaehlen ; DEB49: STS DEBZT,R20 ; Counter retten ; DEB9: POP R21 POP R20 RET ; ; ; +++ Serial Receive, called on 4,8 kHz Service ; Uses R16,R22,R23,R24 SERIN: lds R22,SERCNT ; Wenn Counter >= 192 cpi R22,192 brcc TIM55X ; .. nix tun ; tst R22 ; Wenn Counter = 0 brne TIM51 sbis PINB,2 ; .. und Leitung auf Low inc R22 ; .... Counter auf 1 setzen = Empfangsstart TIM50: rjmp TIM55 ; .. und fertig ; TIM51: inc R22 ; Wenn Counter > 0 : inkrementieren sbrc R22,0 ; Prüfen, ob Counter = n*4 + 2 rjmp TIM55 sbrs R22,1 TIM55X: rjmp TIM55 cpi R22,166 ; Bei Counterwert 166: Fertig breq TIM511 rjmp TIM52 TIM511: clr R22 ; .. Counter auf 0 mov R23,SHIFT0 ; Prüfbyte in R23 generieren eor R23,SHIFT1 eor R23,SHIFT2 eor R23,SHIFT3 eor R23,SHIFT4 ; cpi R23,$C3 ; Prüfbyte = Sollwert? brne TIM513 ; .. dann stsi SERFLG,1 ; .... RX complete Semaphore setzen rjmp TIM518 ; TIM513: cpi R23,$A5 ; Prüfbyte = Sollwert für FoxPro -> Fuchs (Clone)? brne TIM55 ; .. dann stsi SERFLG,4 ; .... anderen RX complete Semaphore setzen ; TIM518: sts IN4B+0,SHIFT0 ; .... Empfangenen String kopieren sts IN4B+1,SHIFT1 sts IN4B+2,SHIFT2 sts IN4B+3,SHIFT3 rjmp TIM55 ; TIM52: clc ; Bei Counterwert 2, 6, ..162 sbic PINB,2 ; .. ein Bit von Leitung nach Carry einlesen sec rol SHIFT4 ; 40 bit Shiftregister links schieben rol SHIFT3 rol SHIFT2 rol SHIFT1 rol SHIFT0 ; TIM55: sts SERCNT,R22 ; Counter in RAM ablegen ret ; +++ Serial Send, called on 1,2 kHz Service ; SEROUT: lds R22,SERCNT ; Wenn Senden nicht aktiv brne TIM56 lds R23,SERFLG sbrs R23,1 ; und wenn Sende Semaphore gesetzt rjmp TIM56X ldi R23,$A5 ; Prüfbyte vorbereiten TIM560: stsi SERFLG,0 ; Sende Semaphore löschen sbi DDRB,2 ; Startbit senden ldi R22,192 ; Counter auf Senden sts OUT4B+0,SHIFT0 ; Sendedaten in OUT4B retten für Hex-Display sts OUT4B+1,SHIFT1 sts OUT4B+2,SHIFT2 sts OUT4B+3,SHIFT3 eor R23,SHIFT0 ; und Prüfbyte erzeugen eor R23,SHIFT1 eor R23,SHIFT2 eor R23,SHIFT3 mov SHIFT4,R23 rjmp TIM59 ; Fertig mit Start ; TIM56X: sbrs R23,3 ; Wenn Sende-Semaphore für Clone gesetzt rjmp TIM56 ldi R23,$C3 ; Vertauschtes Prüfbyte vorbereiten rjmp TIM560 ; Weiter wie oben ; TIM56: cpi R22,192 ; Wenn Counter >= 192 brcs TIM59 inc R22 ; .. Counter hochzählen cpi R22,234 ; Wenn Counter = + 40 Data + 1 Stop (=fertig) brne TIM57 cbi DDRB,2 ; .. Leitungstreiber aus clr R22 ; .. und Counter wieder auf 0 rjmp TIM59 ; TIM57: sbrs SHIFT0,7 ; Bit 7 von Shift0 senden sbi DDRB,2 ; 0 = Low Level sbrc SHIFT0,7 cbi DDRB,2 ; 1 = High Z = High Level ; sec ; Stopbit nachschieben rol SHIFT4 rol SHIFT3 rol SHIFT2 rol SHIFT1 rol SHIFT0 ; TIM59: sts SERCNT,R22 reti ; ; ******************* ; **** Display Strings ********************************************* ; ******************* ; ; Die ersten 32 Bytes sind der Festtext-Teil der Anzeige ; ":" in Variablenposition = 0 als Space zeigen (Leading Zero Suppress) ; "H" " = High nibble Hex anzeigen ; "L" " = Low " ; ; Umlaute: $84/8E = ä/Ä, $94/99 = ö/Ö, $81/9A = ü/Ü ; Pfeile: $7E = ->, $7F = <-, $FB = <<, $FC = >> ; ; Die zweiten 32 Bytes sind jeweils Pointer auf die Variablen ; 1..8 = Leer ; Variablenname = Variable (Adresse <= $FF!) ; 0 = Nächste Stelle der aktuellen Variable ; 9 = Selbe " " ; ; Variablenwerte 0..15 werden in ASCII '0'..'9', 'A'..'F' umgesetzt ; " $C0..C7 werden in Sonderzeichen 0..7 umgesetzt ; ; Der Variablenstring kann an jeder Stelle mit $FF beendet werden ; ; >1234567812345678< Power On STRPO: .DB " FoxPro V. ",VERSHI,".",VERSLO," " .DB " DF1FO 2008 " .DB $FF,0 ; ; >1234567812345678< Hex-Display Send/Receive STRM0: .DB "S $HLHL-HLHL ? " .DB "E $HLHL-HLHL ? ",$FC .DB 1,2,3,OUT4B,9,0,9,8,0,9,0,9,5,6,7,8 .DB 1,2,3,IN4B,9,0,9,8,0,9,0,9,5,$FF ; ; >1234567812345678< Programm eingeben STRM1: .DB ":.:..:.. .F",$81," .0s" .DB ":.:..",$7E,":.:.. ",$FC .DB UHRZ,0,3,0,0,6,0,0,1,NFUCHS,3,4,5,TFUCHS,7,8 .DB STARTZ,0,3,0,0,6,ENDEZ,0,1,0,0,$FF ; ; >1234567812345678< Programm eingeben, Mode > 0 STRM11: .DB "Vorlauf beendet " .DB "Programm l",$84,"uft " .DB $FF,0 ; ; >1234567812345678< Fuchs bedienen STRM2: .DB "Fuchs + TX :...V" .DB "Laden Pr",$81,"fen ",$FC .DB 1,2,3,4,5,6,7,8,1,2,3,UBATF,0,6,0,8 .DB $FF,0 ; ; >1234567812345678< Start-Anzeige STRM3: .DB ":.:..:.. F.:...V" .DB "Start in .:.. ",$FC .DB UHRZ,0,3,0,0,6,0,0,1,2,AFUCHS,UBATF,0,6,0,8 .DB 1,2,3,4,5,6,7,8,1,BCD2,3,0,0,$FF ; ; >1234567812345678< Start, Modus <> 1 STRM31: .DB " F",$81,"chse senden " .DB " nicht! " .DB $FF,0 ; ; >1234567812345678< Extras STRM4: .DB "+ Fu",$23,". .... VH.L" .DB "TX Mod Osz Hex ",$FC .DB 1,2,3,4,5,AFUCHS,7,AMOD,0,0,0,4,5,AVERS,7,9 .DB $FF,0 ; ; >1234567812345678< Top-Menü STRM5: .DB "Programm Fuchs " .DB "Start Ziel :...V" .DB 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 .DB 1,2,3,4,5,6,7,8,1,2,3,UBAT,0,6,0,8 ; ; >1234567812345678< Voltmeter eichen STRM6: .DB "UbBg :...V $HL " .DB "UbFu :...V $HL ",$FC .DB 1,2,3,4,5,UBAT,0,8,0,2,3,4,CFUB,9,7,8 .DB 1,2,3,4,5,UBATF,0,8,0,2,3,4,CFUBF,9,7,8 ; ; >1234567812345678< Voltmeter eichen, Startmeldung STRM61: .DB "Voltmeter eichen" .DB "(Bedieng.+Fuchs)" .DB $FF,0 ; ; >1234567812345678< Ziel-Anzeige STRM7: .DB ":.. :.:..:..,. " .DB ":.. :.:..:..,. ",$FC .DB BCD1,0,3,4,0,0,7,0,0,2,0,0,5,0,7,8 .DB BCD2,0,3,4,0,0,7,0,0,2,0,0,5,0,7,8 ; ; >1234567812345678< RX Analyse, Mode 0 STRRA0: .DB "F ./. .0s :..0'" .DB "Vorlauf :.... s " .DB 1,2,BCD1,4,0,6,7,0,1,2,3,0,0,0,7,8 .DB 1,2,3,4,5,6,7,8,BCD2,0,0,0,0,6,7,8 ; ; >1234567812345678< RX Analyse, Mode 1 STRRA1: .DB "F ./. .0s :..0'" .DB "Send:.,.' F. :.s" .DB 1,2,BCD1,4,0,6,7,0,1,2,3,0,0,0,7,8 .DB 1,2,3,4,BCD2,0,7,0,1,2,3,0,5,0,0,8 ; ; >1234567812345678< RX Analyse, Mode 2 STRRA2: .DB "F ./. '" .DB "Fertig " .DB 1,2,BCD1,4,0,$FF ; ; >1234567812345678< RX Analyse, Mode FOXID lesen STRRA3: .DB "Fuchs ID gelesen" .DB " Nr . Mod . ... " .DB 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 .DB 1,2,3,4,AFUCHS,6,7,8,1,2,AMOD,4,0,0,0,8 ; ; >1234567812345678< TX Analyse Command 1 STRTA1: .DB "Cmd:H 2=Rd 4=Mod" .DB "6=TX 8=Osc A=RId" .DB 1,2,3,4,OUT4B,$FF ; ; >1234567812345678< TX Analyse Command 7 STRTA7: .DB "Fuchs einstellen" .DB " Nr . Mod . ... " .DB 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 .DB 1,2,3,4,AFUCHS,6,7,8,1,2,AMOD,4,0,0,0,8 ; ; >1234567812345678< Sicher, Fuchs Mode 0 STRMX0: .DB ":.:..:.. Vorlauf" .DB ":.:..",$7E,":.:.. .F.0" .DB UHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB STARTZ,0,3,0,0,6,ENDEZ,0,1,0,0,4,NFUCHS,6,TFUCHS,8 ; ; >1234567812345678< Sicher, Fuchs Mode 1 STRMX1: .DB ":.:..:.. Senden " .DB "F./. *.0s ",$7E,":.:.." .DB UHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB 1,AFUCHS,3,NFUCHS,5,6,TFUCHS,8,1,2,3,ENDEZ,0,6,0,0 ; ; >1234567812345678< Sicher, Fuchs Mode 2 STRMX2: .DB ":.:..:.. Fertig " .DB ":.:..-:.:.. " .DB UHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB STARTZ,0,3,0,0,6,ENDEZ,0,1,0,0,$FF ; ; >1234567812345678< Fuchs synchron STROK: .DB " Fuchs ",$23," . " .DB " o k ! " .DB 1,2,3,4,5,6,7,8,1,2,3,4,AFUCHS,$FF ; ; >1234567812345678< Fuchs nicht synchron STRNOK: .DB "FUCHS ",$23," . IST " .DB "NICHT SYNCHRON! " .DB 1,2,3,4,5,6,7,8,AFUCHS,$FF ; ; >1234567812345678< Fuchs antwortet nicht STRTOT: .DB "KEINE VERBINDUNG" .DB " ZUM FUCHS! " .DB $FF,0 ; ; >1234567812345678< Warten STRWAR: .DB " Bitte Warten.. " .DB " " .DB $FF,0 ; ; >1234567812345678< Warten STRCLO: .DB " Programm " .DB " ",$9A,"bernommen ! " .DB $FF,0 ; ; **** Cursor-Positionstabelle ; ; Jeder Entry besteht aus 2 Byte: Modus, zugehörige Cursor-Position + Attribute ; Cursorposition 1.Zeile: 0..15, 2. Zeile: 16..31, Aus: 32 ; Attribute Bit 7,6 = 00: Underline, 10: Underline,blink, 01: Block,blink CURTAB: .DB $00,0+$40,$01,3,$02,4,$03,5 .DB $04,6,$05,8,$06,9,$07,10 .DB $08,11,$09,13+$40,$0A,16+$40,$0B,29+$40 .DB $0C,31+$40 .DB $10,1,$11,4,$12,7+$80,$13,9 .DB $14,13+$80,$15,19,$16,25,$17,31+$40 .DB $20,16+$40,$21,23+$40,$22,31+$40,$23,6+$40 .DB $24,8+$40 .DB $30,31+$40 .DB $40,5+$80,$41,9+$80,$42,16+$40,$43,19+$40 .DB $44,23+$40,$45,27+$40,$46,31+$40 .DB $50,0+$40,$51,10+$40,$52,16+$40,$53,22+$40 .DB $60,11+$40,$61,27+$40,$62,31+$40 .DB $70,31+$40 .DB $FF,$FF ; End of Record ; ; ***************** ; **** Sound Strings ********************************************* ; ***************** ; ; Diese Strings enthalten Tonwertfolgen, die im 100ms-Raster ; abgespielt werden. Frequenz ist 10 kHz / Wert: ; 4 = 2,5 kHz, 10 = 1 kHz, 100 = 100 Hz ; Sonderfälle: 1 = kein Ton, 0 = End of String ; ; Im Start-Modus werden die Strings ausser über den internen Piepser ; auch noch über die serielle Leitung an den externen Lautpsrecher ; ausgegeben. Dazu müssen alle Tonwerte Vielfache von 4 sein: ; 4 = 2,4 kHz, 8 = 1,2 kHz, 12 = 800 Hz, 16 = 600 Hz, 0 und 1 wie oben ; SOUPO: .DB 9,1,9,1,9,1,13,13,13,0 ; Power-On-Fanfare ; SOUALA: .DB 3,4,6,9,12,18,24,0 ; Wusch-Alarm ; SOUHI: .DB 7,1,7,1,7,1,7,1 ; HI-Alarm .DB 1,1,7,1,7,0 ; SOUPIP: .DB 7,0 ; Kurz-Piep hoch ; SOUPAP: .DB 14,0 ; Kurz-Piep tief ; SOUOK: .DB 10,1,10,10,10,1,10,0 ; Morse-R ; SOUNOK: .DB 15,10,5,10,15,10,5,10,15,10 ; Sirenen-Alarm .DB 5,10,15,10,5,10,15,10,5,0 ; SOU1MI: .DB 16,4,16,4,16,4,16,4,16,0 ; Start-Alarm 1 min ; SOU10S: .DB 24,0 ; Start-Alarm 10 s ; SOUNS: .DB 8,0 ; Start-Alarm 5..1 s ; SOU0S: .DB 8,8,8,8,8,8,8,8,8,0 ; Start ; ; ************************ ;******** This is the End..... *************************************** ; ************************