; FOXPRO2.ASM ; ; *************************************************** ; * Fuchsjad-Sender Programmiergerät, 2. Generation * ; *************************************************** ; ; Autor: Nick Roethe, DF1FO, DF1FO at darc.de ; ; Created 13.4.2009 ; Version 0.0: Code-Import von FOXPRO, Version 3.2 ; 23. 4.09 0.1: Serielle Übertragung und HEX-Menü angepasst ; 30. 4.09 0.2: Menü Programm fertig ; 7. 5.09 0.3: Alles codiert, nur grob getestet ; 27. 6.09 0.4: Ändern Startzeit setzt Status auf Vorlauf ; 2. 7.09 0.5; Englische+Deutsche Menütexte, diverse kleine Fixes+Verbesserungen ; 6. 7.09 0.6: Fix für 'Zielzeitlisten-Scroll hakelt' ; 23. 8.09 0.7: Programmscroll nach Schalter->Sicher (statt Sicher + Click) ; Power-On-Message erscheint auch bei Sicher ; --> Dieser Stand gesichert als FOXPRO2Mega8 ; -------------- ; 21. 9.09 1.0: Umgestellt von ATMega8 auf ATMega168 für grösseren Flash ; Sprachauswahl Deutsch/Englisch im Abgleichmenü ; 4 Tastgeschwindigkeiten 40/50/60/70 Bpm ; 4 Sendedauern 60/30/15/12 sec ; Testlauf 10x15' ohne Pausen, fertig nach 2,5 Minuten ; Resetpuls alle 5 Minuten an Pin PD0 ; Zielzeiterfassung speichert letzte 99 Auslösungen ; Programm-Menü in Einfach- und Erweitert-Version ; Eingabe CW-ID und Übertragung an Fuchs ; >> Version 1.x erfordert in den Füchsen FJTX V1.x << ; 6.11.09 1.0 Code freeze und auf meiner Website veröffentlicht ; 8.11.09 1.1: Umschalten zwischen 2 unabhängigen Programmen (z.B. 2m und 80m) ; 12.11.09 1.2: Debounce Drehgeber 4 -> 2 msec, SRAM-Display laufend aktuell ; -4s Start Piep jetzt vollständig, Piep bei 'Sekunden auf 0 setzen' ; 3 Programm-Modi: 1, 12, 8o2 (802: FoxID wählt Programm 80 bzw 2) ; 29.12.09 1.3: Fix für: Anzeige CWID Länge geht nicht (mehr) ; 12. 3.11 1.4: Fix für: 'Keine Verbindung' - Anzeige im Menü Fuchs-+Extras bei F=0, 50Bpm, 1k2 ; 19. 5.11 1.5: Fix für Sende-Unterbrechungen im Testmodus TX* ; .equ VERSHI= '1' .equ VERSLO= '5' ; .equ NACHLZ= 30 ; LED-Beleuchtung Nachleuchtzeit in s ; ; ; **** Specify Device .device ATmega168; ; ; >> AVR-STUDIO << : Ich benutze AVR Studio 4 ; ================ und Assembler Version 2 ; Einstellungen in AVR Studio 4: ; -> Project -> Assembler Options: Assembler Version 2 ; -> Tools -> Options -> Editor -> Tabwidth=8 ; ; >> FUSES << : Im AVR-Programmer: ; - Häkchen nur an SPIEN und EESAVE ; - (Also kein Häkchen bei CKDIV8!) ; - Brown Out Detection auf 4,3 Volt ; - SUT_CKSEL: Ext. Crystal Osc 3,0-8,0MHz, unterste Auswahl ; - BOOTSZ unterste Auswahl (eigentlich egal) ; Richtiges Hex-Pattern X-H-L $F9-D4-FD ; Beim Auslesen kommt L-H-X $FD-D4-F9 zurück ; .listmac; Macro Expansion Listing On ; ; **** I/O Register Definitions (Memory mapped, use LD/ST) .equ UDR0 =$C6 .equ UBRR0H =$C5 .equ UBRR0L =$C4 .equ UCSR0C =$C2 .equ UCSR0B =$C1 .equ UCSR0A =$C0 .equ TWAMR =$BD .equ TWCR =$BC .equ TWDR =$BB .equ TWAR =$BA .equ TWSR =$B9 .equ TWBR =$B8 .equ ASSR =$B6 .equ OCR2B =$B4 .equ OCR2A =$B3 .equ TCNT2 =$B2 .equ TCCR2B =$B1 .equ TCCR2A =$B0 .equ OCR1BH =$8B .equ OCR1BL =$8A .equ OCR1AH =$89 .equ OCR1AL =$88 .equ ICR1H =$87 .equ ICR1L =$86 .equ TCNT1H =$85 .equ TCNT1L =$84 .equ TCCR1C =$82 .equ TCCR1B =$81 .equ TCCR1A =$80 .equ DIDR1 =$7F .equ DIDR0 =$7E .equ ADMUX =$7C .equ ADCSRB =$7B .equ ADCSRA =$7A .equ ADCH =$79 .equ ADCL =$78 .equ TIMSK2 =$70 .equ TIMSK1 =$6F .equ TIMSK0 =$6E .equ PCMSK2 =$6D .equ PCMSK1 =$6C .equ PCMSK0 =$6B .equ EICRA =$69 .equ PCICR =$68 .equ OSCCAL =$66 .equ PRR =$64 .equ CLKPR =$61 .equ WDTCSR =$60 ; I/O Register Definitions (I/O-area, use IN/OUT) .equ SREG =$3F .equ SPH =$3E .equ SPL =$3D .equ SPMCSR =$37 .equ MCUCR =$35 .equ MCUSR =$34 .equ SMCR =$33 .equ MONDR =$31 .equ ACSR =$30 .equ SPDR =$2E .equ SPSR =$2D .equ SPCR =$2c .equ GPIOR2 =$2B .equ GPIOR1 =$2A .equ OCR0B =$28 .equ OCR0A =$27 .equ TCNT0 =$26 .equ TCCR0B =$25 .equ TCCR0A =$24 .equ GTCCR =$23 .equ EEARH =$22 .equ EEARL =$21 .equ EEDR =$20 .equ EECR =$1F .equ GPIOR0 =$1E .equ EIMSK =$1D .equ EIFR =$1C .equ PCIFR =$1B .equ TIFR2 =$17 .equ TIFR1 =$16 .equ TIFR0 =$15 .equ PORTD =$0B .equ DDRD =$0A .equ PIND =$09 .equ PORTC =$08 .equ DDRC =$07 .equ PINC =$06 .equ PORTB =$05 .equ DDRB =$04 .equ PINB =$03 ; ; ; **** Register Definitions .def C0 =r8 ; Constant 0 .def C1 =r9 ; Constant 1 .def SHIFT0 =r10 ; 2B Shiftregister for Serial In/Out MSB .def SHIFT1 =r11 ; " ; .def XL =r26 ; Indexregister .def XH =r27 .def YL =r28 .def YH =r29 .def ZL =r30 .def ZH =r31 ; .def WRK =r16 ; Registerdefinitionen für Kompatibilität des .def STX0 =r17 ; Status Update Codes mit FJTX .def STX1 =r18 .def STX2 =r19 .def STX3 =r20 .def STX4 =r1 .def STX5 =r2 .def STX6 =r3 .def STX7 =r4 .def STX8 =r5 .def STX9 =r6 ; ; **** Memory Sizes .equ RAMBEG = $100 ; First SRAM Location .equ RAMEND = $4FF .equ XRAMEND = $4FF .equ E2END = $1FF .equ FLASHEND = $1FFF ; ; **** Variablen *************************************************** .DSEG .ORG RAMBEG ; Start of RAM address range ($0100) ; VOID: .BYTE 16 ; Unused RAM Area (because of LCDSTR-Limitation) ; ; ++ Zustands-Variablen ; 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, (8=Abfrage Clonen,) 9=ProgrammEinfach CURPOS: .BYTE 1 ; Cursorposition 1.Zeile: 0..15, 2: 16..31, Aus: 32 ; Bit 7,6= 00:Underline, 10:dto,blink, 01:Block,blink CURCID: .BYTE 1 ; Cursorposition für Modus $A0: Eingabe CW-ID (0..15) 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 OLDSW: .BYTE 1 ; Vorheriger Zustand Sicher-Schalter 0/8 PROTO: .BYTE 1 ; Protokollsteuerung für IF zum Fuchs (OUT2B>Fuchs>IN2B) ; $00 Ruhe ; $01 Register laden ; $10 Register laden + verifizieren ; $20 FoxID laden, FoxID + EC-Level lesen ; $21 FoxID + EC-Level lesen ; $28 Register lesen (Reg# in OUT2B+1) ; $30 Status nach Fuchs laden ; $40 Status im Fuchs prüfen ; $50 Status aus Fuchs lesen (Clonen) ; Detaillierte Beschreibung bei MAIN7: OUT2B: .BYTE 3 ; 2 Byte String -> Fuchs, + 1 Byte Scratch SAVE2B: .BYTE 2 ; 2 Byte Zwischenspeicher IN2B: .BYTE 2 ; 2 Byte String <- Fuchs TXTIME: .BYTE 1 ; Sendezeit 1..9' für Menüpunkt TXn' RAMADR: .BYTE 1 ; RAM-Adresse für RAM-Display im Hex-Menü RAMDAT: .BYTE 1 ; RAM-Daten für RAM-Display im Hex-Menü ; $21 ist Einstieg für Laden, $22 für Prüfen SCROLL: .BYTE 1 ; Scroll-Counter für Programm-Display (Schalter -> Sicher) ; 0 = Scroll Aus, 1..102 Zeit in 100 ms Schritten CONFIG: .BYTE 1 ; Konfiguration, im EEPROM ; Bit 0: 1=Deutsch, 0=Englisch ; Bit 2,1: Zahl Programme, 0=1, 1=12, 2=8o2 ; Variablen mit = gibt es je einmal für Programm 1 und 2 P12: .BYTE 2 ;=Aktives Programm 1 oder 2 EXPERT: .BYTE 2 ;=Programmeingabe-Modus: 0= Modus 9, 1 = Modus 1 STAMIN: .BYTE 2 ;=Start Abstand in Minuten, 1..6 ; ; ++ Fuchs-Status 0..9 ist identisch in allen Füchsen und FoxPro STA0: .BYTE 1 ;=Status 0 / 7..0 Uhrzeit binär in 10'- Schritten (0..143) STA1: .BYTE 1 ;=Status 1 / 7 Suchmodus 0=Aus, 1=Ein ; 6..4 Höchster Fuchs # (2..5) ; 3..0 Uhrzeit Minute binär (0..9) STA2: .BYTE 1 ;=Status 2 / 7,6 Durchgangsdauer 0..3 = 60/30/15/12" ; 5..0 Uhrzeit Sekunde binär (0..59) STA3: .BYTE 1 ;=Status 3 / 7 Frei ; 6..4 Modus 0=Vorlauf, 1=Test1, 2=Test2, ; 3=Senden, 4=Fertig ; 3 Frei ; 2..0 Aktueller Fuchs (1..5) ; Status 4..9 enthalten Uhr-Zeiten in 10'-Schritten (wie Status 0) STA4: .BYTE 1 ;=Status 4 Start Testlauf 1 ($FF = Aus) STA5: .BYTE 1 ;=Status 5 Ende Testlauf 1 (STA4=STA5: 10x15") STA6: .BYTE 1 ;=Status 6 Start Testlauf 2 ($FF = Aus) STA7: .BYTE 1 ;=Status 7 Ende Testlauf 2 (STA6=STA7: 10x15") STA8: .BYTE 1 ;=Status 8 Start Senden STA9: .BYTE 1 ;=Status 9 Ende Senden INSTA: .BYTE 10 ; Status 0..9, wie vom Fuchs empfangen STA092: .BYTE 10 ;=STA0..9 für das inaktive Programm FOXID: .BYTE 1 ; Fuchs-Nr./Modulation, Format SSMM0FFF, ; Tastgeschwindigkeit SS: 00=72Bpm, 01=60Bpm, 02=51Bpm, 03=45Bpm ; Modulationsfrequenz MM: 00=1200Hz, 01=800Hz, 10=600Hz, 11=A1 (80m) ; Fuchsnummer NNN: 0=MO, 1..5 MOE..MO5, 6+7=MO mit längerer Pause ; Wird im Fuchs-EEPROM abgelegt VERSHL: .BYTE 1 ; Fuchs Software-Version CWID: .BYTE 17 ; CW-ID-String; Erstes Byte 0000 ETTT E = 0: ID am Beginn, 1: Ende ; TTT = 7: Aus, 6..0 Tastgeschwindigkeit 45,50,60,70,80,90,120 BpM ; Nächste 16 Byte: zu sendende Zeichen in ASCII IOCWID: .BYTE 18 ; CWID wie im Fuchs-EEPROM Byte 1..18 abgelegt ; Byte 0 = CWID Byte 0, Byte 1 = Sendedauer des Strings in Sekunden ; Byte 2..17 = Zeichen im Morseformat, siehe Tabelle ASC2MO IOCWB0: .BYTE 1 ; CWID Byte 0, aus Fuchs gelesen, $FF wenn ungültig, für 'ID'-Anzeige ; ; ++ ASCII/BCD-Werte für Anzeigen BCD1: .BYTE 10 ; BCD-Werte für Zielzeit Display Zeile 1 BCD2: .BYTE 10 ; dto Zeile 2 AP12: .BYTE 2 ; Indikation P1/2 . > bzw. : >> AUHRZ: .BYTE 6 ; Uhrzeit Dezimal hhmmss ASTA4: .BYTE 6 ; Start Testlauf 1 hh:m0- ASTA5: .BYTE 6 ; Ende Testlauf 1 hh:m0_ ASTA6: .BYTE 6 ; Start Testlauf 2 hh:m0- ASTA7: .BYTE 6 ; Ende Testlauf 2 hh:m0_ ASTA8: .BYTE 3 ; Start Senden hhm ASTA9: .BYTE 3 ; Ende Senden hhm NFUCHS: .BYTE 1 ; Zahl der Füchse 2..5 AFUCHS: .BYTE 1 ; Aktueller Fuchs (wenn Fuchs Mode = 1..4) 1..5 (aus STA3) ATSEND: .BYTE 2 ; Sendedauer pro Durchgang 12/15/30/60 XFUCHS: .BYTE 1 ; Derzeit angeschlossener Fuchs (aus FoxID) 0..7 AMOD: .BYTE 5 ; Modulation im Format SSFFF, S = 45..80, FFF= A1/1k2/800/600 ATST: .BYTE 1 ; Anzeige Test aktiv t -> T ANL: .BYTE 2 ; Anzeige Suchmodus (Nachlauf) eingeschaltet s -> SM ATXEIN: .BYTE 1 ; Anzeige TX Ein (Extras-Menü) * = Ein ATITOS: .BYTE 4 ; Zeit bis Start m:ss, in ATITOS+3 ist ss in Hex (0..59) ACWID: .BYTE 2 ; Anzeige CWID id = Aus, ID = Ein ACWIDL: .BYTE 2 ; Anzeige CWID Länge ZE in s ATCWID: .BYTE 6 ; CWID 0..2: 40..120, Aus; 3..5: Beg,End ANZP12: .BYTE 4 ; Anzeige Prog 1/2, jeweils '1 ', '2 ', '80' ANPROG: .BYTE 3 ; Anzeige N Programme im Abgleichmenü (_1, _12, 8o2) ; ; ++ 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 ; ++ 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 TAK33: .BYTE 1 ; 33 ms Timing Flag TAK100: .BYTE 1 ; 100 ms Timing Flag TAK1S: .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 ; ;++ Display-Ansteuerung CURACT: .BYTE 1 ; Aktuelle Cursorposition (32 bei Flash, CURPOS bei Show) LCDDAT: .BYTE 32 ; Data to be displayed in LCD ; ; ++ 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, 99=voll ZZOFF: .BYTE 1 ; Zielzeit-Offset, bei > 99 Entries 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) call LCDSTR ; .. ausführen .ENDMACRO ; ; ++++ Flash Text String @0 for @1*100ms .MACRO FLASH call STA2A ; Parameter nach Anzeigeformat konvertieren stsi CURACT,32 ; Cursor aus ldi ZL,low(2*@0) ; Ausgabe-Kommand-String ldi ZH,high(2*@0) call 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 ; ; ++++ Byte auf Adresse @0 mit Byte auf @0+@1 tauschen .MACRO bswap lds R20,@0 lds R21,@0+@1 sts @0,R21 sts @0+@1,R20 .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 ; ; ++++ @0 erhöhen/erniedrigen nach Bit 2/3 in R17 .MACRO udhilo lds R16,@0 sbrc R17,2 ; rechts drehen/drücken inc R16 sbrc R17,3 ; links dec R16 sts @0,R16 .ENDMACRO ; ; ; ******************** ; **** Code starts here ******************************************** ; ******************** .CSEG .ORG 0 ; ; ++++ Interrupt Vectors JMP START ; 1 Reset JMP START ; 2 INT0 JMP START ; 3 INT1 JMP START ; 4 PCINT0 JMP START ; 5 PCINT1 JMP START ; 6 PCINT2 JMP START ; 7 WDT JMP START ; 8 TIM2 COMPA JMP START ; 9 TIM2 COMPB JMP START ; 10 TIM2 OVF JMP START ; 11 TIM1 CAPT JMP START ; 12 TIM1 COMPA JMP START ; 13 TIM1 COMPB JMP START ; 14 TIM1 OVF JMP START ; 15 TIM0 COMPA JMP START ; 16 TIM0 COMPB JMP TIMINT ; 17 Timer 0 Overflow JMP START ; 18 SPI, STC JMP START ; 19 USART RX JMP START ; 20 USART UDRE JMP START ; 21 USART TX JMP START ; 22 ADC JMP START ; 23 EE READY JMP START ; 24 ANALOG COMP JMP START ; 25 TWI JMP START ; 26 SPM READY ; ; ***************************** ; **** 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 ; ldi XH,HIGH(RAMBEG) ldi XL,LOW(RAMBEG) START1: st X+,C0 cpi XL,LOW(RAMEND+1) brne START1 cpi XH,HIGH(RAMEND+1) brne START1 ; ; ++++ 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 O.D. Output 5'-Reset-Puls ; Bit 1 as Output Test ; 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 sts ADMUX,R16 ldi R16,$86 ; Enable ADC, Clock Divider 64 = 77 kHz sts ADCSRA,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 TCCR0B,R16 ldi R16,-16 ; Set Counter to Start-Value out TCNT0,R16 ldi R16,$01 sts TIMSK0,R16 ; Enable Counter 0 Overflow Interrupt ; ; ++++ Intialize Timer/Counter 1 as Variable Osc. for Sounds ; -- CTC-Mode on OC1A Pin, f is 4,91 MHz /2 /OCR1AH_L ldi R16,$00 ; $00 = Sound Off, $40 = On sts TCCR1A,R16 ldi R16,$09 sts TCCR1B,R16 ldi R16,$0A ; Komparator fuer Counter Reset & Output Toggle sts OCR1AH,R16 ldi R16,0 ; $0A00 = 1 kHz Startwert sts OCR1AL,R16 ; ; ++++ Intialize Timer/Counter 2 for Fosc/4 Measurement on OC2A7Pin17 ldi R16,$42 ; Toggle OC2A on Compare Match, CTC sts TCCR2A,R16 ldi R16,$01 ; Counter 2 clocked with system clock sts TCCR2B,R16 ldi R16,$01 sts OCR2A,R16 ; ; ++++ Initialize some Variables ; call GETEEP ; Voltmeter Eichwerte XFUB/CFUBF, Sprache, CW-ID aus EEPROM ; ; Programm 1 stsi STA0,72 ; 12:00:00 Uhr, Modus Vorlauf stsi STA1,$50 ; 5 Füchse, kein Nachlauf stsi STA4,$FF ; Test 1 Aus stsi STA6,$FF ; Test 2 Aus stsi STA8,78 ; Senden 13:00-15:00 stsi STA9,90 ; stsi STAMIN,5 ; Abstand Starts in Minuten stsi P12,1 ; Aktives Programm = 1 ; Programm 2 stsi STA0+20,72 ; 12:00:00 Uhr, Modus Vorlauf stsi STA1+20,$50 ; 5 Füchse, kein Nachlauf stsi STA4+20,$FF ; Test 1 Aus stsi STA6+20,$FF ; Test 2 Aus stsi STA8+20,78 ; Senden 13:00-15:00 stsi STA9+20,90 ; stsi STAMIN+1,5 ; Abstand Starts in Minuten stsi P12+1,2 ; Nicht aktives Programm = 2 ; Sonstiges stsi MODE,$50 ; Top-Menü stsi RAMADR,$60 ; Erste RAM-Adresse für Hex-Display stsi LEDTIM,NACHLZ ; LED-Nachleuchtzeit auf Startwert stsi TXTIME,5 ; Testsendezeit in Minuten stsi OLDSW,$FF ; Sicher-Schalter auf unbekannt lds R16,CWID ; Wenn CWID im EEPROM noch leer cpi R16,$FF brne START2 ; CW-ID auf Grundstellung: stsi CWID,$0F ; CW-ID aus stsi CWID+1,'D' ; CW-ID 'DE DL0FOX' stsi CWID+2,'E' ; " stsi CWID+3,'.' ; " stsi CWID+4,'D' ; " stsi CWID+5,'L' ; " stsi CWID+6,'0' ; " stsi CWID+7,'F' ; " stsi CWID+8,'O' ; " stsi CWID+9,'X' ; " stsi CWID+10,'.' ; " stsi CWID+11,'.' ; " stsi CWID+12,'.' ; " stsi CWID+13,'.' ; " stsi CWID+14,'.' ; " stsi CWID+15,'.' ; " stsi CWID+16,'.' ; " ; ; ++++ Start Interrupt Handler START2: sei ; Global Interrupt enable ; ; ++++ Initialize LCD and show Start Text ldi R25,100 ; Wait 100 ms call DELXMS call INILCD flash STRPO,20 ldi R25,100 ; Wait 100 ms call DELXMS stsi SWIFLG,0 ; Clear any Drehgeber Flags sound SOUPO ; sbic PINC,5 ; Wenn Drehgeber gedrückt rjmp MAIN stsi MODE,$64 ; .. 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 M101 stsi LEDTIM,NACHLZ ; .. LED-Nachleuchtzeit auf Startwert stsi FLATIM,0 ; .. und Textflash beenden stsi SCROLL,0 ; .. und Programm-Scroll beenden ; M101: lds R16,LEDTIM ; Wenn LEDTIM > 0 tst R16 breq M102 cbi PORTB,0 ; .. LED einschalten rjmp M110 M102: sbi PORTB,0 ; .. sonst ausschalten ; M110: in R16,PINC ; Sicher-Schalter einlesen andi R16,$04 lds R20,OLDSW ; Alten Schalterzustand holen sts OLDSW,R16 ; .. und neuen alten ablegen cpi R20,$FF ; Wenn alter Stand ungültig = Erster Durchlauf nach PO breq M111 ; .. weiter nix tun cp R16,R20 ; Sonst wenn Schalter geändert breq M111 ; stsi LEDTIM,NACHLZ ; .. LED-Nachleuchtzeit auf Startwert stsi FLATIM,0 ; .. und Textflash beenden ; M111: tst R16 ; Wenn Schalter auf Ändern brne M112 stsi SCROLL,0 ; .. Scroll beenden rjmp MAIN2 ; .. und zum normalen Menühandling M112: tst R20 ; Wenn Schalter Ändern -> Sicher brne M118 stsi SCROLL,21 ; .. Programm (ohne Status) scrollen ; M118: lds R18,MODE ; Sonderfall Sicher und Modus = StartZiel andi R18,$F0 cpi R18,$70 brne M119 stsi SCROLL,0 ; .. Programmscroll unterdrücken rjmp MAIN3 ; .. Zielzeitliste scrollen ermöglichen ; M119: rjmp M399 ; Sicher und nicht StartZiel: nix tun ; ; ++++++++++++++++++++++++++++++++++++++++++++++++ ; +++ Modus mit rechts-/linksdrehen weiterschalten ++++++++++++++ ; ++++++++++++++++++++++++++++++++++++++++++++++++ MAIN2: tst R17 ; Wenn keins der Switch-Flags gesetzt brne MAIN21 rjmp M3999 ; .. Switch-Handling überspringen MAIN21: 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,8 ; .. 8 Felder M201: cpi R19,$10 ; Wenn Mode 1 brne M202 ; ldi R16,13 ; .. 13 Felder M202: cpi R19,$20 ; Wenn Mode 2 brne M203 ; ldi R16,7 ; .. 7 Felder M203: cpi R19,$30 ; Wenn Mode 3 brne M204 ; ldi R16,9 ; .. 9 Felder M204: cpi R19,$40 ; Wenn Mode 4 brne M205 ; ldi R16,8 ; .. 8 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,5 ; .. 5 Felder M207: cpi R19,$70 ; Wenn Mode 7 brne M208 ; ldi R16,2 ; .. 2 Felder M208: cpi R19,$80 ; Wenn Mode 8 brne M209 ; ldi R16,2 ; .. 2 Felder M209: cpi R19,$90 ; Wenn Mode 9 brne M20A ; ldi R16,8 ; .. 8 Felder M20A: cpi R19,$A0 ; Wenn Mode A brne M20B ; ldi R16,6 ; .. 6 Felder M20B: cpi R19,$B0 ; Wenn Mode B brne M21 ; ldi R16,2 ; .. 2 Felder ; M21: lds R20,MODE ; Sonderbehandlung Mode = 10/0 cpi R20,$A0 ; (Edit CW-ID) brne M21R ; lds R20,CURCID ; Links-Rechtsdrehen ändert CURCID sbrs R17,0 rjmp M21CL inc R20 sts CURCID,R20 cpi R20,$10 ; Überlauf Rechts breq M21R ; .. dann Mode weiterschalten rjmp M22 ; M21CL: sbrs R17,1 rjmp M22 dec R20 sts CURCID,R20 cpi R20,$FF ; Unterlauf links breq M21L ; .. dann Mode runterschalten rjmp M22 M21R: sbrs R17,0 ; Normalbehandlung: Rechts drehen rjmp M21L sound SOUPOP ; Quittungston inc R18 ; Mode hochzählen cp R18,R16 brne M21L clr R18 ; M21L: sbrs R17,1 ; Links drehen rjmp M22 sound SOUPOP ; Quittungston 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 M399 sound SOUPAP stsi PROTO,$01 ; .... Senden anfordern rjmp M399 ; M301: cpi R18,1 ; Mode 0/1: Hex Sendebyte 0 brne M302 udlo OUT2B+0 ; richtiges Nibble ändern rjmp M399 M302: cpi R18,2 ; Mode 0/2 brne M303 udhi OUT2B+1 ; richtiges Nibble ändern rjmp M399 M303: cpi R18,3 ; Mode 0/3 brne M304 udlo OUT2B+1 ; richtiges Nibble ändern rjmp M399 M304: cpi R18,4 ; Mode 0/4 = Register im Fuchs abfragen brne M305 sbrs R17,4 ; .. und Click: rjmp M305 sound SOUPAP stsi PROTO,$28 ; .... Lesekommando bauen und senden rjmp M399 M305: cpi R18,5 ; Mode 0/5: RAM Adresse ändern brne M306 udhi RAMADR ; richtiges Nibble ändern rjmp M399 M306: cpi R18,6 ; Mode 0/6 brne M307 udhilo RAMADR ; richtiges Nibble ändern rjmp M399 M307: cpi R18,7 ; Mode 0/7: Hex<> -> Extras brne M310 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$46 ; Neuer Mode 4/6 sts MODE,R18 stsi PROTO,$21 ; FoxID lesen sound SOUPIP rjmp M399 ; M310: cpi R18,$10 ; Mode 1/0: Programm Uhrzeit Stunden brne M311 ldi ZL,low(STA0) call UDZ6 rjmp M399 ; M311: cpi R18,$11 ; Mode 1/1: Programm Uhrzeit 10 Minuten brne M312 M3111: ldi ZL,low(STA0) call UDZ1 rjmp M399 ; M312: cpi R18,$12 ; Mode 1/2: Programm Uhrzeit 1 Minute brne M313 call UDZMIN ; Minute ändern 0..9 rjmp M3111 ; Eventuellen 10-Minuten-Übertrag handeln ; M313: cpi R18,$13 ; Mode 1/3: Programm Uhrzeit Sekunden auf 0 brne M314 sbrs R17,4 ; Klicken rjmp M399 stsi TIK10,0 lds R16,STA2 ; Sendedauer in Bit 7,6 erhalten andi R16,$C0 sts STA2,R16 sound SOUPIP rjmp M399 ; M314: cpi R18,$14 ; Mode 1/4: Programm Fuchsanzahl 2..5 brne M315 call UDNFU rjmp M399 ; M315: cpi R18,$15 ; Mode 1/5: Sendezeit 12/15/30/60 brne M316 lds R16,STA2 ; Sendedauer separieren und einstellen swap R16 lsr R16 lsr R16 sbrc R17,2 dec R16 sbrc R17,3 inc R16 andi R16,$03 ; auf 0..3 begrenzen lds R20,STA2 ; Sendedauer in STA2 einsetzen und speichern andi R20,$3F swap R16 lsl R16 lsl R16 or R20,R16 sts STA2,R20 rjmp M399 ; M316: cpi R18,$16 ; Mode 1/6: Programm Menü Testzeiten starten brne M317 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$38 ; Neuer Mode 3/8 sts MODE,R18 sound SOUPIP rjmp M399 ; M317: cpi R18,$17 ; Mode 1/7: Programm Sende-Startzeit Stunden brne M318 andi R17,$0C ; Nur wenn Gedrückt+Drehen breq M318 stsi STA3,0 ; Fuchsstatus auf Vorlauf ldi ZL,low(STA8) ; Stunden ändern call UDZ6 rjmp M3191 ; M318: cpi R18,$18 ; Mode 1/8: Programm Sende-Startzeit 10 Minuten brne M319 andi R17,$0C ; Nur wenn Gedrückt+Drehen breq M319 stsi STA3,0 ; Fuchsstatus auf Vorlauf ldi ZL,low(STA8) ; 10 Minuten ändern call UDZ1 rjmp M31A1 ; M319: cpi R18,$19 ; Mode 1/9: Programm Sende-Endzeit Stunden brne M31A M3191: ldi ZL,low(STA9) call UDZ6 rjmp M399 ; M31A: cpi R18,$1A ; Mode 1/10: Programm Sende-Endezeit 10 Minuten brne M31B M31A1: ldi ZL,low(STA9) call UDZ1 rjmp M399 ; M31B: cpi R18,$1B ; Mode 1/11: Programm Nachlauf toggeln brne M31C sbrs R17,4 ; .. und Click rjmp M399 lds R16,STA1 ldi R20,$80 eor R16,R20 sts STA1,R16 brmi M31B1 flash STRSU0,10 rjmp M31B2 M31B1: flash STRSU1,20 M31B2: sound SOUPAP rjmp M399 ; M31C: cpi R18,$1C ; Mode 1/12: Programm -> Menü brne M320 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$50 ; Neuer Mode 5/0 sts MODE,R18 sound SOUPIP rjmp M399 ; M320: cpi R18,$20 ; Mode 2/0: Fuchs Lesen brne M321 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$81 ; Neuer Mode 8/1 sts MODE,R18 sound SOUPIP rjmp M399 ; M321: cpi R18,$21 ; Mode 2/1: Fuchs Testsendung n Minuten starten brne M322 sbrs R17,4 ; .. und Click rjmp M399 lds R16,TXTIME ; Kommando gesichert an Fuchs sendenn lsl R16 ; Zeit ist TXTIME * 4 + 16 lsl R16 ldi R17,16 add R16,R17 sts OUT2B+1,R16 stsi OUT2B,$0A stsi PROTO,$10 sound SOUPIP rjmp M399 ; M322: cpi R18,$22 ; Mode 2/2: Fuchs Testsendung Dauer einstellen brne M323 lds R16,TXTIME sbrc R17,2 ; TXTime im Bereich 0..9 einstellen inc R16 sbrc R17,3 dec R16 tst R16 brne M3221 inc R16 rjmp M3222 M3221: cpi R16,10 brne M3222 dec R16 M3222: sts TXTIME,R16 rjmp M399 ; M323: cpi R18,$23 ; Mode 2/3: Fuchs Laden brne M324 sbrs R17,4 ; .. und Click rjmp M399 stsi PROTO,$30 ; Status Record senden, empfangen und vergleichen sound SOUPIP flash STRWAR,20 ; Anzeige Warten rjmp M399 ; M324: cpi R18,$24 ; Mode 2/4: Fuchs prüfen brne M325 sbrs R17,4 ; .. und Click rjmp M399 stsi PROTO,$40 ; Status Record empfangen und vergleichen sound SOUPIP flash STRWAR,20 ; Anzeige Warten rjmp M399 ; M325: cpi R18,$25 ; Mode 2/5: Fuchs -> Extras brne M326 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$47 ; Neuer Mode 4/7 sts MODE,R18 stsi PROTO,$21 ; Fuchs-ID lesen sound SOUPAP rjmp M399 ; M326: cpi R18,$26 ; Mode 2/6: Fuchs -> Menü brne M330 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$52 ; Neuer Mode 5/2 sts MODE,R18 sound SOUPIP rjmp M399 ; M330: cpi R18,$30 ; Mode 3/0: Testlauf Test1 Ein/Aus brne M331 sbrs R17,4 ; .. und Click rjmp M399 sound SOUPAP lds R16,STA4 cpi R16,$FF brne M3301 stsi STA4,72 stsi STA5,73 rjmp M399 M3301: stsi STA4,$FF rjmp M399 ; M331: cpi R18,$31 ; Mode 3/1: Testlauf Test1 Startzeit 1 Stunde brne M332 ldi ZL,low(STA4) call UDZ6 ldi ZL,low(STA5) call UDZ6 rjmp M399 ; M332: cpi R18,$32 ; Mode 3/2: Testlauf Test1 Startzeit 10 Minuten brne M333 ldi ZL,low(STA4) call UDZ1 rjmp M3331 ; M333: cpi R18,$33 ; Mode 3/3: Testlauf Test1 Endezeit 10 Minuten brne M334 M3331: ldi ZL,low(STA5) call UDZ1 rjmp M399 ; M334: cpi R18,$34 ; Mode 3/4: Testlauf Test2 Ein/Aus brne M335 sbrs R17,4 ; .. und Click rjmp M399 sound SOUPAP lds R16,STA6 cpi R16,$FF brne M3341 stsi STA6,72 stsi STA7,73 rjmp M399 M3341: stsi STA6,$FF rjmp M399 ; M335: cpi R18,$35 ; Mode 3/5: Testlauf Test2 Startzeit 1 Stunde brne M336 ldi ZL,low(STA6) call UDZ6 ldi ZL,low(STA7) call UDZ6 rjmp M399 ; M336: cpi R18,$36 ; Mode 3/6: Testlauf Test2 Startzeit 10 Minuten brne M337 ldi ZL,low(STA6) call UDZ1 rjmp M3371 ; M337: cpi R18,$37 ; Mode 3/7: Testlauf Test2 Endezeit 10 Minuten brne M338 M3371: ldi ZL,low(STA7) call UDZ1 rjmp M399 ; M338: cpi R18,$38 ; Mode 3/8: Testlauf -> Programm brne M340 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$16 ; Neuer Mode 1/6 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 M3409 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,$F8 or R20,R16 sts FOXID,R20 stsi PROTO,$20 ; FoxID in Fuchs laden und zurücklesen M3409: rjmp M399 ; M341: cpi R18,$41 ; Mode 4/1: Extras Tastgeschwindigkeit brne M342 mov R16,R17 ; Wenn gedrückt+gedreht andi R16,$0C breq M3419 lds R16,FOXID ; Tastung separieren und einstellen swap R16 lsr R16 lsr R16 sbrc R17,2 dec R16 sbrc R17,3 inc R16 andi R16,$03 ; auf 0..3 begrenzen lds R20,FOXID ; Tastung in FOXID einsetzen und speichern andi R20,$37 swap R16 lsl R16 lsl R16 or R20,R16 sts FOXID,R20 stsi PROTO,$20 ; FoxID in Fuchs laden und zurücklesen M3419: rjmp M399 ; M342: cpi R18,$42 ; Mode 4/2: Extras Modulation brne M343 mov R16,R17 ; Wenn gedrückt+gedreht andi R16,$0C breq M3429 lds R16,FOXID ; Modulation separieren und einstellen swap R16 sbrc R17,2 dec R16 sbrc R17,3 inc R16 andi R16,$03 ; auf 0..3 begrenzen lds R20,FOXID ; Modulation in FOXID einsetzen und speichern andi R20,$C7 swap R16 or R20,R16 sts FOXID,R20 stsi PROTO,$20 ; FoxID in Fuchs laden und zurücklesen M3429: rjmp M399 ; M343: cpi R18,$43 ; Mode 4/3: Extras -> CW-ID eingeben brne M344 stsi ATXEIN,0 ; .. Cleanup für Mode 4/4 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$A5 ; Neuer Mode 10/5 sts MODE,R18 sound SOUPIP rjmp M399 ; M344: cpi R18,$44 ; Mode 4/4: Extras Sender-Ein-/Ausschalten brne M345 sbrs R17,4 ; .. und Click rjmp M399 lds R16,ATXEIN ; TXEin-Flag toggeln 0 <> * ldi R20,'*' eor R16,R20 sts ATXEIN,R16 sound SOUPIP rjmp M399 ; M345: cpi R18,$45 ; Mode 4/5 Oszillator messen brne M346 stsi ATXEIN,0 ; .. Cleanup für Mode 4/3 sbrs R17,4 ; .. und Click rjmp M399 sound SOUPIP stsi OUT2B,$0C ; .. Oszillator-Mess-Mode starten stsi PROTO,$01 rjmp M399 ; M346: cpi R18,$46 ; Mode 4/6: Extras -> Hex<> brne M347 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$07 ; Neuer Mode 0/7 sts MODE,R18 sound SOUPIP rjmp M399 ; M347: cpi R18,$47 ; Mode 4/7: Extras -> Fuchs brne M350 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$25 ; Neuer Mode 2/5 sts MODE,R18 sound SOUPIP rjmp M399 ; M350: cpi R18,$50 ; Mode 5/0: Menü -> Programm brne M351 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$97 ; .. Neuer Mode 9/7 lds R16,EXPERT ; .. ausser wenn Programmierexperte tst R16 breq M3502 ldi R18,$1C ; .. dann neuer Mode 1/12 M3502: sts MODE,R18 sound SOUPIP rjmp M399 ; M351: cpi R18,$51 ; Mode 5/1: Programm wechseln brne M352 sbrs R17,4 ; .. und Click rjmp M399 lds R16,CONFIG ; Wenn Programmzahl = 1 andi R16,6 brne M3512 sound SOUPAP ; .. nichts tun rjmp M399 M3512: ldi R18,$B1 ; .. sonst neuer Mode 11/1 sts MODE,R18 sound SOUPIP rjmp M399 ; M352: cpi R18,$52 ; Mode 5/2: Menü -> Fuchs brne M353 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$26 ; Neuer Mode 2/6 sts MODE,R18 sound SOUPIP rjmp M399 ; M353: cpi R18,$53 ; Mode 5/3: Menü -> StartZiel brne M360 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$70 ; Neuer Mode 7/0 sts MODE,R18 sound SOUPIP call MSTRT ; Anzeige vorbereiten 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 M3608: andi R17,$0C ; Gedrückt + gedreht? breq M3609 flash STRVHX,10 ; .. dann Hex-Werte flashen M3609: rjmp M399 ; 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 rjmp M3608 ; M362: cpi R18,$62 ; Mode 6/2: Zahl der Programme einstellen 0..2 brne M363 lds R16,CONFIG lsr R16 sbrc R17,2 ; Drücken+drehen inc R16 ; Korrekturfaktor ändern sbrc R17,3 dec R16 cpi R16,-1 brne M3621 ldi R16,0 M3621: cpi R16,3 brne M3629 ldi R16,2 M3629: lds R17,CONFIG ; Mit Sprachwahl-Bit zusammenbauen ror R17 rol R16 sts CONFIG,R16 rjmp M399 ; M363: cpi R18,$63 ; Mode 6/3: Sprache Umschalten brne M364 sbrs R17,4 ; .. und Click rjmp M399 lds R16,CONFIG ; Sprache toggeln (Bit 0 von CONFIG) ldi R19,$01 eor R16,R19 sts CONFIG,R16 sound SOUPIP rjmp M399 ; M364: cpi R18,$64 ; Mode 6/4: Eichen-> Hauptmenü brne M370 sbrs R17,4 ; .. und Click rjmp M399 call 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: StartZiel Start Benden brne M371 sbic PINC,2 ; Wenn Schalter auf Sicher rjmp M3721 ; .. neuer Mode 7/2 M3701: ldi R18,$70 sts MODE,R18 sbrs R17,4 ; Click rjmp M399 ldi R18,$53 ; .. Neuer Mode 5/3 sts MODE,R18 sound SOUPIP rjmp M399 ; M371: cpi R18,$71 ; Mode 7/1: StartZiel Start Minuten Ändern brne M372 sbic PINC,2 ; Wenn Schalter auf Sicher rjmp M3721 ; .. neuer Mode 7/2 call UDSTAM rjmp M399 ; M372: cpi R18,$72 ; Mode 7/2: StartZiel Ziel brne M380 sbis PINC,2 ; Wenn Schalter auf Ändern rjmp M3701 ; .. neuer Mode 7/0 M3721: ldi R18,$72 sts MODE,R18 lds R16,ZZDISP sbrs R17,0 ; Drehen ohne Drücken rjmp M3722 lds R18,ZZEND ; .. Display-Pointer ändern cp R16,R18 ; .. im Bereich 0 .. ZZEND breq M3722 inc R16 M3722: sbrs R17,1 rjmp M3723 tst R16 breq M3723 dec R16 M3723: sts ZZDISP,R16 rjmp M399 ; M380: cpi R18,$80 ; Mode 8/0: Abfrage Clonen Ja brne M381 sbrs R17,4 ; .. und Click rjmp M399 stsi PROTO,$50 ; Status Record empfangen und laden flash STRWAR,20 ; Anzeige Warten stsi EXPERT,1 ; Expertenmodus für Programmeingabe einschalten rjmp M3811 ; M381: cpi R18,$81 ; Mode 8/1: Abfrage Clonen Zurück brne M390 sbrs R17,4 ; .. und Click rjmp M399 M3811: ldi R18,$20 ; Neuer Mode 2/0 sts MODE,R18 sound SOUPIP rjmp M399 ; M390: cpi R18,$90 ; Mode 9/0: Programm Uhrzeit Stunden brne M391 ldi ZL,low(STA0) call UDZ6 rjmp M399 ; M391: cpi R18,$91 ; Mode 9/1: Programm Uhrzeit 10 Minuten brne M392 M3911: ldi ZL,low(STA0) call UDZ1 rjmp M399 ; M392: cpi R18,$92 ; Mode 9/2: Programm Uhrzeit 1 Minute brne M393 call UDZMIN ; Minute ändern 0..9 rjmp M3911 ; Eventuellen 10-Minuten-Übertrag handeln ; M393: cpi R18,$93 ; Mode 9/3: Programm Uhrzeit Sekunden auf 0 brne M394 sbrs R17,4 ; Klicken rjmp M399 stsi TIK10,0 lds R16,STA2 ; Sendedauer in Bit 7,6 erhalten andi R16,$C0 sts STA2,R16 sound SOUPAP rjmp M399 ; M394: cpi R18,$94 ; Mode 9/4: Programm Sende-Startzeit 10 Minuten brne M395 andi R17,$0C ; Nur wenn Gedrückt+Drehen breq M3949 stsi STA3,0 ; Fuchsstatus auf Vorlauf ldi ZL,low(STA8) ; 10 Minuten ändern call UDZ1 M3949: rjmp M399 ; M395: cpi R18,$95 ; Mode 9/5: Programm Sende-Endezeit 10 Minuten brne M396 ldi ZL,low(STA9) call UDZ1 rjmp M399 ; M396: cpi R18,$96 ; Mode 9/6: Expertenmodus einschalten brne M397 sbrs R17,4 ; .. und Click rjmp M399 stsi EXPERT,1 ; Expertenmodus-Flag setzen ldi R18,$1C ; Neuer Mode 1/12 sts MODE,R18 sound SOUPIP rjmp M399 ; M397: cpi R18,$97 ; Mode 9/7: Programm -> Menü brne M3A0 sbrs R17,4 ; .. und Click rjmp M399 ldi R18,$50 ; Neuer Mode 5/0 sts MODE,R18 sound SOUPIP rjmp M399 ; M3A0: cpi R18,$A0 ; Mode 10/0: CW-ID Text editieren brne M3A1 ldi XL,low(CWID+1) ; Pointer auf aktuelles Zeichen bauen ldi XH,high(CWID+1) lds R16,CURCID ; @CWID + 1 + CURCID add XL,R16 ld R16,X ; Aktuelles Zeichen holen sbrc R17,3 ; .. und ändern dec R16 sbrc R17,2 inc R16 cpi R16,'-'-1 ; Wrappen - / . 0..9 A..Z brne M3A02 ldi R16,'-' M3A02: cpi R16,'Z'+1 brne M3A03 ldi R16,'Z' M3A03: cpi R16,'9'+1 brne M3A04 ldi R16,'A' M3A04: cpi R16,'A'-1 brne M3A09 ldi R16,'9' M3A09: st X,R16 rjmp M399 ; M3A1: cpi R18,$A1 ; Mode 10/1: CW-ID Tastgeschwindigkeit einstellen brne M3A2 stsi CURCID,$0F ; Cursor vorbereiten für Mode 10/0 lds R16,CWID mov R20,R16 ; Obere Bits retten andi R20,$F8 sbrc R17,2 dec R16 sbrc R17,3 inc R16 andi R16,$07 ; auf 0..7 begrenzen or R16,R20 sts CWID,R16 rjmp M399 ; M3A2: cpi R18,$A2 ; Mode 10/2: Beginn/Ende toggeln brne M3A3 sbrs R17,4 ; .. und Click rjmp M399 lds R16,CWID ; CWID Bit 3 toggeln ldi R20,$08 eor R16,R20 sts CWID,R16 sound SOUPIP rjmp M399 ; M3A3: cpi R18,$A3 ; Mode 10/3: CW-ID nach Fuchs laden brne M3A4 sbrs R17,4 ; .. und Click rjmp M399 sound SOUPIP call LOADID ; 17B CWID in 18B IOCWID übersetzen stsi PROTO,$80 ; 18B IOCWID in Fuchs laden und prüfen rjmp M399 ; M3A4: cpi R18,$A4 ; Mode 10/4: CW-ID aus Fuchs lesen brne M3A5 sbrs R17,4 ; .. und Click rjmp M399 stsi PROTO,$C0 ; 18B CWID aus Fuchs holen sound SOUPIP rjmp M399 ; M3A5: cpi R18,$A5 ; Mode 10/5: CW-ID -> Fuchs Extras brne M3B0 stsi CURCID,$00 ; Cursor vorbereiten für Mode 10/0 sbrs R17,4 ; .. und Click rjmp M399 call SAVCID ; Alle Einstellungen im EEPROM speichern ldi R18,$43 ; Neuer Mode 4/3 sts MODE,R18 sound SOUPIP rjmp M399 ; M3B0: cpi R18,$B0 ; Mode 11/0: Abfrage Programmwechsel Ja brne M3B1 sbrs R17,4 ; .. und Click rjmp M399 call PSWAP ; Swap Program sound SOUOK rjmp M3B11 ; M3B1: cpi R18,$B1 ; Mode 11/1: Abfrage Programmwechsel Zurück brne M399 sbrs R17,4 ; .. und Click rjmp M399 sound SOUPIP M3B11: ldi R18,$51 ; Neuer Mode 5/1 sts MODE,R18 rjmp M399 ; ; M399: stsi TAK33,0 ; Siehe Erläuterungen vor MAIN7: sbrs R17,5 ; Wenn Zieltaster Click rjmp M3999 rcall ZZREG ; .. Zielzeit registrieren rcall ZZCONV ; .. Zielzeiten aus Tabelle holen flash STRM7Z,100 ; .. und 10 Sekunden zeigen M3999: ; ; ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; +++ Alle 33 ms: Handeln der Übertragung Bediengerät <> Fuchs gemäß PROTO +++ ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; Protokollsteuerung für IF zum Fuchs (OUT2B>Fuchs>IN2B) ; Protokoll wird alle 33 ms abgewickelt, wenn nicht ; anders angegeben, wird PROTO dabei um 1 erhöht ; $00 Ruhe ; $01 Register laden ; $10 Register laden + verifizieren ; $20 FoxID laden, FoxID + EC-Level + CWID_Byte0 lesen ; $21 FoxID + EC-Level + CWID_Byte0 lesen ; $28 Register lesen (Reg# in OUT2B, OUT2B erhalten) ; $30 Status nach Fuchs laden ; $40 Status im Fuchs prüfen ; $50 Status aus Fuchs lesen (Clonen) ; $80/90 CWID (18B) in Fuchs laden ; $A0/B0 CWID (18B) aus Fuchs lesen ; Detaillierte Beschreibung unten bei der Funktion ; ; Das 33ms-Flag TAK33 wird alle 33 ms vom Interrupt-Handler gesetzt ; Nach längeren Codesequenzen in Main wird es (falls gesetzt) gelöscht, ; sonst können durch den Zeitversatz Übertragungen überlappen ; MAIN7: lds R16,TAK33 ; 33 ms Flag testen tst R16 brne M70 rjmp M7999 M70: stsi TAK33,0 ; lds R16,PROTO ; Derzeitiger Protokollstate in R16 mov R17,R16 ; andi R17,$F0 ; High Nibble davon in R17 ; cpi R16,$01 ; $01 = OUT2B senden breq M701 cpi R17,$10 ; $1x = Register laden und verifizieren brne M72 rjmp M71X M72: cpi R17,$20 ; $2x = FoxID/EC lesen brne M73 rjmp M72X M73: cpi R17,$30 ; $3x = Status an Fuchs senden brne M74 rjmp M73X M74: cpi R17,$40 ; $4x = Status aus Fuchs prüfen brne M75 rjmp M74X M75: cpi R17,$50 ; $5x = Status aus Fuchs clonen brne M78 rjmp M75X M78: andi R17,$E0 cpi R17,$80 ; $8/9x = CWID aus IOCWID in Fuchs laden brne M7A rjmp M76X M7A: cpi R17,$A0 ; $A/Bx = CWID aus Fuchs mit IOCWID vergleichen brne M7C rjmp M7AX M7C: cpi R17,$C0 ; $C/Dx = CWID aus Fuchs lesen nach IOCWID brne M7XX rjmp M7CX M7XX: stsi PROTO,$00 ; $00 oder kein gültiger Zustand: löschen rjmp M799 ; und fertig ; ; ; Register laden ; $01 OUT2B Senden, -> $00 M701: stsi SERFLG,2 ; TX Start Flag für OUT2B senden stsi PROTO,0 ; Flag löschen rjmp M799 ; ; Register Laden/Verifizieren ; $10 Load-Command OUT2B senden ; $11 Read Command dazu senden ; $12 Wert empfangen und vergleichen, -> 00 M71X: cpi R16,$12 breq M712 cpi R16,$13 breq M713 ; M711: lds R16,OUT2B ; OUT2B für Compare retten sts SAVE2B,R16 lds R16,OUT2B+1 sts SAVE2B+1,R16 stsi SERFLG,2 ; TX Start Flag für Load senden rjmp M798 ; M712: stsi OUT2B,$0F lds R16,SAVE2B sts OUT2B+1,R16 stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M713: lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R16,IN2B+1 ; .. Ja: Ergebnis vergleichen lds R17,SAVE2B+1 cp R16,R17 breq M7139 rjmp M7SYNC M7139: stsi PROTO,0 rjmp M799 ; ; FoxID laden, FoxID und EC-Level und CWID_Byte0 lesen ; $20 'Load FOXID'senden ; $21 'Read FOXID' senden ; $22 FOXID empfangen, 'Read EC' senden ; $23 EC Empfangen, 'Read EEPROM' senden ; $24 CWID_Byte0 empfangen, -> 00 ; Register lesen ; $28 Read senden, Reg# in OUT2B+1 ; $29 Inhalt empfangen in IN2B+1, ->00 ; M720: stsi OUT2B,$0B ; Load FoxID Command lds R16,FOXID sts OUT2B+1,R16 stsi SERFLG,2 ; TX Start Flag für Load senden rjmp M798 M721: stsi OUT2B,$0F ; Read FoxID Command stsi OUT2B+1,$0B stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M722: stsi FOXID,$FF ; Default: ungültig lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMS lds R16,IN2B+1 ; .. Ja: FoxID ablegen sts FOXID,R16 stsi OUT2B,$0F ; Read EC Command stsi OUT2B+1,$0C stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M72X: cpi R16,$20 breq M720 cpi R16,$21 breq M721 cpi R16,$22 breq M722 cpi R16,$23 breq M723 cpi R16,$24 breq M724 cpi R16,$28 breq M728 cpi R16,$29 breq M729 ; M723: stsi VERSHL,$FF ; Default: ungültig lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMS lds R16,IN2B+1 ; .. Ja: FoxID ablegen sts VERSHL,R16 stsi OUT2B,$0F ; Read EEPROM Command stsi OUT2B+1,$0E stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M724: stsi IOCWB0,$FF lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMS lds R16,IN2B+1 ; .. Ja: EC ablegen sts IOCWB0,R16 stsi PROTO,0 rjmp M799 ; M728: lds R17,OUT2B+1 ; Alten Wert OUT2B retten sts OUT2B+2,R17 lds R17,OUT2B sts OUT2B+1,R17 stsi OUT2B,$0F ; Read Register Command stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M729: lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO stsi PROTO,0 lds R17,OUT2B+1 ; Alten Wert von OUT2B wiederherstellen sts OUT2B,R17 lds R17,OUT2B+2 sts OUT2B+1,R17 rjmp M799 ; ; Status nach Fuchs laden ; $30 Read FoxID senden ; $31 FoxID empfangen, wenn nötig Programm wechseln ; $32 Warten auf Zeit TIK10 = 0 ; Wenn erreicht; STA0 senden ; ..$3B STA9 senden, -> $40 M73X: cpi R16,$30 brne M731 stsi OUT2B,$0F ; Read FoxID Command stsi OUT2B+1,$0B stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M731: cpi R16,$31 brne M732 stsi FOXID,$FF ; Default: ungültig lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R16,IN2B+1 ; .. Ja: FoxID ablegen sts FOXID,R16 call P2SWAP ; Wenn nötig, Programm 80<>2 wechseln rjmp M798 ; M732: cpi R16,$32 brne M733 lds R17,TIK10 ; Zeit TIK10=0 erreicht? cpi R17,0 breq M733 rjmp M799 ; Nein, in diesem Protokollschritt bleiben ; Der folgende Code behandelt $33..$3B M733: andi R16,$0F ; Schussnummer 0..9 dec R16 dec R16 ldi XL,low(STA0) ; Pointer auf STA add XL,R16 ldi XH,1 ld R17,X sts OUT2B,R16 ; Schussnummer = Registernummer sts OUT2B+1,R17 stsi SERFLG,2 ; TX Start Flag cpi R16,9 ; Wenn letzter Schuss brne M7339 stsi PROTO,$40 ; Weiter mit Prüfen rjmp M799 M7339: rjmp M798 ; ; Status in Fuchs prüfen ; $40 Warten auf Zeit TIK10 = 5 ; Wenn erreicht: Read STA0 senden ; $41 INSTA0 empfangen, Read STA1 senden ; ..$4A INSTA9 empfangen, Read FOXID senden ; $4B FoxID empfangen, wenn nötig Programm wechseln, ; STA-INSTA vergleichen, -> 0 M74X: cpi R16,$40 breq M740 cpi R16,$4B breq M74B rjmp M741 ; behandelt $41..$4A ; M740: lds R17,TIK10 ; Zeit TIK10=5 erreicht? cpi R17,5 brne M7409 clr R16 ; Read STA 0 Command senden rjmp M7411 M7409: rjmp M799 ; M741: andi R16,$0F ; Schussnummer 0..9 dec R16 ldi XL,low(INSTA) add XL,R16 ldi XH,1 lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R17,IN2B+1 ; .. Ja: Schuss ablegen st X,R17 inc R16 cpi R16,$0A ; Sonderfall letzter Schuss (FoxID) brne M7411 inc R16 M7411: stsi OUT2B,$0F ; Read Command sts OUT2B+1,R16 stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M74B: lds R17,SERFLG ; Read FoxID complete? sbrs R17,0 rjmp M7TIMO lds R17,IN2B+1 ; Ja: Schuss ablegen sts FOXID,R17 andi R17,$07 sts XFUCHS,R17 ; Fuchs# für Erfolgsmeldung call P2SWAP ; Wenn nötig Programm 80<>2 wechseln M74B0: ldi YL,low(STA0) ; STA mit INSTA vergleichen ldi YH,1 M74B1: ldd R16,Y+10 ld R17,Y+ cp R16,R17 breq M74B2 rjmp M7SYNC ; Ungleich: Fehlermeldung M74B2: cpi YL,low(INSTA) ; 10 Passes brne M74B1 stsi PROTO,$00 sound SOUOK flash STROK,20 M74B3: rjmp M799 ; ; Status aus Fuchs lesen (Clonen) ; $50 Read FoxID senden ; $51 FoxID empfangen, wenn nötig Programm wechseln ; $52 Read command TIK30 senden ; $53 TIK30 empfangen, wenn <> 0..1 -> $50, sonst Read STA0 senden ; $54 INSTA0 empfangen, Read STA1 senden ; ..$5D INSTA9 empfangen, STA:=INSTA, TIK10 := 4, -> 0 ; M750: stsi OUT2B,$0F ; Read FoxID Command stsi OUT2B+1,$0B stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M751: stsi FOXID,$FF ; Default: ungültig lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R16,IN2B+1 ; .. Ja: FoxID ablegen sts FOXID,R16 call P2SWAP ; Wenn nötig, Programm 80<>2 wechseln rjmp M798 M752: stsi OUT2B,$0F ; Read TIK30 Command stsi OUT2B+1,$0D stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M753: lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R17,IN2B+1 ; .. Ja: Zeit = 0,1? andi R17,$FE brne M7532 clr R16 ; Read STA 0 senden rjmp M7541 M7532: stsi SERFLG,2 ; Zeit <> 0,1: neues Read senden rjmp M799 ; M75X: cpi R16,$50 breq M750 cpi R16,$51 breq M751 cpi R16,$52 breq M752 cpi R16,$53 breq M753 cpi R16,$5D breq M75D rjmp M754 ; $52..$5A behandeln ; M754: andi R16,$0F ; Schussnummer 0..9 ldi R17,4 sub R16,R17 ; .. aus Protokollstatus ldi XL,low(INSTA) add XL,R16 ldi XH,1 lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R17,IN2B+1 ; .. Ja: Schuss ablegen st X,R17 inc R16 M7541: stsi OUT2B,$0F ; Read Command sts OUT2B+1,R16 stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M75D: lds R17,SERFLG ; Read STA9 complete? sbrs R17,0 rjmp M7TIMO lds R17,IN2B+1 ; .. Ja: Schuss ablegen sts INSTA+9,R17 ldi YL,low(STA0) ; INSTA nach STA kopieren ldi YH,1 M75D1: ldd R17,Y+10 st Y+,R17 cpi YL,low(INSTA) ; 10 Passes brne M75D1 stsi TIK10,4 ; Bediengeräte-Uhr an Fuchs angleichen sound SOUOK flash STRCLO,20 stsi PROTO,$00 rjmp M799 ; ; IOCWID (18 Byte) nach Fuchs laden und prüfen ; $80 Lade EEADR = 1 senden ; $81 CWID Byte 0 ; ..$92 .. Byte 17 senden -> $A0 (prüfen, siehe unten) M76X: cpi R16,$80 brne M761 stsi OUT2B,$0D ; EEADR auf 1 setzen stsi OUT2B+1,$01 stsi SERFLG,2 ; TX Start Flag rjmp M798 M761: andi R16,$1F ; Schussnummer 1..18 ldi XL,low(IOCWID-1) ; Pointer auf STA-Wert add XL,R16 ldi XH,1 ld R17,X stsi OUT2B,$0E ; Ein Schuss ins EEPROM @ EEADR+ sts OUT2B+1,R17 stsi SERFLG,2 ; TX Start Flag cpi R16,18 ; Wenn letzter Schuss brne M7619 stsi PROTO,$A0 ; Fertig, weiter mit Prüfen rjmp M799 M7619: rjmp M798 ; ; ; CWID aus Fuchs lesen und vergleichen mit IOCWID ; $A0 Lade EEADR = 1 senden ; $A1 Read EEPROM senden ; $A2..$B2 CWID(0)..(16) empfangen und vergleichen Read EEPROM senden ; $B3 CWID(17) empfangen und vergleichen, -> 0 ; M7AX: cpi R16,$A0 breq M7C0 cpi R16,$A1 breq M7C1 rjmp M7A2 ; $52..$5A behandeln ; M7A2: andi R16,$1F ; Schussnummer 0..17 abspeichern ldi XL,low(IOCWID-2) add XL,R16 ldi XH,1 lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R17,IN2B+1 ; .. Ja: Schuss holen ld R18,X ; .. mit Sollwert vergleichen cp R17,R18 breq M7A21 rjmp M7SYNC M7A21: cpi R16,19 brne M7C1 ; Insgesamt 18 Read-Zyklen ; stsi PROTO,$00 ; Fertig und OK sound SOUOK flash STROKC,20 rjmp M799 ; ; CWID aus Fuchs lesen ; $C0 Lade EEADR = 1 senden ; $C1 Read EEPROM senden ; $C2..$D2 CWID(0)..(16) empfangen, Read EEPROM senden ; $D3 CWID(17) empfangen, ASCII-konvertieren, -> 0 ; M7CX: cpi R16,$C0 breq M7C0 cpi R16,$C1 breq M7C1 rjmp M7C2 ; $52..$5A behandeln ; M7C0: stsi OUT2B,$0D ; EEADR auf 1 setzen stsi OUT2B+1,$01 stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M7C1: stsi OUT2B,$0F ; Lese EEPROM Command senden stsi OUT2B+1,$0E stsi SERFLG,2 ; TX Start Flag für Read senden rjmp M798 ; M7C2: andi R16,$1F ; Schussnummer 0..17 abspeichern ldi XL,low(IOCWID-2) add XL,R16 ldi XH,1 lds R17,SERFLG ; Read complete? sbrs R17,0 rjmp M7TIMO lds R17,IN2B+1 ; .. Ja: Schuss ablegen st X,R17 cpi R16,19 brne M7C1 ; Insgesamt 18 Read-Zyklen ; rcall GETID ; Fertig: ID nach ASCII übersetzen stsi PROTO,$00 sound SOUOK rjmp M799 ; ; Keine Antwort auf Read (Timeout) M7TIMO: flash STRTOT,20 ; Timeout-Message flashen sound SOUNOK ; Piepsen stsi PROTO,0 ; .. und Protokoll abbrechen rjmp M799 ; Dto. ohne Piepsen M7TIMS: flash STRTOT,5 ; Timeout-Message flashen stsi PROTO,0 ; .. und Protokoll abbrechen rjmp M799 ; ; Fuchs nicht synchron M7SYNC: flash STRNOK,20 ; Nicht Synchron Message flashen sound SOUNOK ; .. und piepsen stsi PROTO,0 ; .. und Protokoll abbrechen rjmp M799 ; ; Fertig, Protokoll weiterschalten M798: lds R16,PROTO ; Protokoll weiterschalten inc R16 sts PROTO,R16 ; Fertig, nicht weiterschalten M799: lds R16,SERFLG ; RX complete Flag löschen andi R16,$FE sts SERFLG,R16 ; Fertig ; M7999: ; +++ Ende 33 msec Service ; ; ++++++++++++++++++++++++++++++++++++++++++++ ; ++++ Zur vollen Sekunde: Status-Update etc. ++++++++++++++++ ; ++++++++++++++++++++++++++++++++++++++++++++ ; MAIN4: lds R16,TAK1S ; 1 s Flag testen tst R16 brne M40 rjmp M49 M40: stsi TAK1S,0 ; ; ++ Display-Beleuchtung lds R16,LEDTIM ; LED-Nachleuchtzeit handeln tst R16 ; Wenn > 0 breq M42 dec R16 ; .. dekrementieren sts LEDTIM,R16 ; ; ++ Status-Record weiterzählen, Zeit bis nächsten Start ausrechnen M42: rcall TITOS ; Zeit bis Start ausrechnen rcall NXTSTA ; ; ++ Starttöne erzeugen lds R16,MODE ; Wenn Modus = Start (nicht Ziel) cpi R16,$70 breq M422 cpi R16,$71 brne M43 M422: rcall MSTRT ; .. Start-Töne erzeugen ; ; Reset-Impuls an PD0 für Klassik-Füchse erzeugen M43: lds R16,ATITOS+3 ; Rest-Sekunden bis nächster Start lds R17,ATITOS ; Rest-Minuten cpi R16,0 ; Wenn Rest-Sekunde = 0 brne M431 cbi DDRD,0 ; .. Puls beenden rjmp M44 M431: cpi R16,2 ; Wenn Rest-Sekunde = 2 brne M44 cpi R17,0 ; .. und Rest-Minute = 0 brne M44 sbi DDRD,0 ; .... Puls einschalten ; ; ; ++ Im Mode 'Extras' & Ändern jede zweite Sekunde FoxID/EC lesen M44: sbic PINC,2 ; Wenn Schalter auf Ändern rjmp M449 lds R16,MODE ; und Mode = 4 andi R16,$F0 cpi R16,$40 brne M449 lds R16,PROTO ; und Protokoll nicht busy tst R16 brne M449 lds R16,STA2 ; und gerade Sekunde andi R16,$01 brne M449 stsi PROTO,$21 ; Lesen FoxID/EC anstossen ; M449: stsi TAK33,0 ; Siehe Erläuterungen vor MAIN7: M49: ; ; ++++++++++++++++++++++++++++++++++ ; ++++ Alles weitere nur alle 100 ms: ++++++++++++++ ; ++++++++++++++++++++++++++++++++++ ; MAIN5: lds R16,TAK100 ; 100 ms Flag testen tst R16 brne M501 rjmp MAIN8 M501: stsi TAK100,0 ; rcall SOUGEN ; Soundgenerator handeln ; ; ++ Wenn Testsenden aktiv: Sender einschalten lds R16,ATXEIN ; Wenn TXEin-Flag gesetzt cpi R16,'*' brne MAIN51 lds R16,PROTO ; .. und Protokollhandler nicht belegt tst R16 brne MAIN51 stsi OUT2B,$0A ; .... Sender einschalten ohne Mod stsi OUT2B+1,$08 stsi PROTO,$01 MAIN51: ; ; ; +++++++++++++++++++++++++++++++++++ ; +++ 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: ; ; ++++++++++++++++++++++++++++++ ; ++++ Je nach Mode Display laden +++++++++++++++++++++++++++++ ; ++++++++++++++++++++++++++++++ MAIN6: rcall STA2A ; STA0..STA9, FoxID ins Anzeigeformat konvertieren ; lds R17,FLATIM ; Flash-Timer > 0 tst R17 breq M60 dec R17 ; .. dann dekrementieren sts FLATIM,R17 rjmp M6MF ; .. 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 M62 cp R18,R16 ; Aktueller Modus = Tabellenentry? brne M61 ; Nein: weiterscannen mov R17,R0 ; Ja: Cursorposition aus Tabelle übernehmen M62: cpi R17,$FF ; Wenn Position = $FF brne M63 ; .. (für Edit CW-ID) lds R17,CURCID ; .. Position aus CURCID verwenden M63: 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 ; M6M00: stsi SCROLL,0 ; Bei 'nicht Sicher' Scroll-zähler auf Anfang ; M6M0: cpi R16,$00 ; Mode 0 brne M6M1 show STRM0 ; M6M1: cpi R16,$10 ; Mode 1 brne M6M2 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 M6M8 show STRM7S ; M6M8: cpi R16,$80 ; Mode 8 brne M6M9 show STRM8 ; M6M9: cpi R16,$90 ; Mode 9 brne M6MA show STRM9 ; M6MA: cpi R16,$A0 ; Mode A brne M6MB show STRMA ; M6MB: cpi R16,$B0 ; Mode B brne M6MFF show STRMB ; M6MFF: rjmp M6MF ; ; Schalter auf Sicher ; M6MX: stsi CURPOS,32 ; Cursor aus lds R17,SCROLL ; Wenn Scroll aktiv (Programmanzeige) tst R17 breq M6MX01 rjmp M6MY ; .. zur Programmanzeige ; M6MX01: cpi R16,$70 ; Wenn Mode = Ziel brne M6MX02 rcall ZZCONV ; .. Zielzeiten aus Tabelle holen show STRM7Z ; .. Zielzeiten anzeigen rjmp M6MF ; ; Statusanzeige ; M6MX02: lds R16,STA3 ; Fuchsmode holen andi R16,$70 ; und separieren swap R16 ; M6MX0: cpi R16,0 ; Fuchs Modus 0 brne M6MX1 show STRX0 ; M6MX1: cpi R16,1 ; Fuchs Modus 1 brne M6MX2 show STRX1 ; M6MX2: cpi R16,2 ; Fuchs Modus 2 brne M6MX3 show STRX2 ; M6MX3: cpi R16,3 ; Fuchs Modus 3 brne M6MX4 show STRX3 ; M6MX4: cpi R16,4 ; Fuchs Modus 4 brne M6MX9 lds R17,STA1 ; Suchmodus eingeschaltet? tst R17 brmi M6MX41 show STRX4 ; Nein, Anzeige Fertig rjmp M6MF M6MX41: lds R17,STA2 ; Ja. Sekunde kleiner 16? andi R17,$30 brne M6MX42 show STRX41 ; .. dann Anzeige Suchen/Sendet rjmp M6MF M6MX42: show STRX40 ; .. sonst Anzeige Suchen/Pause M6MX9: rjmp M6MF ; ; Programmanzeige (gescrollt) ; M6MY: lds R17,SCROLL cpi R17,1 ; Wenn Scrollzähler = 1 brne M6MY1 stsi SCROLL,2 ; .. Scrollzähler auf 2 setzen sound SOUPIP ; .. Screenwechsel ankündigen rjmp M6MX02 ; .. und Status anzeigen M6MY1: cpi R17,21 ; Wenn Scrollzähler=21 brne M6MY2 lds R18,STA4 ; .. und Test 1 eingeschaltet cpi R18,$FF breq M6MY11 show STRY1 ; .... Anzeige Y1 rjmp M6MY9 ; .... sonst überspringen M6MY11: ldi R17,41 M6MY2: cpi R17,41 ; Wenn Scrollzähler=41 brne M6MY3 lds R18,STA6 ; .. und Test 2 ausgeschaltet cpi R18,$FF breq M6MY21 show STRY2 ; .... Anzeige Y2 rjmp M6MY9 M6MY21: ldi R17,61 ; .... sonst überspringen M6MY3: cpi R17,61 ; Wenn Scrollzähler=61 brne M6MY4 show STRY3 ; ... Anzeige Y3 rjmp M6MY9 M6MY4: cpi R17,81 ; Wenn Scrollzähler=81 brne M6MY91 lds R18,STA1 ; und Suchmodus eingeschaltet? sbrc R18,7 rjmp M6MY41 ldi R17,99 rjmp M6MY91 M6MY41: show STRY41 ; .. Anzeige Y41 rjmp M6MY9 ; M6MY9: sound SOUPIP ; Screenwechsel ankündigen M6MY91: inc R17 ; Scrollzähler inkrementieren sts SCROLL,R17 cpi R17,100 ; .. bei 100 brne M6MY92 sound SOUPAP ; .... Ende-Ton M6MY92: cpi R17,102 ; .. bei 102 brne M6MF stsi SCROLL,0 ; .... fertig ; M6MF: stsi TAK33,0 ; Siehe Erläuterungen vor MAIN7: ; +++ Ende 100 ms Service ; MAIN8: ldi R16,$80 ; Sleep Mode enablen out MCUCR,R16 sleep ; .. und schlafen bis zum nächsten 4,8kHz Event ; MAIN99: jmp 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 ; ; Zeit (n x 10') in R16 in 3 BCD in R1 (H), R2, R3 (L) wandeln ; und ablegen auf Adresse Z-> Z3BCD: push R17 push R18 ldi R17,10 ldi R18,6 clr R1 ; BCD-Startwert 000 clr R2 clr R3 inc R16 ; Z3BC1: dec R16 ; Loop bis R16 auf 0 breq Z3BC9 inc R3 cp R3,R18 ; 10-Minuten-Zähler wrapped bei 6 brne Z3BC1 clr R3 inc R2 cp R2,R17 ; Stunden-Zähler wrapped bei 10 brne Z3BC1 clr R2 inc R1 rjmp Z3BC1 ; Z3BC9: ldi ZH,1 st Z,R1 std Z+1,R2 std Z+2,R3 pop R18 pop R17 ret ; ; ; ######################################## ; #### Status etc. in Anzeigeformat wandeln ############################# ; ######################################## ; ;++ Uhrzeit STA2A: push R16 push R17 push R18 ; lds R16,STA0 ; Uhrzeit 10 Minuten + Stunden ldi ZL,low(AUHRZ) rcall Z3BCD lds R16,STA1 ; Uhrzeit Minuten Einer andi R16,$0F sts AUHRZ+3,R16 lds R16,STA2 ; Uhrzeit Sekunden andi R16,$3F ; Sendedauer entfernen rcall B3BCD sts AUHRZ+4,R2 sts AUHRZ+5,R3 ; ;++ Aktueller und letzter Fuchs lds R16,STA1 ; Letzter Fuchs swap R16 andi R16,$07 sts NFUCHS,R16 lds R16,STA3 ; Aktueller Fuchs andi R16,$07 sts AFUCHS,R16 ; ;++ Sendedauer lds R16,STA2 ; Bit 6,7 in STA2 andi R16,$C0 S2A00: cpi R16,$00 ; 0 ist 60" brne S2A01 stsi ATSEND,'6' stsi ATSEND+1,'0' rjmp S2A09 S2A01: cpi R16,$40 ; 1 ist 30" brne S2A02 stsi ATSEND,'3' stsi ATSEND+1,'0' rjmp S2A09 S2A02: cpi R16,$80 ; 2 ist 15" brne S2A03 stsi ATSEND,'1' stsi ATSEND+1,'5' rjmp S2A09 S2A03: cpi R16,$C0 ; 3 ist 12" brne S2A09 stsi ATSEND,'1' stsi ATSEND+1,'2' rjmp S2A09 S2A09: ; ;++ TST und NL-Flags lds R16,STA1 ; Suchmodus-(Nachlauf)-Flag prüfen sbrs R16,7 rjmp S2A11 stsi ANL,'S' stsi ANL+1,'M' rjmp S2A12 S2A11: stsi ANL,'s' stsi ANL+1,' ' S2A12: lds R16,STA4 ; Test 1 oder 2 eingeschaltet? cpi R16,$FF brne S2A13 lds R16,STA6 cpi R16,$FF breq S2A14 S2A13: stsi ATST,'T' rjmp S2A15 S2A14: stsi ATST,'t' S2A15: lds R16,P12 ; Programm 1 oder 2? cpi R16,1 brne S2A16 stsi AP12,'.' ; Punkt stsi AP12+1,'>' rjmp S2A19 S2A16: stsi AP12,':' stsi AP12+1,$FC S2A19: ; ; ;++ Start- und Endezeiten lds R16,STA5 ldi ZL,low(ASTA5) rcall Z3BCD lds R16,STA4 ldi ZL,low(ASTA4) rcall Z3BCD lds R17,STA4 lds R18,STA5 rcall S2ATX ; lds R16,STA7 ldi ZL,low(ASTA7) rcall Z3BCD lds R16,STA6 ldi ZL,low(ASTA6) rcall Z3BCD lds R17,STA6 lds R18,STA7 rcall S2ATX ; lds R16,STA8 ldi ZL,low(ASTA8) rcall Z3BCD lds R16,STA9 ldi ZL,low(ASTA9) rcall Z3BCD ; pop R18 pop R17 pop R16 ret ; ;++ Test Start- und Endezeit von 3+3 auf 12 BCD expandieren ; Z zeigt auf Startzeit, R17 = Start binär, R18 = Ende binär S2ATX: ldd R16,Z+2 ; Anzeigeformat umsortieren std Z+3,R16 ; für Normalformat hh:mm-hh:mm ldd R16,Z+8 std Z+9,R16 lds R16,AP12 ; Konstante Felder std Z+2,R16 std Z+8,R16 ldi R16,0 std Z+4,R16 std Z+10,R16 ldi R16,'-' std Z+5,R16 ldi R16,' ' std Z+11,R16 ; cp R17,R18 ; Wenn Start = Ende brne S2ATX1 ldi R16,' ' ; .. Format hh:mm 10*15" std Z+5,R16 ldi R16,1 std Z+6,R16 std Z+9,R16 ldi R16,0 std Z+7,R16 ldi R16,'*' std Z+8,R16 ldi R16,5 std Z+10,R16 ldi R16,'"' std Z+11,R16 ; S2ATX1: cpi R17,$FF ; Wenn Start = FF, d.h. Test ausgeschaltet brne S2ATX9 lds R16,CONFIG ; .. je nach Sprache andi R16,$01 breq S2ATX2 ldi R16,'A' ; .. Format AUS std Z+5,R16 ldi R16,'U' std Z+6,R16 ldi R16,'S' std Z+7,R16 rjmp S2ATX3 S2ATX2: ldi R16,'O' ; .. bzw. Format OFF std Z+5,R16 ldi R16,'F' std Z+6,R16 std Z+7,R16 ; S2ATX3: ldi R16,' ' st Z,R16 std Z+1,R16 std Z+2,R16 std Z+3,R16 std Z+4,R16 std Z+8,R16 std Z+9,R16 std Z+10,R16 std Z+11,R16 S2ATX9: ; ANP0: lds R16,CONFIG ; Zahl Programme anzeigen im Abgleichmenü lsr R16 stsi ANPROG,'1' stsi ANPROG+1,' ' stsi ANPROG+2,' ' cpi R16,1 brne ANP2 stsi ANPROG+1,'2' ANP2: cpi R16,2 brne ANP9 stsi ANPROG,'8' stsi ANPROG+1,'o' stsi ANPROG+2,'2' ANP9: ; APNU0: stsi ANZP12+1,' ' ; Programmnummern-Anzeige 1/2/80 lds R17,P12 ; 1/2 handeln sts ANZP12,R17 stsi ANZP12+3,' ' lds R16,P12+1 sts ANZP12+2,R16 lds R16,CONFIG ; Programmzahl holen lsr R16 cpi R16,2 ; Wenn Programmzahl = 2 =80/2 brne APNU9 lds R16,P12 cpi R16,1 ; .. die 1 durch 80 ersetzen brne APNU2 stsi ANZP12,'8' stsi ANZP12+1,'0' rjmp APNU9 APNU2: stsi ANZP12+2,'8' stsi ANZP12+3,'0' APNU9: ; ; FOXID dekodieren in Anzeigeformat XFUCHS, AMOD DFOXID: lds R16,FOXID ; Fuchsnummer separieren cpi R16,$FF ; Noch Unbekannt? breq DFID4 andi R16,$07 sts XFUCHS,R16 ; .. und speichern ; lds R16,FOXID ; Tastgeschwindigkeit separieren rol R16 ; Bit 6,7 -> 0,1 rol R16 rol R16 andi R16,$03 ldi R20,7 ; Anzeige ist 7 für 0 bis 4 für 3 sub R20,R16 sts AMOD,R20 ; .. speichern stsi AMOD+1,0 ; Zweite Stelle ist 0 cpi R20,4 ; .. ausser wenn erste Stelle = 4 brne DFID00 stsi AMOD+1,5 ; .... dann ist zweite Stelle = 5 ; DFID00: lds R16,FOXID 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' rjmp DFID9 DFID4: ldi R16,'?' sts XFUCHS,R16 sts AMOD+0,R16 stsi VERSHL,$00 ldi R20,'?' ldi R21,'?' ldi R22,'?' DFID9: sts AMOD+2,R20 sts AMOD+3,R21 sts AMOD+4,R22 ; ; Anzeige ID für CW-ID ein, id für aus lds R16,IOCWB0 ; Byte0 von CWID im Fuchs wird mit FoxID abgepollt andi R16,$07 cpi R16,$07 brne DCWID1 stsi ACWID,'i' stsi ACWID+1,'d' rjmp DCWID2 DCWID1: stsi ACWID,'I' stsi ACWID+1,'D' ; ; Tastgeschwindigkeit CW-ID DCWID2: ldi R18,0 ; Anzeige in R17:R18:R19 bauen ldi R19,' ' lds R16,CWID com R16 andi R16,$07 ldi R17,2 add R17,R16 ; Fertig für 50,60,70 cpi R17,4 ; 40 -> 45 brne DCWID3 ldi R18,5 DCWID3: cpi R17,3 ; 30 -> 40 brne DCWID4 ldi R17,4 DCWID4: cpi R17,9 ; 90 -> 120 brne DCWID5 ldi R17,1 ldi R18,2 ldi R19,0 DCWID5: cpi R17,8 ; 80 -> 90 brne DCWID6 ldi R17,9 DCWID6: cpi R17,2 ; 20 -> Aus brne DCWID7 ldi R17,'A' ldi R18,'u' ldi R19,'s' lds R16,CONFIG ; Wenn English andi R16,1 brne DCWID7 ldi R17,'O' ; 20 -> Off ldi R18,'f' ldi R19,'f' DCWID7: sts ATCWID,R17 sts ATCWID+1,R18 sts ATCWID+2,R19 ; ; CW-ID am Beginn oder Ende ldi R17,'B' ; Default Beginn ldi R18,'e' ldi R19,'g' lds R16,CWID ; Wenn Bit 3 in CWID gesetzt sbrs R16,3 rjmp DCWID8 ldi R17,'E' ; .. Ende ldi R18,'n' ldi R19,'d' DCWID8: sts ATCWID+3,R17 sts ATCWID+4,R18 sts ATCWID+5,R19 ; ; RAM-Entry lesen für RAM Display (Hex-Menü) lds YL,RAMADR ldi YH,1 ld R16,Y sts RAMDAT,R16 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 ldi YL,low(ZZDATA) ; Gesamten Zielzeitspeicher eins verschieben ldi YH,high(ZZDATA) ; in Richtung Anfang ldi R17,196 ; Loopcounter, move 98 * 4B ZZREG0: ldd R16,Y+4 st Y+,R16 ldd R16,Y+4 st Y+,R16 dec R17 brne ZZREG0 stsi ZZEND,98 ; Damit ist Entry 99 frei für neuen Entry lds R16,ZZOFF ; Anzeige-Offset eins erhöhen inc R16 sts ZZOFF,R16 cpi R16,100 ; .. bei 100 auf 0 wrappen brne ZZREG1 stsi ZZOFF,0 ; ZZREG1: sound SOUPAP ; Normal-Quittungston ldi YL,low(ZZDATA) ; Pointer auf nächsten Entry in ZZDATA bauen ldi YH,high(ZZDATA) ; @ZZDATA + 4 * ZZEND lds R16,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,AUHRZ ; Uhrzeit komprimieren und in ZZDATA ablegen swap R16 lds R19,AUHRZ+1 or R16,R19 st Y+,R16 lds R16,AUHRZ+2 swap R16 lds R19,AUHRZ+3 or R16,R19 st Y+,R16 lds R16,AUHRZ+4 swap R16 lds R19,AUHRZ+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,'V' ; Pfeile nach unten zeigen rjmp ZZVC13 ; ZZVC12: lds R17,ZZEND ; Wenn Entry-Nummer = ZZEND+1 inc R17 cp R16,R17 brne ZZVC14 ldi R16,$17 ; 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: lds R17,ZZOFF ; Offset zur Entrynummer addieren (für > 99 Entries) add R16,R17 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 ; ; #################################### ; #### CW-ID ASCII <-> Morse übersetzen ############################### ; #################################### ; ; ++++ CW-ID-String für Fuchs übersetzen +++++++++++++++++++++++++++++ ; LOADID: push R16 push R17 push R18 push R19 ; ; ++ ASCII-String in Morsestring übersetzen ldi XL,low(CWID+1) ; Pointer auf ASCII-String ldi XH,high(CWID+1) ldi YL,low(IOCWID+2) ; Pointer auf Morse-String ldi YH,high(IOCWID+2) ldi R19,16 ; Loopcounter ; LDID11: ld R16,X+ ; Ein Ascii-Zeichen holen ldi ZL,low(2*ASC2MO) ; Pointer auf Code-Tabelle ldi ZH,high(2*ASC2MO) LDID12: lpm ; Get ASCII Entry from table adiw ZL,1 ; Increment Pointer mov R17,R0 lpm ; Get Morse Entry from table adiw ZL,1 ; Increment Pointer mov R18,R0 cpi R17,$FF ; $FF = Tabellenende breq LDID13 cp R17,R16 ; ASCII-Zeichen = Tabellenentry? brne LDID12 ; Nein: weiterscannen LDID13: st Y+,R18 ; Ja: Morsezeichen aus Tabelle übernehmen dec R19 brne LDID11 ; ; ++ Länge in Bit ausrechnen ldi ZL,7 ; Bits in Z zählen, mit Wortabstand anfangen ldi ZH,0 ldi R19,16 ; Loopcounter LDID21: ld R16,-Y ; Ein Morsezeichen holen tst R16 ; Wenn Blank brne LDID23 cpi ZL,7 ; .. und Bitzähler noch auf Anfang brne LDID22 tst ZH brne LDID22 ; .... trailing Blanks ignorieren rjmp LDID25 LDID22: adiw ZL,4 ; Normales Blank + 4 für Wortabstand rjmp LDID25 LDID23: cpi R16,$10 ; Bindestrich ist 15 Punkte Dauerstrich brne LDID24 adiw ZL,15 rjmp LDID25 LDID24: mov R17,R16 ; Normales Zeichen andi R17,$07 ; Bitcount ist lsl R17 ; 2* Elementcount ldi R18,2 ; +2 für Buchstabenabstand add R17,R18 sbrc R16,7 ; +2 für jeden Strich add R17,R18 sbrc R16,6 add R17,R18 sbrc R16,5 add R17,R18 sbrc R16,4 add R17,R18 sbrc R16,3 add R17,R18 clr R18 add ZL,R17 ; Zwischensumme zum Bitzähler addieren adc ZH,R18 LDID25: dec R19 brne LDID21 ; ++ Wenn String-Anfang '/-' = Schnell senden: Länge um 24 verringern lds R16,CWID+1 cpi R16,'/' brne LDID26 lds R16,CWID+2 cpi R16,'-' brne LDID26 sbiw ZL,24 ; ++ Länge mit CW-Clockteiler multiplizieren ; Teiler ist 360 / BpM (3..9) LDID26: lds R16,CWID ; Teiler aus CWID holen andi R16,$07 inc R16 inc R16 ; CWID(2:0) + 2 mov R17,ZL mov R18,ZH LCID31: add ZL,R17 adc ZH,R18 dec R16 brne LCID31 ; ++ Länge durch 60 Teilen, gibt Sendezeit in Sekunden clr R16 ; Loopcounter LCID41: inc R16 sbiw ZL,60 ; Z um 60 verringern brcc LCID41 ; .. bis es negativ wird lds R17,CWID ; Wenn ID ausgeschaltet andi R17,$07 cpi R17,7 brne LCID42 clr R16 ; .. ist die Länge 0 LCID42: sts IOCWID+1,R16 ; Länge in s für Fuchs ablegen ; lds R16,CWID ; CWID Byte 0 kopieren sts IOCWID,R16 ; ; Damit ist der Record IOCWID für die Übertragung bereit ; lds R16,IOCWID+1 ; Stringdauer in Sekunden rcall B3BCD ; .. nach BCD wandeln sts ACWIDL,R2 sts ACWIDL+1,R3 flash STRIDL,14 ; Dauer in Sekunden anzeigen ; call SAVCID ; CW-ID im EEPROM sichern ; pop R19 pop R18 pop R17 pop R16 ret ; ++++ CW-ID-String aus Fuchs übersetzen ++++++++++++++++++++++++++++ ; GETID: push R16 push R17 push R18 push R19 ; ++ Morsestring in ASCII-String übersetzen ldi XL,low(CWID+1) ; Pointer auf ASCII-String ldi XH,high(CWID+1) ldi YL,low(IOCWID+2) ; Pointer auf Morse-String ldi YH,high(IOCWID+2) ldi R19,16 ; Loopcounter GTID81: ld R16,Y+ ; Ein Morse-Zeichen holen ldi ZL,low(2*ASC2MO) ; Pointer auf Code-Tabelle ldi ZH,high(2*ASC2MO) GTID82: lpm ; Get ASCII Entry from table adiw ZL,1 ; Increment Pointer mov R17,R0 lpm ; Get Morse Entry from table adiw ZL,1 ; Increment Pointer mov R18,R0 cpi R17,$FF ; $FF = Tabellenende breq GTID83 cp R18,R16 ; Morse-Zeichen = Tabellenentry? brne GTID82 ; Nein: weiterscannen rjmp GTID84 ; GTID83: ldi R17,'.' ; Nicht gefunden: Punkt einsetzen GTID84: st X+,R17 ; Gefunden: ASCII-Zeichen aus Tabelle übernehmen dec R19 brne GTID81 ; lds R16,IOCWID ; Byte 0 kopieren sts CWID,R16 pop R19 pop R18 pop R17 pop R16 ret ; ; ################################# ; #### Variablen ändern und anzeigen ############################### ; ################################# ; ;++ Zahl der Füchse ändern 2..5 UDNFU: lds R16,STA1 ; Fuchsanzahl holen mov R20,R16 ; .. und von Rest trennen andi R16,$70 andi R20,$8F swap R16 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 sts STAMIN,R16 ; Zahl der Füchse als Start-Abstand vorgeben swap R16 or R16,R20 sts STA1,R16 ret ; ;++ Zeit Z-> um 1 (10 Minuten) ändern UDZ1: push R16 ldi ZH,1 ld R16,Z cpi R16,$FF ; Zeit = $FF: breq UDZ19 ; .. nicht ändern sbrc R17,2 ; Drücken+drehen inc R16 ; Zeit ändern sbrc R17,3 dec R16 cpi R16,144 ; Wrappen 0 <-> 143 brne UDZ11 clr R16 UDZ11: cpi R16,-1 brne UDZ19 ldi R16,143 UDZ19: st Z,R16 pop R16 ret ; ;++ Zeit Z-> um 6 (1 Stunde) ändern UDZ6: rcall UDZ1 rcall UDZ1 rcall UDZ1 rcall UDZ1 rcall UDZ1 rcall UDZ1 ret ; ;++ Uhrzeit um 1 Minute ändern UDZMIN: push R16 push R20 ldi ZL,low(STA0) ldi ZH,1 lds R16,STA1 ; Minuten holen und separieren mov R20,R16 andi R16,$0F andi R20,$F0 sbrc R17,2 ; Drücken+drehen inc R16 ; Zeit ändern sbrc R17,3 dec R16 clr R17 ; UP-/Down-Flags löschen cpi R16,10 ; Wrappen 0 <-> 9 brne UDZM1 clr R16 ldi R17,4 ; 10-Minuten-Up-Flag UDZM1: cpi R16,-1 brne UDZM9 ldi R16,9 ldi R17,8 ; 10-Minuten-Down-Flag UDZM9: or R16,R20 ; Minuten wieder einbauen sts STA1,R16 pop R20 pop R16 ret ; ;++++ Startabstand in Minuten ändern 1..6, nicht wrappen UDSTAM: lds R16,STAMIN ; Startabstand Minuten ändern sbrc R17,2 inc R16 sbrc R17,3 dec R16 cpi R16,0 brne UDST1 ldi R16,1 UDST1: cpi R16,7 brne UDST9 ldi R16,6 UDST9: sts STAMIN,R16 UDST99: ret ; ; ++++ Restzeit bis zum nächsten Start-Zeitpunkt ausrechnen ; ; Relative Minute im Fuchssendezyklus ausrechnen ; Fuchs-Sendestart ist Bezugspunkt für Minute 0 ; Relative Minute ist ((STA0 + 144 - STA8) * 10 + STA1) mod Periode TITOS: clr R19 ; 2 Byte Akku in R18/R19 lds R18,STA0 ; Aktuelle Zeit in 10'-Schritten clr R17 ; 144 dazuaddieren (damit Ergebnis > 0) ldi R16,144 add R18,R16 adc R19,R17 lds R16,STA8 ; Startzeit abziehen sub R18,R16 sbc R19,R17 lsl R18 ; Ergebnis mit 10 multiplizieren rol R19 mov R16,R18 mov R17,R19 lsl R18 rol R19 lsl R18 rol R19 add R18,R16 adc R19,R17 lds R16,STA1 ; Minuten Einer addieren andi R16,$0F clr R17 add R18,R16 adc R19,R17 lds R16,STAMIN ; Periode zwischen Starts (normal Zahl der Füchse) MSTR1: sub R18,R16 ; Periodendauer abziehen, bis Ergebnis < 0 sbc R19,R17 brpl MSTR1 add R18,R16 ; .. dann wieder einmal Periodendauer dazuaddieren dec R16 ; Restminuten ist Periode - 1 - Ergebnis sub R16,R18 mov R18,R16 ; MSTR2: sts ATITOS,R18 ; Rest Minuten ablegen für Display ; ldi R17,59 ; Restsekunden ist 59 - Sekunden lds R16,STA2 andi R16,$3F sub R17,R16 mov R16,R17 sts ATITOS+3,R16 ; Restsekunden retten für MSTRT und Reset-Impuls rcall B3BCD ; Sekunden in BCD wandeln sts ATITOS+1,R2 ; .. und ablegen für Display sts ATITOS+2,R3 ret ; ; ; +++ Töne erzeugen zur vollen Sekunde im Start-Modus ; MSTRT: push R17 Push R18 lds R18,ATITOS ; Restzeit Minuten lds R17,ATITOS+3 ; Restzeit Sekunden 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 R18 pop R17 ret ; ; ; +++ Beide Status-Records eine Sekunde weiterschalten ; NXTSTA: lds STX0,STA0 ; Status-Record in Register laden lds STX1,STA1 ; Aktives Programm lds STX2,STA2 lds STX3,STA3 lds STX4,STA4 lds STX5,STA5 lds STX6,STA6 lds STX7,STA7 lds STX8,STA8 lds STX9,STA9 rcall NXTS1 ; Status-Record weiterschalten sts STA0,STX0 ; Variablen Teil Status-Record wieder ablegen sts STA1,STX1 sts STA2,STX2 sts STA3,STX3 ; tst R16 ; Wenn Modus geändert breq X01 sound SOUHI ; .. Tonsignal stsi LEDTIM,NACHLZ ; .. LED-Nachleuchtzeit auf Startwert X01: ; lds STX0,STA0+20 ; Status-Record in Register laden lds STX1,STA1+20 ; Nicht aktives Programm lds STX2,STA2+20 lds STX3,STA3+20 lds STX4,STA4+20 lds STX5,STA5+20 lds STX6,STA6+20 lds STX7,STA7+20 lds STX8,STA8+20 lds STX9,STA9+20 rcall NXTS1 ; Status-Record weiterschalten sts STA0+20,STX0 ; Variablen Teil Status-Record wieder ablegen sts STA1+20,STX1 sts STA2+20,STX2 sts STA3+20,STX3 ; NXTST9: ret ; Fertig ; ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;++++ Status-Record in STX0..9 eine Sekunde weiterschalten ++++ ; NXTS1: ;++++ Echtzeit-Uhr eine Sekunde weiterzählen X22: mov WRK,STX2 ; STA2 Bit 7,6 separieren andi WRK,$C0 andi STX2,$3F inc STX2 ; Sekunden hochzählen cpi STX2,60 ; .. bis 59 breq X221 or STX2,WRK rjmp X23 X221: mov STX2,WRK inc STX1 ; Minuten hochzählen mov WRK,STX1 andi WRK,$0F cpi WRK,10 ; .. bis 9 brne X23 andi STX1,$F0 ; .. linkes Nibble STA1 erhalten! inc STX0 ; 10 Minuten hochzählen cpi STX0,144 ; .. bis 23:50 brne X23 clr STX0 ; ;++++ Wenn Sekunde auf Umschaltzeit: aktuellen Fuchs weiterschalten X23: mov WRK,STX3 ; Wenn Modus > 0 andi WRK,$70 breq X24 mov ZL,STX2 ; und Sekunde = 0 andi ZL,$3F breq X235 ; .. weiterschalten ; cpi WRK,$10 ; Wenn Modus = 1 brne X231 cp STX4,STX5 ; .. und Test1 Endezeit = Startzeit breq X232 X231: cpi WRK,$20 ; oder Modus = 2 brne X233 cp STX6,STX7 ; .. und Test2 Endezeit = Startzeit brne X233 X232: mov WRK,STX2 ; .... dann zur Zeit 15,30,45 weiterschalten andi WRK,$3F cpi WRK,15 breq X235 cpi WRK,30 breq X235 cpi WRK,45 breq X235 rjmp X24 ; X233: cpi WRK,$40 ; Wenn Sekunde <> 0 und Modus <> 4 (Nachlauf) breq X24 cpi STX2,$40+30 ; .. die weiteren Durchgangslängen-abhängigen breq X235 ; .. Schaltzeitpunkte abtesten cpi STX2,$80+15 breq X235 cpi STX2,$80+30 breq X235 cpi STX2,$80+45 breq X235 cpi STX2,$C0+12 breq X235 cpi STX2,$C0+24 breq X235 cpi STX2,$C0+36 breq X235 cpi STX2,$C0+48 brne X24 ; X235: inc STX3 ; .. Aktuelle Fuchsnummer hochzählen mov WRK,STX3 ; .. Wenn letzte Fuchsnummer überschritten andi WRK,$07 mov ZH,STX1 swap ZH andi ZH,$07 inc ZH cp ZH,WRK brne X24 andi STX3,$F8 ; .... Aktuelle Fuchsnummer = 1 inc STX3 ; ;++++ Zu vollen 10 Minuten Ein-/Ausschaltzeiten prüfen und ggf. Modus ändern X24: mov WRK,STX2 ; Wenn Sekunden auf 0 andi WRK,$3F brne X247 mov WRK,STX1 ; und Minuten Einer auf 0 andi WRK,$0F brne X247 ; mov WRK,STX3 ; Aktuellen Modus holen andi WRK,$70 cpi WRK,$40 ; Bei Modus 4 = Fertig brne X240 rjmp X249 ; .. nix tun X240: cpi WRK,$30 ; Bei Modus 3 = Senden brne X241 cp STX0,STX9 ; .. Wenn Zeit = Sende-Ende brne X249 ldi STX3,$41 ; .... Modus auf 4 setzen, Fuchsnummer auf 1 für Nachlauf rjmp X248 X241: cpi WRK,$00 ; Bei Modus 0 = Vorlauf brne X242 ; cp STX0,STX4 ; .. Wenn Zeit = Start Test1 brne X242 ldi STX3,$11 ; .. Modus auf 1 = Test 1 rjmp X248 X242: cpi WRK,$10 ; Bei Modus 1 = Test 1 brne X243 ; cp STX0,STX5 ; .. Wenn Zeit = Ende Test 1 brne X243 ldi STX3,$00 ; .. Modus auf 0 = Vorlauf rjmp X248 X243: cpi WRK,$00 ; Bei Modus 0 = Vorlauf brne X244 ; cp STX0,STX6 ; .. Wenn Zeit = Start Test2 brne X244 ldi STX3,$21 ; .. Modus auf 2 = Test 2 rjmp X248 X244: cpi WRK,$20 ; Bei Modus 2 = Test 2 brne X245 ; cp STX0,STX7 ; .. Wenn Zeit = Ende Test 2 brne X245 ldi STX3,$00 ; .. Modus auf 0 = Vorlauf rjmp X248 X245: cp STX0,STX8 ; Bei Modus = 0,1,2: Wenn Zeit = Start Senden brne X249 ldi STX3,$31 ; .. Modus auf 3 = Senden rjmp X248 ; ;++++ Zur Zeit 2,5 Minuten Schnell-Testläufe beenden X247: mov WRK,STX2 ; Wenn Sekunden auf 30 andi WRK,$3F cpi WRK,30 brne X249 mov WRK,STX1 ; und Minuten Einer auf 2 andi WRK,$0F cpi WRK,2 brne X249 ; mov WRK,STX3 ; Aktuellen Modus holen andi WRK,$70 X2471: cpi WRK,$10 ; Wenn Modus 1 = Test 1 brne X2472 cp STX4,STX5 ; .. und Test1 Endezeit = Startzeit brne X2472 ldi STX3,$00 ; .... Modus auf 0 = Vorlauf rjmp X248 X2472: cpi WRK,$20 ; Wenn Modus 2 = Test 2 brne X249 cp STX6,STX7 ; .. und Test2 Endezeit = Startzeit brne X249 ldi STX3,$00 ; .... Modus auf 0 = Vorlauf ; X248: ldi WRK,1 ; Flag: Status-Änderung rjmp NXTS9 X249: ldi WRK,0 ; .. keine Statusänderung NXTS9: ret ; Fertig ; ; ; #################################### ; #### Programm wechseln P1 <> P2 ############################### ; #################################### ; ; ++ Uhrzeit vom noch aktiven ins inaktive kopieren PSWAP: lds R20,STA0 ; Minuten/10 sts STA0+20,R20 lds R20,STA1 ; Minuten in bits 3..0 andi R20,$0F lds R21,STA1+20 andi R21,$F0 or R21,R20 sts STA1+20,R21 lds R20,STA2 ; Sekunden in bits 5..0 andi R20,$3F lds R21,STA2+20 andi R21,$C0 or R21,R20 sts STA2+20,R21 ; ++ Programm tauschen inaktiv <> aktiv bswap STA0,20 ; Status 0..9 tauschen bswap STA1,20 bswap STA2,20 bswap STA3,20 bswap STA4,20 bswap STA5,20 bswap STA6,20 bswap STA7,20 bswap STA8,20 bswap STA9,20 bswap EXPERT,1 ; Programmspezifische Variablen tauschen bswap STAMIN,1 ; " bswap P12,1 ; Programmanzeige tauschen ; ret ; ; ++ Bei Fuchs Laden/Prüfen Programm wechseln wenn NProg = 8o2 und ; Fuchs-Band (aus FoxID) <> FoxPro-Band (aus P12) P2SWAP: lds R16,CONFIG ; Wenn NPROG = 8o2 andi R16,$04 breq P2SWA9 lds R16,FOXID ; Band des Fuchs ermitteln ldi R17,1 andi R16,$30 cpi R16,$30 breq P2SWA1 ldi R17,2 P2SWA1: lds R16,P12 ; Wenn Fuchs-Band <> FoxPro-Band cp R16,R17 breq P2SWA9 rcall PSWAP ; Programm wechseln P2SWA9: ret ; ; ############################ ; #### EEPROM-Lesen + Schreiben ######################### ; ############################ ; ; ++++ CFUB/CFUBF/CONFIG ins EEPROM Adr. 0/1/2 schreiben ; SAVEEP: OUT EEARH,C0 ; High Adresse ist 0 CLR R15 ; Low Address LDS R16,CFUB ; Variable holen LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 RCALL SAVEE1 ; 1 Byte ins EEPROM schreiben ; LDS R16,CFUBF ; Variable holen LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 RCALL SAVEE1 ; 1 Byte ins EEPROM schreiben ; LDS R16,CONFIG ; Variable holen RCALL SAVEE1 ; 1 Byte ins EEPROM schreiben RET ; SAVEE1: IN R17,EECR ; Wait for EEPROM Ready to write ANDI R17,$02 BRNE SAVEE1 OUT EEARL,R15 INC R15 ; Increment Address for next write 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 ; ; ++++ CWID ins EEPROM Adr. 3-19 schreiben ; SAVCID: OUT EEARH,C0 ; High Adresse ist 0 LDI R16,3 ; Low Address MOV R15,R16 LDI XL,low(CWID) ; CWID Pointer vobereiten LDI XH,high(CWID) SCID20: LD R16,X+ ; Variable holen RCALL SAVEE1 ; 1 Byte ins EEPROM schreiben CPI XL,low(CWID+17) ; Insgesamt 17 Byte CWID geschrieben? BRNE SCID20 RET ; ; ++++ Alle 20 Parameter aus EEPROM holen +++++++++++++++++++++++++++++++ ; GETEEP: OUT EEARH,C0 ; High Adresse ist 0 CLR R15 ; Low Address ; RCALL GETEE1 ; Read 1 Byte LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 STS CFUB,R16 ; Variable ablegen ; RCALL GETEE1 ; Read 1 Byte LDI R17,$80 ; Bit 7 komplementieren EOR R16,R17 STS CFUBF,R16 ; Variable ablegen ; RCALL GETEE1 ; Read 1 Byte CPI R16,$FF ; Bei leerem EEPROM BRNE GEEP10 LDI R16,$01 ; .. 1 Programm, Deutsch GEEP10: STS CONFIG,R16 ; Variable ablegen ; LDI XL,low(CWID) ; CWID lesen vobereiten LDI XH,high(CWID) GEEP20: RCALL GETEE1 ; Ein Byte lesen ST X+,R16 ; und ablegen CPI XL,low(CWID+17) ; Insgesamt 20 Byte gelesen? BRNE GEEP20 RET ; GETEE1: OUT EEARL,R15 INC R15 ; Increment Address for next Read 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 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: sts ADMUX,R16 ; ADMUX einstellen clr R16 ; Wait a little for I/O to settle AC1: dec R16 brne AC1 ldi R16,$C6 sts ADCSRA,R16 ; Start ADC AC2: lds R16,ADCSRA sbrs R16,4 ; Wait for ADIF rjmp AC2 ldi R16,$96 sts ADCSRA,R16 ; Clear ADIF lds R16,ADCL ; Get Conversion Results lds 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 ; Scale result 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 ; r17:r16 and r19:r18. ; The result is placed in r21..r18 ; ; Number of words :14 + return ; Number of cycles :153 + return ; Low registers used :None ; High registers used :7 R16..R22 ; ; r16 multiplicand low byte ; r17 multiplicand high byte ; r18 multiplier low byte ; r19 multiplier high byte ; r20 result byte 2 ; r21 result byte 3 (MSB) ; r22 loop counter ; MPY16u: clr r21 ;clear 2 highest bytes of result clr r20 ldi r22,16 ;init loop counter lsr r19 ror r18 ; m16u_1: brcc noad8 ;if bit 0 of multiplier set add r20,r16 ;add multiplicand Low to byte 2 of res adc r21,r17 ;add multiplicand high to byte 3 of res noad8: ror r21 ;shift right result byte 3 ror r20 ;rotate right result byte 2 ror r19 ;rotate result byte 1 and multiplier High ror r18 ;rotate result byte 0 and multiplier Low dec r22 ;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 sts OCR1AH,R0 ; Variablen Oscillator laden clr R18 sts 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: sts 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 R18 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: LDI R16,2 ; Loopcounter for 2 16B-Strings ; LCDS11: CLR XH ; X is Offset to start of next 16B-String CLR XL ; (used only for multiple language records) LPM ; Get first Byte of line to R0 MOV R17,R0 ; Is it $10 = Dual Language Flag? CPI R17,$10 BRNE LCDS15 ; ADIW ZL,2 ; Read-Pointer skips $1010 LDS R17,CONFIG ; Get selected Language ANDI R17,1 ; BREQ LCDS12 LDI XL,16 ; Language 1: Post-Offset 16 RJMP LCDS15 LCDS12: ADIW ZL,16 ; Language 2: Pre-Offset 16 ; LCDS15: LDI R17,16 ; Bytecounter 16 to 0 LCDS16: LPM ; Get one Byte to R0 ADIW ZL,1 ; Increment Z MOV R18,R0 CPI R18,'%' ; Handle the two P1/2 special chars BRNE LCDS17 LDS R18,AP12 ; % becomes . / : LCDS17: CPI R18,'&' BRNE LCDS18 LDS R18,AP12+1 ; & becomes > / >> LCDS18: ST Y+,R18 ; Store Byte DEC R17 ; Repeat 16 times BRNE LCDS16 ; ADD ZL,XL ; Post-Correct readpointer for multi-language ADC ZH,XH DEC R16 ; Do Two 16-Char Lines BRNE LCDS11 ; LDI YH,HIGH(LCDDAT) ; Restore Pointer 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,1 ; 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: ADIW YL,1 ; Increment Write Pointer CPI YL,LOW(LCDDAT+32) ; Repeat 16 times BRNE LCDST2 ; LCDSTA: POP YH POP YL POP XH POP XL POP R18 POP R17 POP R16 POP R0 rcall OUTLCD ; Ergebnis anzeigen RET ; ; ; ++++ Initialize the LCD Display INILCD: push R16 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, Instruction Table = 1 rcall LC2CMD ldi R25,$1C ; Bias Set 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 ; ; ++ Load 8 character generator fields from table ; ldi R25,$28 ; Function Set, Instruction Table = 0 rcall LC2CMD INICG: ldi ZL,low(2*SPECCH) ; Readpointer for CharGen-Table ldi ZH,high(2*SPECCH) ldi R25,$40 ; CGRAM-Adresse auf Anfang rcall LC2CMD clr R16 ; Character-Counter 0 - 63 ; INICG1: lpm ; Get one Byte from Table to R0 mov R25,R0 rcall LC2DAT ; .. and send to LCD adiw ZL,1 ; Increment Z inc R16 ; Increment Bytecounter cpi R16,64 ; If less than 64 brne INICG1 ; .. loop gain ; pop R25 pop R16 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 ldi YH,HIGH(LCDDAT) 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 = StartZiel ($7x) andi R22,$70 cpi R22,$70 brne TIM10 lds R22,SCROLL ; und Scrollzähler auf 0 = 'Scroll nicht aktiv' tst R22 brne TIM12 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 lds R22,TIK1k2 ; Wenn TIK1k2 = 20, 60, 100 cpi R22,19 breq TIM123 TIM121: cpi R22,59 breq TIM123 TIM122: cpi R22,99 brne TIM14 TIM123: stsi TAK33,1 ; .. 33 msec Flag setzen TIM14: inctim TIK1k2,120,TIM99 ; Increment to 100 msec ; ; ++ 100 ms Service sei ; Enable next interrupt stsi TAK100,1 ; 100 ms Flag setzen inctim TIK10,10,TIM99 ; Increment to 1 sec ; ; ++ 1 s Service stsi TAK1S,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 R20,R21 ; Bei 1 * SOUFRQ brne SOUIN2 sbi DDRB,2 ; .. Leitungstreiber ein rjmp SOUIN9 ; SOUIN2: lsl R20 ; Bei 2 * SOUFRQ cp R20,R21 brcc 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,2 ; An oberem Limit? BREQ DEB3 INC R20 STS DEBP1,R20 CPI R20,2 ; 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 (Protocol: see FJTX.asm) ; Uses R16,R22,R23,R24 SERIN: lds R22,SERCNT ; Wenn Counter >= 128 sbrc R22,7 rjmp TIM55 ; .. 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 rjmp TIM55 cpi R22,70 ; Bei Counterwert 70: Fertig brne TIM52 clr R22 ; .. Counter auf 0 ldi R23,$50 ; Prüfsumme in R23/linkes Halbbyte prüfen eor R23,SHIFT0 eor R23,SHIFT1 mov R24,R23 swap R24 eor R23,R24 andi R23,$F0 ; brne TIM55 ; Prüfbyte = Sollwert? stsi SERFLG,1 ; .... RX complete Semaphore setzen ; TIM518: sts IN2B+0,SHIFT0 ; .... Empfangenen String kopieren sts IN2B+1,SHIFT1 rjmp TIM55 ; TIM52: clc ; Bei Counterwert 2, 6, ..162 sbic PINB,2 ; .. ein Bit von Leitung nach Carry einlesen sec rol SHIFT1 ; 16 bit Shiftregister links schieben rol SHIFT0 ; TIM55: sts SERCNT,R22 ; Counter in RAM ablegen ret ; +++ Serial Send, called on 1,2 kHz Service (Protocol: see FJTX.asm) ; SEROUT: lds R22,SERCNT ; Wenn Senden nicht aktiv tst R22 brne TIM56 lds R23,SERFLG sbrs R23,1 ; und wenn Sende Semaphore gesetzt rjmp TIM59 stsi SERFLG,0 ; Sende Semaphore löschen sbi DDRB,2 ; Startbit senden ldi R22,128 ; Counter auf Senden lds SHIFT0,OUT2B+0 ; Sendedaten aus OUT2B holen lds SHIFT1,OUT2B+1 mov R23,SHIFT0 ; High Nibble von Shift 0 löschen andi R23,$0F mov SHIFT0,R23 ldi R23,$0A ; Prüfsumme ausrechnen eor R23,SHIFT0 eor R23,SHIFT1 swap R23 eor R23,SHIFT1 andi R23,$F0 or SHIFT0,R23 rjmp TIM59 ; Fertig mit Start ; TIM56: sbrs R22,7 ; Wenn Counter >= 128 rjmp TIM59 inc R22 ; .. Counter hochzählen cpi R22,146 ; Wenn Counter = 128 + 16 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 SHIFT1 rol SHIFT0 ; TIM59: sts SERCNT,R22 ret ; ; ****************** ; **** Special Tables ********************************************** ; ****************** ; ; ++++ Special Characters 0..7, to be loaded into LCD-Display ; SPECCH: .DB $10,$14,$12,$1F,$02,$04,$00,$00 ; 0: '-> .DB $04,$0E,$15,$04,$1C,$00,$00,$00 ; 2: -^ .DB $02,$05,$00,$00,$00,$05,$02,$00 ; 1: Up + Down Arrow .DB $00,$0A,$00,$04,$04,$11,$0E,$00 ; 3: Smile .DB $00,$00,$00,$0C,$0C,$00,$00,$00 ; 4: Hochgestellter Punkt .DB $18,$1B,$1B,$1B,$1B,$1B,$1B,$18 ; 5: tbd .DB $0C,$0C,$00,$0C,$0C,$00,$0C,$0C ; 6: tbd .DB $00,$1B,$1B,$00,$1B,$1B,$00,$00 ; 7: tbd ; ; ++++ Translation ASCII <-> Morse ; Morseformat MMMM MLLL ; LLL = Zeichenlänge 1..5 Pu+Stri, 0: Blank, 6,7: Reserviert ; MMMMM = 0:Punkt, 1:Strich, erstes Element in Bit 7 ; Sonderfälle $00= Wortabstand $10= Langer Strich ; ASC2MO: .DB "A",$42,"B",$84,"C",$A4,"D",$83 .DB "D",$83,"E",$01,"F",$24,"G",$C3 .DB "H",$04,"I",$02,"J",$74,"K",$A3 .DB "L",$44,"M",$C2,"N",$82,"O",$E3 .DB "P",$64,"Q",$D4,"R",$43,"S",$03 .DB "T",$81,"U",$23,"V",$14,"W",$63 .DB "X",$94,"Y",$B4,"Z",$C4 .DB "0",$FD,"1",$7D,"2",$3D,"3",$1D .DB "4",$0D,"5",$05,"6",$85,"7",$C5 .DB "8",$E5,"9",$F5 .DB "/",$95,".",$00,"-",$10 .DB ".",$FF ; für EEPROM leer .DB $FF,$FF ; End of Record ; ; ******************* ; **** 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 " ; 0 in Zeichenposition = Pfeil von oben nach rechts ; 1 " = Pfeil von links nach oben ; 2 " = Pfeile nach oben und unten ; 3 " = Smile ; 4 " = Hochgesetzter Punkt ; 5 " = Frei ; 6 " = Frei ; 7 " = Frei ; ; Umlaute: $84/8E = ä/Ä, $94/99 = ö/Ö, $81/9A = ü/Ü ; Pfeile: $7E = ->, $7F = <-, $FB = <<, $FC = >> ; Indikation Programm 1/2: % = ./: & = >/>> ; ; Die zweiten 32 Bytes sind jeweils Pointer auf 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 ; ; Der Festtext-Teil (die ersten 2*16 Bytes) kann sprachabhängig ; definiert werden. Dafür ist pro 16 Bytes (eine Zeile) die Syntax ; .DW $1010 .DB '--Deutscher Txt--' .DB '--Englischer Txt-' ; ; ; >1234567812345678< Power On STRPO: .DB "FoxPro 2G V ",VERSHI,".",VERSLO .DB " DF1FO 2009 " .DB $FF,0 ; ; ++++ Menüs für die verscheidenen Modi ; ; >1234567812345678< Hex-Display Send/Receive STRM0: .DB "S $L:HL E $L:HL" .DB "SRAM $1HL:HL &" .DB 1,2,3,OUT2B,5,0,9,8,1,2,3,4,IN2B,5,0,9 .DB 1,2,3,4,5,6,7,RAMADR,9,2,RAMDAT,9,5,6,7,$FF ; ; >1234567812345678< Programm eingeben,Experte STRM1: .DB ":.%..'.. .x..",$22," ." .DB ":.%.0-:.%.0 .. &" .DB AUHRZ,0,3,0,0,6,0,0,1,NFUCHS,3,ATSEND,0,6,7,ATST .DB ASTA8,0,3,0,5,6,ASTA9,0,1,0,3,4,ANL,0,7,$FF ; ; >1234567812345678< Fuchs bedienen STRM2: .DW $1010 ; 1,2 .DB "Lesen TX.' :.,.V" .DB "Read TX.' :...V" .DW $1010 ; 1,2 .DB "Laden Pr",$81,"fen + &" .DB "Load Check + &" .DB 1,2,3,4,5,6,7,8,TXTIME,2,3,UBATF,0,6,0,8 .DB $FF,0 ; ; >1234567812345678< Testzeiten-Eingabe STRM3: .DB "T1 :.....:..... " .DB "T2 :.....:.....&" .DB 1,2,3,ASTA4,0,0,0,0,0,0,0,0,0,0,0,8 .DB 1,2,3,ASTA6,0,0,0,0,0,0,0,0,0,0,0,$FF ; ; >1234567812345678< Fuchs Extras STRM4: .DW $1010 ; 1,2 .DB "F. T.. M... .. " .DB "F. K.0 M... .. " .DW $1010 ; 1,2 .DB "VH.L TX: Osz # &" .DB "VH.L TX: Osc # &" .DB 1,XFUCHS,3,4,AMOD,0,7,8,0,0,0,4,ACWID,0,7,8 .DB 1,VERSHL,3,9,5,6,7,ATXEIN,1,$FF ; ; >1234567812345678< Top-Menü STRM5: .DW $1010 ; 1,2 .DB "Programm.. :.,.V" .DB "Program_.. :...V" .DW $1010 ; 1,2 .DB "Fuchs StartZiel" .DB "Fox StartFini" .DB 1,2,3,4,5,6,7,8,ANZP12,0,3,UBAT,0,6,0,$FF ; ; >1234567812345678< Voltmeter eichen STRM6: .DW $1010 ; 1,2 .DB "FP:.,.V Fu:.,.V" .DB "FP:.,.V Fox:.,.V" .DW $1010 ; 1,2 .DB "NProg ... Deu &" .DB "NProg ... Eng &" .DB 1,2,UBAT,0,5,0,7,8,1,2,3,UBATF,0,6,0,8 .DB 1,2,3,4,5,6,ANPROG,0,0,$FF ; ; >1234567812345678< Voltmeter eichen, Startmeldung STRM61: .DW $1010 ; 1,2 .DB ">>>> Basis- <<<<" .DB ">>>> Base- <<<<" .DW $1010 ; 1,2 .DB " Einstellungen " .DB ">>> Settings <<<" .DB $FF,0 ; ; >1234567812345678< Start-Anzeige STRM7S: .DB ":.%..'.. ",$7F,".'",$7E .DB "Start in .'.. &" .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,STAMIN,7,8 .DB 1,2,3,4,5,6,7,8,1,ATITOS,3,0,0,$FF ; ; >1234567812345678< Ziel-Anzeige STRM7Z: .DB ":.. :.%..'..,. " .DB ":.. :.%..'..,. " .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< Sicherheitsfrage Clonen STRM8: .DW $1010 ; 1,2 .DB "Fuchs -> FoxPro?" .DB " Fox -> FoxPro ?" .DW $1010 ; 1,2 .DB " Ja &" .DB " Yes &" .DB $FF,0 ; ; >1234567812345678< Programm eingeben, einfach STRM9: .DB ":.%..'.. " .DB ":.%.0-:.%.0 + &" .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB ASTA8,0,3,0,5,6,ASTA9,0,1,0,3,$FF ; ; >1234567812345678< CW-Kennung eingeben STRMA: .DB "................" .DW $1010 ; 1,2 .DB "T... ... ",0,"Fu",1," &" .DB "K... ... ",0,"Fx",1," &" .DB CWID+1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .DB 1,ATCWID,0,0,5,0,0,0,1,$FF ; ; >1234567812345678< Sicherheitsfrage Programm wechseln STRMB: .DW $1010 ; 1,2 .DB "Programm ..",$7E,".. ?" .DB "Program ..",$7E,".. ?" .DW $1010 ; 1,2 .DB " Ja &" .DB " Yes &" .DB 1,2,3,4,5,6,7,8,1,ANZP12,0,4,0,0,7,$FF ; ; ; ++++ Rückmeldungen für Aktionen aus den Menüs ; ; >1234567812345678< Voltmeter eichen, Hexwert Korrekturfaktor STRVHX: .DW $1010 ; 1,2 .DB "FP:.,.V Fu:.,.V" .DB "FP:.,.V Fox:.,.V" .DB " $HL $HL " .DB 1,2,UBAT,0,5,0,7,8,1,2,3,UBATF,0,6,0,8 .DB 1,2,3,CFUB,9,6,7,8,1,2,3,4,CFUBF,9,7,8 ; ; >1234567812345678< Suchmodus Ein STRSU1: .DW $1010 ; 1,2 .DB " Suchmodus EIN " .DB " Searchmode ON " .DB " " .DB $FF,0 ; ; >1234567812345678< Suchmodus Aus STRSU0: .DW $1010 ; 1,2 .DB " Suchmodus AUS " .DB " Searchmode OFF " .DB " " .DB $FF,0 ; ; >1234567812345678< Warten STRWAR: .DW $1010 ; 1,2 .DB " Bitte Warten.. " .DB " Please wait.. " .DB " " .DB $FF,0 ; ; >1234567812345678< Fuchs synchron mit Fuchs# STROK: .DW $1010 ; 1,2 .DB " Fuchs . " .DB " Fox . " .DW $1010 ; 1,2 .DB "Programm .. OK !" .DB " Program .. OK !" .DB 1,2,3,4,5,6,7,8,1,XFUCHS,3,4,5,6,7,8 .DB 1,2,3,4,5,6,7,8,1,ANZP12,0,$FF ; ; >1234567812345678< CW-Ident ok STROKC: .DW $1010 ; 1,2 .DB " Identifikation " .DB " CW-Ident " .DW $1010 ; 1,2 .DB " geladen + ok ! " .DB " loaded o k ! " .DB $FF,0 ; ; >1234567812345678< Fuchs nicht synchron STRNOK: .DW $1010 ; 1,2 .DB "FUCHS . PROG .. " .DB " FOX . PROG .. " .DW $1010 ; 1,2 .DB "NICHT SYNCHRON! " .DB " OUT OF SYNC! " .DB 1,2,3,4,5,6,XFUCHS,8,1,2,3,4,5,ANZP12,0,$FF ; ; >1234567812345678< Fuchs antwortet nicht STRTOT: .DW $1010 ; 1,2 .DB "KEINE VERBINDUNG" .DB " FOX NOT " .DW $1010 ; 1,2 .DB " ZUM FUCHS! HL" .DB " CONNECTED HL" .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,4,5,6,PROTO,9,$FF,0 ; ; >1234567812345678< Clonen erfolgreich STRCLO: .DW $1010 ; 1,2 .DB "Fuchs-Programm " .DB "Fox-Program " .DW $1010 ; 1,2 .DB ".. ",$9A,"bernommen ! " .DB ".. copied ok ! " .DB 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 .DB ANZP12,0,$FF,0 ; ; >1234567812345678< Dauer CW-ID anzeigen STRIDL: .DW $1010 ; 1,2 .DB " ID-L",$84,"nge :.",$22," " .DB " ID-Length :.",$22," " .DB " " .DB 1,2,3,4,5,6,7,8,1,2,3,ACWIDL,0,$FF ; ; ++++ Status-Anzeigen bei Schalter auf Sicher ; ; >1234567812345678< Sicher, Vorlauf STRX0: .DW $1010 ; 1,2 .DB ":.%..'.. Vorlauf" .DB ":.%..'.. Wait" .DB " -:.%.0 " .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB 1,2,3,4,5,6,ASTA8,0,1,0,3,4,5,6,7,8 ; ; >1234567812345678< Sicher, Testsendung 1 STRX1: .DB ":.%..'.. Test 1" .DB ":. .. :. .. F./." .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB ASTA4,0,0,0,0,0,0,0,0,0,0,0,5,AFUCHS,7,NFUCHS ; ; >1234567812345678< Sicher, Testsendung 2 STRX2: .DB ":.%..'.. Test 2" .DB ":. .. :. .. F./." .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB ASTA6,0,0,0,0,0,0,0,0,0,0,0,5,AFUCHS,7,NFUCHS ; ; >1234567812345678< Sicher, Senden STRX3: .DW $1010 ; 1,2 .DB ":.%..'.. Senden" .DB ":.%..'.. Active" .DB ":.%.0-:.%.0 F./." .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB ASTA8,0,3,0,5,6,ASTA9,0,1,0,3,4,5,AFUCHS,7,NFUCHS ; ; >1234567812345678< Sicher, Fertig STRX4: .DW $1010 ; 1,2 .DB ":.%..'.. Fertig" .DB ":.%..'.. Done" .DW $1010 ; 1,2 .DB " seit :.%.0" .DB " since :.%.0" .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB 1,2,3,4,5,6,7,8,1,2,3,ASTA9,0,6,0,8 ; ; >1234567812345678< Sicher, Nachlauf, Sendet STRX41: .DW $1010 ; 1,2 .DB ":.%..'.. Suchen" .DB ":.%..'.. Search" .DW $1010 ; 1,2 .DB "F./. sendet " .DB "F./. transmits " .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB 1,AFUCHS,3,NFUCHS,5,$FF ; ; >1234567812345678< Sicher, Nachlauf, Pause STRX40: .DW $1010 ; 1,2 .DB ":.%..'.. Suchen" .DB ":.%..'.. Search" .DB "F./. Pause " .DB AUHRZ,0,3,0,0,6,0,0,1,2,3,4,5,6,7,8 .DB 1,AFUCHS,3,NFUCHS,5,$FF ; ; ++++ Programm-Anzeige bei Schalter auf Sicher + Klick ; ; >1234567812345678< Programm-Zeiten Test 1 STRY1: .DW $1010 ; 1,2 .DB "Testlauf 1 " .DB "Testrun 1 " .DB ":.....:..... ->" .DB 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 .DB ASTA4,0,0,0,0,0,0,0,0,0,0,0,5,$FF ; ; >1234567812345678< Programm-Zeiten Test 2 STRY2: .DW $1010 ; 1,2 .DB "Testlauf 2 " .DB "Testrun 2 " .DB ":.....:..... ->" .DB 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 .DB ASTA6,0,0,0,0,0,0,0,0,0,0,0,5,$FF ; ; >1234567812345678< Programm-Zeiten Senden STRY3: .DW $1010 ; 1,2 .DB "Senden .x..",$22 .DB "Active .x..",$22 .DB ":.%.0-:.%.0 ->" .DB 1,2,3,4,5,6,7,8,1,2,3,NFUCHS,5,ATSEND,0,8 .DB ASTA8,0,3,0,5,6,ASTA9,0,1,0,3,$FF ; ; >1234567812345678< Programm-Zeiten Suchmodus STRY41: .DW $1010 ; 1,2 .DB "Suchmodus " .DB "Searchmode " .DB ":.%.0- ... ->" .DB 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 .DB ASTA9,0,3,0,5,$FF ; ; **** 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, $80: Underline,blink, $40: Block,blink ; Cursorposition = $FF : es wird die Position aus CURCID genommen CURTAB: .DB $00,0+$40,$01,3,$02,5,$03,6,$04,9+$40 .DB $05,23,$06,24,$07,31+$40 .DB $10,1,$11,3,$12,4,$13,7+$80 .DB $14,9,$15,11,$16,15+$40,$17,17,$18,19 .DB $19,23,$1A,25,$1B,28+$40,$1C,31+$40 .DB $20,0+$40,$21,6+$40,$22,8+$80,$23,16+$40 .DB $24,22+$40,$25,29+$40,$26,31+$40 .DB $30,0+$40,$31,4,$32,6,$33,12 .DB $34,16+$40,$35,20,$36,22,$37,28,$38,31+$40 .DB $40,0+$40,$41,3+$40,$42,7+$40,$43,12+$40 .DB $44,21+$40,$45,25+$40,$46,29+$40,$47,31+$40 .DB $50,0+$40,$51,8+$80,$52,16+$40,$53,23+$40 .DB $60,5+$80,$61,14+$80,$62,22+$80,$63,27+$40,$64,31+$40 .DB $70,31+$40,$71,13+$80,$72,32 .DB $80,26+$40,$81,31+$40 .DB $90,1,$91,3,$92,4,$93,7+$80 .DB $94,19,$95,25,$96,29+$40,$97,31+$40 .DB $A0,$FF,$A1,16+$40,$A2,21+$40,$A3,26+$40 .DB $A4,29+$40,$A5,31+$40 .DB $B0,26+$40,$B1,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 1,12,1,12,1,12,1,9,9,9,1,7,0,0 ; Power-On Fanfare ; SOUALA: .DB 4,6,9,12,18,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 (Quittung Eingabe) ; SOUPAP: .DB 13,0 ; Kurz-Piep mittel (Quittung Eingabe) ; SOUPOP: .DB 50,0 ; Kurz-Piep tief (Quittung Mode +/-) ; 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 4..1 s ; SOU0S: .DB 8,8,8,8,8,8,8,8,8,0 ; Start ; ; ************************ ;******** This is the End..... *************************************** ; ************************