; FJTX.ASM ; ; ************************************ ; * Fuchsjagd Sender, 2. Generation * ; ************************************ ; ; Code für Fuchsjagd-Sender-Steuerung ; Basiert auf der Fuchssteuerung 1. Generation 2mMidiTX, ist dazu aber nicht kompatibel ; Geändert: Übertragungsformat, Kommando-Layout, Register-Layout, Funktionsumfang ; ; ; Created 13.4.2009 ; Version 0.0: Code-Import von 2mMidiTX.asm Version 2.1 ; 18. 4.09 0.1: FoxPro-I/F und Register-Layout umgestellt ; 23. 4.09 0.2: Status-Update (jede Sekunde) und Sende-/Blinksteuerung umgestellt ; 30. 4.09 0.3: Clean-Ups ; 10. 5.09 0.4: Fix OscOn-Flackern bei serieller Übertragung, Clean-Ups ; 1. 7.09 0.5: 50 ms Delay nach Reset, Command 0 löscht TXTIMR ; 10. 8.09 0.6: Fix für '"TX" schaltet OscOn nicht ein' (Tnx Reinhard Hergert) ; 3. 9.09 0.7: Code läuft sowohl auf ATtiny12 als auch auf ATtiny25 ; --> Dieser Stand gesichert als FJTXtiny12 ; -------------- ; 28. 9.09 1.0: Ab diesem Level nur noch ATtiny25 unterstützt (ATtiny12-Flash zu klein) ; 4 Tastgeschwindigkeiten 40/50/60/70 Bpm ; 4 Sendedauern 60/30/15/12 sec ; Ergänzungen im Protokoll für CWID: $D, $E, $F_0E ; ID senden, max 16 Zeichen ; >> Version 1.x erfordert im FoxPro FOXPRO2 V1.x << ; 6.11.09 1.0 Code freeze und auf meiner Website veröffentlicht ; 13. 5.11 1.1 Drucktastenkonfigurator (µ-FoxPro) ; Sendedauer 'Autonomer Modus' von 4h auf 6h verlängert ; 23. 6.11 1.2 Drucktasten-Konfigurator startet mit EEPROM-Wert bzw. Default ; ; .equ VERSHL =$12 ; Software-Version ; .equ DEFFOX =$76 ; Default-Fuchs-ID bei leerem EEPROM ; ; $5x = Fuchs x, 800Hz A2, 60 BpM ; ; $7x = Fuchs x, A1, 60BpM ; .equ A1ONLY =0 ; 1 = nur A1-Modulation unabhängig von Modulationseinstellung ; ; 0 = Normalbetrieb ; ;***** Specify Device .device ATtiny25 ; ; Fuses im ATtiny25 werden wie folgt programmiert: ; Häkchen nur bei SPIEN und EESAVE ; BODLEVEL: Brown-out detection at VCC=4,3V ; SUT_CKSEL = 'Ext. Crystal Osc. 3,0-8,0 MHZ', unterste Auswahl = längster Startup ; Fuse-Pattern X-H-L FF-D4-FD, wird zurückgelesen als FD-D4-FF ; ;***** I/O Register Definitions .equ SREG =$3f .equ TIMSK =$39 .equ TCCR0 =$33 .equ TCNT0 =$32 .equ EEARH =$1f .equ EEAR =$1e .equ EEDR =$1d .equ EECR =$1c .equ PORTB =$18 .equ DDRB =$17 .equ PINB =$16 .equ RAMBEG =$60 .equ RAMEND =$DF ; RAM-size 128 B (used for Stack and some Variables) .equ E2END =$7F ; Last EEPROM Location, 128 B .equ FLASHEND=$3FF ; Last FLASH Location, 2 kB ; ;**** Register Useage ; ; r0 Flash Access, auch Workregister ; .DEF SHIFT0 =r2 ; Serial I/F Shift Register First Byte, Bit7 (MSb) shifted first .DEF SHIFT1 =r3 ; Second Byte = Last Byte ; ; Status 0..9 ist identisch in allen Füchsen und FoxPro ; Status 4..9 enthalten Uhr-Zeiten in 10'-Schritten (wie Status 0) .DEF STA4 =r4 ; Status 4 Start Testlauf 1 ($FF = Aus) .DEF STA5 =r5 ; Status 5 Ende Testlauf 1 (STA5=STA4: 10x15") .DEF STA6 =r6 ; Status 6 Start Testlauf 2 ($FF = Aus) .DEF STA7 =r7 ; Status 7 Ende Testlauf 2 (STA7=STA6: 10x15") .DEF STA8 =r8 ; Status 8 Start Senden .DEF STA9 =r9 ; Status 9 Ende Senden ; .DEF FOXID =r10 ; Fuchs-Nr./Modulation wie im EEPROM, 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 ; .DEF PODEL =r11 ; Power-On Delay, zählt ab Reset 1*/s runter bis 0 ; Solange PODEL > 0 wird OscOn auf 0 gehalten .DEF MODCTR =r12 ; Modulationszähler, teilt 4,8 kHz in Modulationsfrequenz ; .DEF IWRK2 =r13 ; 2tes Workregister für Interupt-Handler ; .DEF STA0 =r16 ; Status 0 / 7..0 Uhrzeit binär in 10'- Schritten (0..143) .DEF STA1 =r17 ; Status 1 / 7 Nachlauf (Suchmodus) 0=Aus, 1=Ein ; 6..4 Höchste Fuchs # (2..5) ; 3..0 Uhrzeit Minute binär (0..9) .DEF STA2 =r18 ; Status 2 / 7,6 Durchgangsdauer 0..3 = 60/30/15/12" ; 5..0 Uhrzeit Sekunde binär (0..59) .DEF STA3 =r19 ; 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) ; .DEF WRK =r20 ; 3 Work registers for Main .DEF WRK1 =r21 ; .DEF WRK2 =r22 .DEF CWCTR =r23 ; CW-String-Bit-Zähler 0..127 .DEF SERCNT =r24 ; Serial Interface Bit Counter <128 Receive, >=128 Send ; 0 = Warten auf Startbit, ab Vorflanke zählen mit 4800 Hz ; 6,10,14..66 Abtastzeitpunkte für die 16 Datenbits ; 70 (Mitte Stopbit) zurücksetzen auf 0 ; 128 = Startbit senden ; 129..144 = Bit 0..15 senden ; 145 = fertig, zurück auf 0 .DEF TXTIMR =r25 ; TX-Timer für Testsendungen mit 'TX', enthält Restsendezeit ; 255..16 dekrementiert alle 15 sec, sendet Kennung ; 15..1 dekrementiert alle 1/10 sec, sendet Träger ; 0=Fertig .DEF SEMA =r26 ; Semaphores Main to Interrupt-Handler and back ; Bit 0: 1=TX On, 0= TX Off ; Bit 1: Send Shift Register ; Bit 2: Frei ; Bit 3: Pausenblinken an (1x Vorlauf, 2x Sendepause) ; Bit 4: 1 sec Timing Event (für Fuchs-Ablauf) ; Bit 5: Key Timing Event (für CW Senden) ; Bit 6: Serial Receive complete ; Bit 7: Pause .DEF IWRK =r27 ; Interrupt Work Register .DEF TIK30 =r29 ; Interrupt-Hdlr: Zählt alle 30 Hz bis 29 = 1 sec .DEF ZL =r30 ; Used for Flash access and as General Work .DEF ZH =r31 ; dto ; ;**** RAM Useage .DSEG .ORG RAMBEG ; EEADR: .BYTE 1 ; EEPROM-Schreib-/Lese-Pointer CWID: .BYTE 18 ; CWID wie im EEPROM Byte 1..18 abgelegt ; Byte 0: O000 ETTT E = 0: ID am Beginn, 1: Ende ; TTT = 7: Aus, 6..0 Tastgeschwindigkeit 45,50,60,70,80,90,120 BpM ; Byte 1 = Sendedauer des Strings in Sekunden ; Byte 2..17: Zeichen im Morseformat IDDOTS: .BYTE 1 ; Noch zu senden für aktuelles Element eeee aaaa ; eeee Zahl der noch zu sendenden Ein-Punkte, aaaa Aus-Punkte ; $00 = ID-Senden aus, $FF = fertig mit String IDCTR: .BYTE 1 ; Zählt beim ID-Senden die Elemente sssc cccc ; ccccc = Aktuelles Byte 0..16 ; sss = Nächste zu sendende Stelle 0..5 TIK4K8: .BYTE 1 ; Interrupt-Hdlr: Zählt alle 4,8 kHz bis 160 = 30 Hz TIKKEY: .BYTE 1 ; Interrupt-Hdlr: Zählt alle 60 Hz bis 360/BpM (6 für 60 BpM) ; ;***** EEPROM Useage ; Adress 0: FOXID ; Adress 1..18: CWID ; ;**** Serial Interface Data Format ; ; Datenformat für die serielle Übertragung: ; Pegel: Ruhezustand = High, Treiber OD, Pull-Up auf Sende- und Empfangsseite ; Geschwindigkeit: 1200 baud ; Format: 1 Startbit (L), 16 Nutzbits (4b Prüfsumme, 4b Kommando, 8b Daten), 1 Stopbit (H) ; Reihenfolge Bit 7 (Highest) -> Bit 0 (Lowest) ; Prüfsumme auf Halbbyte-Basis (in H0) ist L0 x H1 x L1 x Pattern (x = Exor) ; Pattern ist $A -> Fuchs, $5 -> FoxPro ; Eine Kommando-Übertragung dauert 16 msec, ein Lesevorgang (Kommando + Antwort) 32 msec ; ; Kommandos FoxPro -> Fuchs: ; $0..$9 : Lade Fuchsstatus Register 0..9 mit 8b Daten ; $A : Lade Testlauf Register mit 8b Daten ; $B : Lade FoxID-Register mit 8b Daten und speichere Kopie ins EEPROM ; $C : Starte Oszillator-Abgleich-Modus ; $D : Setze EEPROM-Adresse EEADR auf 8b-Wert (für CW-ID) ; $E : Schreibe 8b Daten ins EEPROM @ EEADR, inkrementiere EEADR ; ; $F_00..09: Lese Fuchsstatus Register 0..9 ; $F_0A : Lese Testlauf Register ; $F_0B : Lese FoxID Register ; $F_0C : Lese Software EC-Level ; $F_0D : Lese 30 Hz Timer (TIK30) ; $F_0E : Lese 8b Daten aus EEPROM @ EEADR ; $F_0F : Frei ; ; Lese-Kommandos werden vom Fuchs beantwortet im Format ; 4b Prüfsumme, 4b Register-Nr. (wie im Lese Kommando), 8b Daten ; ; Zusatzeffekte: Einige Kommandos lösen Zusatzfunktionen aus ; $0 : (Lade Fuchsstatus 0) setzt zugleich 30 Hz-Timer (TIK30) auf Null ; und Testsendetimer (TXTIMR) auf Null ; $B : (Lade FoxID-Register) speichert zugleich Kopie ins EEPROM ; $F_0B : (Lese FoxID-Register) setzt EEADR auf 1 (= CWID Byte 0) ; ;**** Code starts here ***************************************************** ; .CSEG .ORG 0 ; ; ;++++ Interrupt Vectors ; RJMP START ; 1 Reset RJMP START ; 2 RJMP START ; 3 RJMP START ; 4 RJMP START ; 5 RJMP TIMER ; 6 Timer 0 Overflow ; ;++++ Start here after Reset ; START: ; ; Stackpointer wird bei Reset per Hardware auf RAMEND gesetzt ; ; Wait 50 ms for power to settle clr ZH STAR1: adiw ZL,1 ; 2~ 4~ * 65k /5 MHz = 50 msec brne STAR1 ; 2~ ; ;++++ Initialize Port B Bit 0 as Output TX On (+OscOn) ; Bit 1 as Output Modulation (-PA On) ; (Input with Pull-Up, except during Xmit) ; Bit 2 as Input w/o Pull-Up (switched to O/D Output) ldi WRK,$01 out DDRB,WRK ldi WRK,$02 out PORTB,WRK ; ;++++ Intialize Timer/Counter 0 as 4800 Hz Timing Interrupt ; (4,9152 Mhz/64/16) ldi WRK,$03 ; Set Clock Divider to 64 out TCCR0,WRK ldi WRK,-16 ; Set Counter to 256-16 out TCNT0,WRK ldi WRK,$02 out TIMSK,WRK ; Enable Counter 0 Overflow Interrupt ; ;++++ Initialize some Register-Variables ; ; Fuchs ID und CWID aus EEPROM holen ldi ZL,0 ; Adresse 0 rcall GETEEP mov FOXID,WRK ldi WRK,DEFFOX ; Fuchs ID auf Default-Fuchs sbrc FOXID,3 ; .. falls EEPROM leer = $FF mov FOXID,WRK ; ; Wenn Taster im µFoxPro gedrückt: Abflug zum Tasten-Konfigurator sbis PINB,2 rjmp CONFIG ; STAR2: rcall GETEEP ; 18 Bytes CWID holen push WRK ; und auf Stack abladen cpi ZL,19 brne STAR2 STAR3: ldi ZL,CWID+18 ; RAM-Pointer auf Ende von CWID +1 STAR4: pop WRK ; Stack ins RAM leeren st -Z,WRK cpi ZL,CWID brne STAR4 ; ldi ZL,1 ; EEADR initialisieren auf CWID Byte 0 sts EEADR,ZL ; ; Default-Status: 5 Füchse, Aktueller Fuchs = dieser, Gesamt 6h, Suchmodus Ein clr STA0 ; Zeit = 00:00 ldi STA1,$D0 ; 5 Füchse, Suchmodus Ein clr STA2 ; 60" pro Fuchs mov STA3,FOXID ; Aktueller Fuchs = Eigene Fuchs# andi STA3,$07 ori STA3,$30 ; Modus 3 = Senden clr WRK ; Sendestart = Sofort mov STA8,WRK ldi WRK,36 ; Sendedauer 36 * 10' = 6 Stunden mov STA9,WRK ldi WRK,$FF ; Beide Testläufe Aus mov STA4,WRK mov STA6,WRK ; clr TXTIMR clr CWCTR clr SERCNT clr SEMA clr TIK30 clr MODCTR ldi WRK,0 sts TIK4K8,WRK sts TIKKEY,WRK sts IDDOTS,WRK ldi WRK,5 ; OscOn nach Reset 5 sec auf inaktiv mov PODEL,WRK ; lds WRK,CWID ; Wenn CWID eingeschaltet für Durchgangs-Anfang sbrc WRK,3 rjmp STAR5 andi WRK,$07 cpi WRK,$07 breq STAR5 ldi WRK,$01 ; .. CW-ID starten sts IDDOTS,WRK ldi WRK,$00 sts IDCTR,WRK ; ;++++ Wenn Taster im µFoxPro gedrückt: Tasten-Konfigurator starten STAR5: sbis PINB,2 rjmp CONFIG ; ;++++ Start Interrupt Handler sei ; Global Interrupt enable ; ; ************* ;**** Main Loop **************************************************** ; ************* ; MAIN: ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;++++ On Key Timing Event: Handle LED Flash/Transmit/MOe..MO5 ++++++ ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; MAIN1: sbrs SEMA,5 ; Wenn Key Event rjmp MAIN2 cbr SEMA,$20 ; .. Semaphore löschen ; ; ++ Wenn Tune-Taster gedrückt: OSCOn einschalten sbic DDRB,1 ; Wenn -PAOn Leitung Input rjmp M10 sbic PINB,1 ; .. und trotzdem auf Low-Level rjmp M10 ; .. dann ist der Taster gedrückt sbi PORTB,0 ; .... Dann Oszillator hart einschalten rjmp M1A ; .... und fertig mit Sendersteuerung ; ;++ TX-Timer updaten und abhandeln M10: tst TXTIMR ; Wenn TX-Timer=0 : Normalbetrieb breq M11 mov WRK,TXTIMR ; Wenn TX-Timer >15 andi WRK,$F0 brne MAIN10 ; Kennung senden ; Wenn TX-Timer = 15..1 sbr SEMA,$01 ; .. TX Flag Ein sbi PORTB,0 ; ...Oszillator einschalten cbr SEMA,$08 ; .. Blinken Aus dec TXTIMR ; .. runterzählen breq M19 ; .. und wenn 0 erreicht TX ausschalten rjmp MAI199 ; ;++ Rückholfuchs sendet immer M11: mov WRK,FOXID ; Wenn Fuchsnummer = 0,6,7 (Rückholer) andi WRK,$07 breq MAIN10 ; .. Kennung MO senden andi WRK,$06 cpi WRK,$06 breq MAIN10 ; ;++ Weiteres nur wenn aktueller Fuchs = dieser Fuchs mov WRK,FOXID ; Dieser Fuchs und eor WRK,STA3 ; aktueller Fuchs andi WRK,$07 ; vergleichen brne M19 ; Wenn verschieden: Sender Aus ; mov ZL,STA3 ; Modus nach ZL separieren andi ZL,$70 ;-- Modus=0 : Nicht senden breq M19 ;-- Modus 1,2,3 : 12..60" senden M123: cpi ZL,$40 brne MAIN10 ;-- Modus 4 und Suchmodus = Ein : 15" Senden sbrs STA1,7 rjmp M19 ; ;++++ CW-Kennung Senden nur während der ersten 15 Sekunden ++++++ M15: mov WRK,STA2 ; Sekunden separieren andi WRK,$3F cpi WRK,15 brcs MAIN10 ; ;++++ Nicht senden, LED blinken lassen ++++++++++++++++++++++++++ M19: cbi PORTB,0 ; Oszillator ausschalten (ausser Tune-Taster gedrückt) M1A: cbr SEMA,$01 ; Senden Aus sbr SEMA,$08 ; Blinken Ein ldi CWCTR,6 ; Counter vorbereiten für nächsten Durchgang rjmp MAI199 ; ;++++ CW-Kennung Senden ++++++++++++++++++++++++++++++++++++++++++ MAIN10: cbr SEMA,$08 ; Pausenblinken aus tst PODEL ; Wenn nicht mehr im Power-On Delay brne MAI101 cpi CWCTR,6 ; .. und CWCTR = 6 brne MAI101 sbi PORTB,0 ; .... dann Oszillator einschalten ; MAI101: lds WRK,IDDOTS ; Wenn ID aktiv tst WRK breq MAI102 rjmp MAIN19 ; ... zur Sonderbehandlung ID gehen ; MAI102: mov WRK,CWCTR ; CW-Counter in Byte und Bit auflösen andi WRK,$F8 MAIN11: cpi WRK,0 ; Richtiges Byte holen brne MAIN12 ldi ZL,0b00000001 ; m MAIN12: cpi WRK,8 brne MAIN13 ldi ZL,0b11011100 ; MAIN13: cpi WRK,16 brne MAIN14 ldi ZL,0b01110111 ; o MAIN14: cpi WRK,24 brne MAIN15 ldi ZL,0b01110001 ; e..5 MAIN15: cpi WRK,32 brne MAIN16 ldi ZL,0b01010101 ; MAIN16: mov WRK,CWCTR ; Richtiges Bit in Position 7 schieben andi WRK,$07 MAIN17: tst WRK breq MAIN18 rol ZL dec WRK rjmp MAIN17 ; MAIN18: mov WRK,FOXID ; Sonderfall: Wenn Fuchs = 6,7 andi WRK,$06 cpi WRK,$06 brne MAI180 cpi CWCTR,29 ; und CW-Counter >= 29 brcs MAI180 clr ZL ; .. dann lange Sendepause cbi PORTB,0 ; .. und Oszillator ausschalten ; MAI180: sbrs ZL,7 ; Aktuelles Bit in TX On Semaphore kopieren cbr SEMA,$05 ; TX Off, Blinken Off sbrc ZL,7 sbr SEMA,$01 ; bzw. TX On, Blinken Off ; inc CWCTR ; Counter hochzählen mov WRK,FOXID ; Eigene Fuchsnummer aus FoxID holen andi WRK,$07 lsl WRK ; Fuchsnummer verdoppeln cpi WRK,12 ; Wenn 2*Fuchsnummer = 12 brne MAI18A ldi WRK,40 ; .. Stringlänge = 40 = 4/8 sec rjmp MAI182 MAI18A: cpi WRK,14 ; Wenn 2*Fuchsnummer = 14 brne MAI181 ldi WRK,80 ; .. Stringlänge = 80 = 8/16 sec rjmp MAI182 MAI181: ldi ZH,30 ; .. sonst Basis-Stringlänge dazu add WRK,ZH ; MAI182: cp WRK,CWCTR ; Wenn CWCTR = Basis-Stringlänge + 2*Fuchsnummer brne MAI183 ; (bzw. bei Fuchs 6 CWCTR = wie oben) clr CWCTR ; .. Counter auf 0 setzen MAI183: rjmp MAI199 ; fertig mit CWID ; ; ;++++ ID Senden, String ist im RAM ++++++++++++++++++++++++++++++ MAIN19: tst PODEL ; Wenn nicht mehr im Power-On Delay brne M190 sbi PORTB,0 ; .. Oszillator einschalten ; M190: lds WRK,CWID+2 ; Wenn erstes Sendebyte ein '/' cpi WRK,$95 ; .. weiter MO-Kennung senden breq MAI102 ; .. aber mit ID-Geschwindigkeit ; lds ZL,IDDOTS ; Steuerparameter holen lds ZH,IDCTR ldi CWCTR,6 ; Pointer für MO*-Kennung auf Anfang cpi ZL,$FF ; Wenn fertig mit ID brne M191 ; .. Tastung aus cbr SEMA,$05 ; TX Off, Blinken Off rjmp M199 ; M191: mov WRK,ZL ; Noch Ein-Bits zu senden? swap WRK andi WRK,$0F breq M192 sbr SEMA,$01 ; Ja: TX On, Blinken Off dec WRK ; 1er-Zähler dekrementieren swap WRK andi ZL,$0F or ZL,WRK ; und wieder einbauen rjmp M193 ; M192: tst ZL ; Wenn keine Ein-Bits: Noch Aus-Bits? breq M193 cbr SEMA,$05 ; Ja: TX Off, Blinken Off dec ZL ; 0er-Zähler dekrementieren ; M193: tst ZL ; Wenn IDDOTS jetzt auf $00 brne M199 mov WRK1,ZH ; Bytecounter holen andi WRK1,$1F cpi WRK1,$10 ; Wenn Bytecounter = 16 brne M1931 ldi ZL,$FF ; .. fertig rjmp M199 ; ; Wenn Bytecounter < 16 M1931: push ZH ; Aktuell gesendetes Byte holen push ZL ; Adresse ist CWID + 2 + Bytecounter clr ZH ldi ZL,CWID+2 add ZL,WRK1 ld WRK,Z pop ZL pop ZH ; cpi WRK,$00 ; Wenn Sende-Byte = $00 brne M1932 ldi ZL,$04 ; Buchstabenabstand erzeugen inc ZH ; und Bytezähler weiterschalten rjmp M199 M1932: cpi WRK,$10 ; Wenn Sende-Byte = $10 brne M194 ldi ZL,$F0 ; Langen Strich ohne Pause erzeugen inc ZH ; und Bytezähler weiterschalten rjmp M199 ; M194: mov WRK2,ZH ; Bitcounter holen lsr WRK2 swap WRK2 andi WRK2,$07 push WRK2 push WRK M1941: tst WRK2 ; Datenbyte um Bitcounter Stellen nach links schieben breq M1942 ; bis aktuelles Bit in MSb lsl WRK dec WRK2 rjmp M1941 M1942: sbrs WRK,7 ; Wenn aktuelles Bit 0 ldi ZL,$11 ; .. Punkt senden sbrc WRK,7 ldi ZL,$31 ; .. sonst Strich senden pop WRK ; Wiederherstellen aktuelles Datenbyte pop WRK2 ; und Bitcounter inc WRK2 ; Bitcounter hochzählen andi WRK,$7 ; Mit Bitcount im Datenbyte vergleichen cp WRK,WRK2 breq M195 ; Wenn noch nicht erreicht mov ZH,WRK1 ; IDCTR wieder zusammenbauen swap WRK2 lsl WRK2 andi WRK2,$E0 or ZH,WRK2 rjmp M199 ; M195: inc WRK1 ; Wenn max Bitcount für dieses Byte erreicht mov ZH,WRK1 ; Bytectr auf nächstes Byte inc ZL ; und Buchstabenabstand einfügen inc ZL ; M199: sts IDDOTS,ZL ; Steuerparameter retten sts IDCTR,ZH MAI199: ; +++++++++++++++++++++++++++++++++ ;++++ On 1 sec Event: Update Status ++++++++++++++++++++ ; +++++++++++++++++++++++++++++++++ ; Der folgende Codeteil (mit X2-Labels) wird fast identisch im FoxPro verwendet ; MAIN2: sbrs SEMA,4 ; Wenn 1 s Event rjmp MAIN3 cbr SEMA,$10 ; .. Semaphore löschen ; ;++++ Power On Delay tst PODEL ; Wenn Power On Delay > 0 breq X21 dec PODEL ; .. runterzählen ; ;++++ Sende-Timer X21: mov WRK,STA2 ; Zur Zeit n*16 sec andi WRK,$0F brne X22 tst TXTIMR ; .. und wenn Sende-Timer > 0 breq X22 dec TXTIMR ; .... Sendetimer runterzählen ; ;++++ Echtzeit-Uhr eine Sekunde weiterzählen X22: mov WRK,STA2 ; STA2 Bit 7,6 separieren andi WRK,$C0 andi STA2,$3F inc STA2 ; Sekunden hochzählen cpi STA2,60 ; .. bis 59 breq X221 or STA2,WRK rjmp X23 X221: mov STA2,WRK inc STA1 ; Minuten hochzählen mov WRK,STA1 andi WRK,$0F cpi WRK,10 ; .. bis 9 brne X23 andi STA1,$F0 ; .. linkes Nibble STA1 erhalten! inc STA0 ; 10 Minuten hochzählen cpi STA0,144 ; .. bis 23:50 brne X23 clr STA0 ; ;++++ Wenn Sekunde auf Umschaltzeit: aktuellen Fuchs weiterschalten X23: mov WRK,STA3 ; Wenn Modus > 0 andi WRK,$70 breq X24 mov ZL,STA2 ; und Sekunde = 0 andi ZL,$3F breq X235 ; .. weiterschalten ; cpi WRK,$10 ; Wenn Modus = 1 brne X231 cp STA4,STA5 ; .. und Test1 Endezeit = Startzeit breq X232 X231: cpi WRK,$20 ; oder Modus = 2 brne X233 cp STA6,STA7 ; .. und Test2 Endezeit = Startzeit brne X233 X232: mov WRK,STA2 ; .... 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 STA2,$40+30 ; .. die weiteren Durchgangslängen-abhängigen breq X235 ; .. Schaltzeitpunkte abtesten cpi STA2,$80+15 breq X235 cpi STA2,$80+30 breq X235 cpi STA2,$80+45 breq X235 cpi STA2,$C0+12 breq X235 cpi STA2,$C0+24 breq X235 cpi STA2,$C0+36 breq X235 cpi STA2,$C0+48 brne X24 ; X235: inc STA3 ; .. Aktuelle Fuchsnummer hochzählen mov WRK,STA3 ; .. Wenn letzte Fuchsnummer überschritten andi WRK,$07 mov ZH,STA1 swap ZH andi ZH,$07 inc ZH cp ZH,WRK brne X24 andi STA3,$F8 ; .... Aktuelle Fuchsnummer = 1 inc STA3 ; ;++++ Zu vollen 10 Minuten Ein-/Ausschaltzeiten prüfen und ggf. Modus ändern X24: mov WRK,STA2 ; Wenn Sekunden auf 0 andi WRK,$3F brne X247 mov WRK,STA1 ; und Minuten Einer auf 0 andi WRK,$0F brne X247 ; mov WRK,STA3 ; Aktuellen Modus holen andi WRK,$70 cpi WRK,$40 ; Bei Modus 4 = Fertig breq X248 ; .. nix tun cpi WRK,$30 ; Bei Modus 3 = Senden brne X241 cp STA0,STA9 ; .. Wenn Zeit = Sende-Ende brne X248 ldi STA3,$41 ; .... Modus auf 4 setzen, Fuchsnummer auf 1 für Nachlauf rjmp X248 X241: cpi WRK,$00 ; Bei Modus 0 = Vorlauf brne X242 ; cp STA0,STA4 ; .. Wenn Zeit = Start Test1 brne X242 ldi STA3,$11 ; .. Modus auf 1 = Test 1 rjmp X248 X242: cpi WRK,$10 ; Bei Modus 1 = Test 1 brne X243 ; cp STA0,STA5 ; .. Wenn Zeit = Ende Test 1 brne X243 ldi STA3,$00 ; .. Modus auf 0 = Vorlauf rjmp X248 X243: cpi WRK,$00 ; Bei Modus 0 = Vorlauf brne X244 ; cp STA0,STA6 ; .. Wenn Zeit = Start Test2 brne X244 ldi STA3,$21 ; .. Modus auf 2 = Test 2 rjmp X248 X244: cpi WRK,$20 ; Bei Modus 2 = Test 2 brne X245 ; cp STA0,STA7 ; .. Wenn Zeit = Ende Test 2 brne X245 ldi STA3,$00 ; .. Modus auf 0 = Vorlauf rjmp X248 X245: cp STA0,STA8 ; Bei Modus = 0,1,2: Wenn Zeit = Start Senden brne X248 ldi STA3,$31 ; .. Modus auf 3 = Senden rjmp X248 ; X248: mov WRK,FOXID ; Wenn Fuchs = Rückholer andi WRK,$07 breq X2481 andi WRK,$06 cpi WRK,$06 brne X249 X2481: lds WRK,CWID ; .. und CWID eingeschaltet andi WRK,$07 cpi WRK,$07 breq X249 rjmp M2555 ; .. ID senden am Beginn jeder 10' ; ;++++ Zur Zeit 2,5 Minuten Schnell-Testläufe beenden X247: mov WRK,STA2 ; Wenn Sekunden auf 30 andi WRK,$3F cpi WRK,30 brne X249 mov WRK,STA1 ; und Minuten Einer auf 2 andi WRK,$0F cpi WRK,2 brne X249 ; mov WRK,STA3 ; Aktuellen Modus holen andi WRK,$70 X2471: cpi WRK,$10 ; Wenn Modus 1 = Test 1 brne X2472 cp STA4,STA5 ; .. und Test1 Endezeit = Startzeit brne X2472 ldi STA3,$00 ; .... Modus auf 0 = Vorlauf X2472: cpi WRK,$20 ; Wenn Modus 2 = Test 2 brne X249 cp STA6,STA7 ; .. und Test2 Endezeit = Startzeit brne X249 ldi STA3,$00 ; .... Modus auf 0 = Vorlauf X249: ; ; ;++++ Wenn CWID eingeschaltet: Zur richtigen Zeit Starten/Beenden M25: mov ZL,STA2 ; Aktuelle Sekunden holen andi ZL,$3F ; mov WRK,STA2 ; Durchgangslänge in Sekunden dekodieren andi WRK,$C0 ; 00..11 ist 60, 30, 15, 12 ldi ZH,60 cpi WRK,$40 brne M251 ldi ZH,30 M251: cpi WRK,$80 brne M2511 ldi ZH,15 M2511: cpi WRK,$C0 brne M252 ldi ZH,12 M252: mov WRK,STA3 ; Aktuellen Modus holen andi WRK,$70 cpi WRK,$10 ; Wenn Modus = 1 brne M2521 cp STA4,STA5 ; .. und Test1 Endezeit = Startzeit brne M253 rjmp M2523 M2521: cpi WRK,$20 ; oder Modus = 2 brne M2522 cp STA6,STA7 ; .. und Test2 Endezeit = Startzeit brne M253 rjmp M2523 M2522: cpi WRK,$40 ; oder Modus =4 (Nachlauf) brne M253 M2523: ldi ZH,15 ; .... dann ist Durchgangslänge 15 Sekunden ; M253: sub ZL,ZH ; Zeit := Zeit Modulo Durchgangslänge brpl M253 add ZL,ZH lds WRK1,CWID+1 ; ID-Länge holen lds WRK2,CWID ; Beginn/Ende-Flag holen ; mov WRK,FOXID ; Wenn Fuchs = Rückholer (ID startet volle 10') andi WRK,$07 breq M2530 ; andi WRK,$06 cpi WRK,$06 brne M2533 M2530: cp ZL,WRK1 ; .. und Sekunde = Länge breq M2535 ; .... ID beenden rjmp M258 ; M2533: sbrs WRK2,3 ; Wenn ID am Ende rjmp M254 tst ZL ; .. und Sekunde = 0 brne M255 M2535: clr WRK sts IDDOTS,WRK ; .. ID beenden rjmp M258 M254: cp ZL,WRK1 ; ID am Anfang und Sekunde = Länge breq M2535 ; .. ID beenden ; M255: lds WRK,CWID ; Wenn CWID eingeschaltet andi WRK,$07 cpi WRK,$07 breq M258 sbrs WRK2,3 ; und wenn ID am Ende rjmp M256 sub ZH,WRK1 ; und Zeit = Durchgangslänge - ID-Länge cp ZL,ZH brne M258 ; M2555: ldi WRK,$06 ; .. ID starten sts IDDOTS,WRK ldi WRK,$00 sts IDCTR,WRK rjmp M258 M256: tst ZL ; CWID eingeschaltet und ID am Anfang und Zeit = 0 breq M2555 ; .. ID starten ; M258: tst TXTIMR ; Wenn allerdings der TXTIMR läuft (Testsendung mit TXn') breq M259 clr WRK sts IDDOTS,WRK ; .. ID immer unterdrücken M259: ; ; +++++++++++++++++++++++++++++++++++ ;++++ Handle Commands over Serial I/F ++++++++++++++++++++++ ; +++++++++++++++++++++++++++++++++++ ; MAIN3: sbrs SEMA,6 ; If serial RX complete semaphore rjmp MAIN39 cbr SEMA,$40 ; .. clear semaphore ; mov WRK,SHIFT0 ; Separate Command cpi WRK,$00 brne M31 ; Command 0 = Lade Status 0 mov STA0,SHIFT1 ; clr TIK30 ; .. zusätzlich 30 Hz Timer auf Start neue Sekunde clr TXTIMR ; .. und Sendetimer TXTIMR auf Aus M31: cpi WRK,$01 brne M32 ; Command 1 mov STA1,SHIFT1 M32: cpi WRK,$02 brne M33 ; Command 2 mov STA2,SHIFT1 M33: cpi WRK,$03 brne M34 ; Command 3 mov STA3,SHIFT1 M34: cpi WRK,$04 brne M35 ; Command 4 mov STA4,SHIFT1 M35: cpi WRK,$05 brne M36 ; Command 5 mov STA5,SHIFT1 M36: cpi WRK,$06 brne M37 ; Command 6 mov STA6,SHIFT1 M37: cpi WRK,$07 brne M38 ; Command 7 mov STA7,SHIFT1 M38: cpi WRK,$08 brne M39 ; Command 8 mov STA8,SHIFT1 M39: cpi WRK,$09 brne M3A ; Command 9 = Lade Status 9 mov STA9,SHIFT1 M3A: cpi WRK,$0A brne M3B ; Command $A = Lade Testlauf-Register mov TXTIMR,SHIFT1 M3B: cpi WRK,$0B brne M3C ; Command $B = Lade FoxID-Register mov FOXID,SHIFT1 rjmp M3BWR M3C: cpi WRK,$0C brne M3D ; Command $C = Oszillator-Abgleich-Modus rjmp OSCOUT M3D: cpi WRK,$0D brne M3E ; Command $D = Lade EEPROM-Adress-Register EEADR sts EEADR,SHIFT1 M3E: cpi WRK,$0E brne M3F ; Command $E = Schreibe EEPROM @ EEADR+ rjmp WRTEEP ; M3F: cpi WRK,$0F ; Command $F = Read Register n brne M39X mov WRK,SHIFT1 ; Zu lesende Registernummer mov SHIFT0,WRK ; .. für Antwort bereitstellen ; M3F0: cpi WRK,$00 ; Lese Status 0 brne M3F1 mov SHIFT1,STA0 M3F1: cpi WRK,$01 ; Lese Status 1 brne M3F2 mov SHIFT1,STA1 M3F2: cpi WRK,$02 ; Lese Status 2 brne M3F3 mov SHIFT1,STA2 M3F3: cpi WRK,$03 ; Lese Status 3 brne M3F4 mov SHIFT1,STA3 M3F4: cpi WRK,$04 ; Lese Status 4 brne M3F5 mov SHIFT1,STA4 M3F5: cpi WRK,$05 ; Lese Status 5 brne M3F6 mov SHIFT1,STA5 M3F6: cpi WRK,$06 ; Lese Status 6 brne M3F7 mov SHIFT1,STA6 M3F7: cpi WRK,$07 ; Lese Status 7 brne M3F8 mov SHIFT1,STA7 M3F8: cpi WRK,$08 ; Lese Status 8 brne M3F9 mov SHIFT1,STA8 M3F9: cpi WRK,$09 ; Lese Status 9 brne M3FA mov SHIFT1,STA9 M3FA: cpi WRK,$0A ; Lese Testlauf-Register brne M3FB mov SHIFT1,TXTIMR M3FB: cpi WRK,$0B ; Lese Fox-ID brne M3FC mov SHIFT1,FOXID ldi ZL,1 ; EEADR auf 1 setzen sts EEADR,ZL M3FC: cpi WRK,$0C ; Lese Software-EC-Lever brne M3FD ldi WRK,VERSHL mov SHIFT1,WRK M3FD: cpi WRK,$0D ; Lese 30Hz-Timer brne M3FE mov SHIFT1,TIK30 M3FE: cpi WRK,$0E ; Lese EEPROM @ EEADR+ brne M3FF lds ZL,EEADR ; EEADR holen und in absolute Adresse umrechnen ldi ZH,CWID-1 add ZL,ZH clr ZH ld SHIFT1,Z lds ZL,EEADR ; EEADR inkrementieren inc ZL sts EEADR,ZL ; M3FF: sbr SEMA,$02 ; Sende Shift Register Semaphore setzen M39X: rjmp MAIN39 ; ; ;++++ Fuchs ID ins EEPROM schreiben M3BWR: ldi ZL,0 out EEAR,ZL ; EEPROM Adresse 0 out EEDR,FOXID rcall WEEP rjmp MAIN39 ; ;++++ 1 Byte ins EEPROM @ EEADR schreiben WRTEEP: lds ZL,EEADR ; Adresse der RAM-Kopie bauen ldi ZH,CWID-1 add ZL,ZH clr ZH st Z,SHIFT1 ; Kopie ins RAM legen lds ZL,EEADR ; EEADR inkrementieren out EEAR,ZL inc ZL sts EEADR,ZL out EEDR,SHIFT1 ; Byte ins EEPROM schreiben rcall WEEP ; MAIN39: ; MAIN9: rjmp MAIN ; Repeat forever ; ;++++ Write one Byte to EEPROM WEEP: cli ; Interrupt ausschalten ldi ZL,$04 ; Schreiben ldi ZH,$02 out EECR,ZL ; Set EEPROM Master Write Enable out EECR,ZH ; Set EEPROM Write sei ; Interrupt wieder an WEEP1: sbic EECR,1 ; Wait for Write complete rjmp WEEP1 ret ;++++ Oscillator Calibration Mode ; Output Fosc/4 on Pin6/PB1 until Reset OSCOUT: cli ; No more interrupts sbi DDRB,1 ; Switch PB1 to Output ldi ZH,$00 ; Patterns to toggle PB1 ldi ZL,$02 OSCOU1: out PORTB,ZH ; 1~ Toggle PB1.. out PORTB,ZL ; 1~ rjmp OSCOU1 ; 2~ .. forever ; ; *********************************** ; ******* Subroutines ********************************** ; *********************************** ; ; 1 Byte aus EEPROM @ ZL+ holen und in WRK ablegen GETEEP: push ZL out EEAR,ZL clr ZL out EEARH,ZL ldi ZL,$01 out EECR,ZL ; Set EEPROM Read Cmd GETEE1: in ZL,EECR ; Wait for EEPROM Read complete andi ZL,$01 brne GETEE1 in WRK,EEDR ; Fuchs ID lesen pop ZL inc ZL ret ; ; *********************************** ; ******* 4800 Hz Timer Interrupt Handler ********************************** ; *********************************** ; TIMER: in IWRK,SREG ; Save Statusreg push IWRK ; ldi IWRK,-16 ; Reset Counter 0 for next interrupt out TCNT0,IWRK ; ;++++ TX-Output Service ; TIMA: sbrc SEMA,0 rjmp TIM0 ; If TX Flag Off .. sbrs SEMA,3 ; .. and Pausenblinken an rjmp TIMA8 ; ;++ Pausenblinken mov IWRK,STA3 ; Aktuellen Mode holen andi IWRK,$70 cpi IWRK,$40 ; Wenn Modus <> Ende breq TIMA8 cpi TIK30,0 ; .. zur Zeit 0/30 s breq TIMA7 ; .... LED On tst IWRK breq TIMA8 ; Wenn Modus <> Vorlauf, Ende cpi TIK30,9 ; .. zur Zeit 9/30 s brne TIMA8 TIMA7: sbi DDRB,1 ; .... LED On cbi PORTB,1 rjmp TIMA9 TIMA8: cbi DDRB,1 ; .... sonst LED Off sbi PORTB,1 ; TIMA9: rjmp TIM1 ; ;++ TX Flag On: Senden TIM0: mov IWRK,FOXID ; Modulationsfrequenz aus FoxID separieren swap IWRK andi IWRK,$03 .if A1ONLY == 1 ; Sonderversion für nur-A1-Füchse ldi IWRK,3 ; Tonmodulation unterdrücken .endif cpi IWRK,3 ; Wenn MM = 3 = A1 brne TIM01 sbi DDRB,1 ; .. Dauerträger setzen cbi PORTB,1 rjmp TIM1 ; .. und fertig mit Modulation ; TIM01: inc IWRK ; Sonst ist Teilerwert = MM + 2 inc IWRK inc MODCTR ; Frequenzteiler weiterzählen cp MODCTR,IWRK ; Wenn Zählwert = Teilerwert brne TIM02 sbi DDRB,1 sbi PORTB,1 ; .. Modulation auf High TIM02: lsl IWRK ; Wenn Zählwert = 2 * Teilerwert cp MODCTR,IWRK brne TIM1 sbi DDRB,1 cbi PORTB,1 ; .. Modulation auf Low clr MODCTR ; .. und Zählwert auf 0 ; ++ 4k8 Service ; TIM1: lds IWRK,TIK4K8 ; Increment 4,8 kHz Timer inc IWRK sts TIK4K8,IWRK cpi IWRK,80 ; .. at 80 extra timming event for CW Keying breq TIM3 cpi IWRK,160 ; .. wrap on 160 (30 Hz) brne TIM5 clr IWRK sts TIK4K8,IWRK ; ; ++ 30 Hz Service ; TIM2: inc TIK30 ; Increment 30 Hz Timer cpi TIK30,30 ; Wrap on 30 brne TIM3 clr TIK30 sbr SEMA,$10 ; .. and set 1s Timing Event Flag ; TIM3: lds IWRK2,TIKKEY ; Increment 60 Hz CW-Timer inc IWRK2 sts TIKKEY,IWRK2 lds IWRK,IDDOTS ; Wird gerade die ID gesendet? tst IWRK breq TIM31 lds IWRK,CWID ; .. dann CW-Geschwindigkeit andi IWRK,$07 ; .. aus CWID Byte 0 holen inc IWRK ; .. und um 3 erhöhen inc IWRK rjmp TIM32 TIM31: mov IWRK,FOXID ; Keine ID: CW-Geschwindigkeit swap IWRK ; .. aus FOXID Bit 7,6 holen lsr IWRK lsr IWRK andi IWRK,$03 ori IWRK,$04 ; .. und um 5 erhöhen TIM32: inc IWRK cp IWRK2,IWRK ; Wenn TIKKEY-Endwert brcs TIM5 clr IWRK2 sts TIKKEY,IWRK2 ; .. Tikkey auf 0 sbr SEMA,$20 ; .. und Key Timing Event Flag setzen ; ; ++ Serial Interface Service ; + Receive + TIM5: sbrc SERCNT,7 ; Wenn Counter >= 128 rjmp TIM55 ; .. zum Sendeteil wechseln ; tst SERCNT ; Wenn Counter = 0 brne TIM51 sbis PINB,2 ; .. und Leitung auf Low inc SERCNT ; .... Counter auf 1 setzen = Empfangsstart rjmp TIM55 ; .. sonst Sende-Semaphore testen ; TIM51: inc SERCNT ; Wenn Counter > 0 : inkrementieren sbrc SERCNT,0 ; Prüfen, ob Counter = n*4 + 2 rjmp TIM59 sbrs SERCNT,1 rjmp TIM59 cpi SERCNT,70 ; Bei Counterwert 70: Fertig brne TIM52 clr SERCNT ; .. Counter auf 0 ldi IWRK,$A0 ; Prüfbyte generieren und vergleichen eor IWRK,SHIFT0 ; $A x H0 x H1 x L0 x L1 soll 0 ergeben eor IWRK,SHIFT1 mov IWRK2,IWRK swap IWRK2 eor IWRK,IWRK2 andi IWRK,$F0 brne TIM59 ; .. wenn ok mov IWRK,SHIFT0 ; .... Prüfsumme entfernen andi IWRK,$0F mov SHIFT0,IWRK sbr SEMA,$40 ; .... und RX complete Semaphore setzen rjmp TIM59 ; TIM52: clc ; Bei Counterwert (2,) 6, ..66 sbic PINB,2 ; .. ein Bit von Leitung nach Carry einlesen sec rol SHIFT1 ; .. und 16-bit-Schieberegister weiterschieben rol SHIFT0 ; ; + Send + TIM55: lds IWRK,TIK4K8 ; Wenn vierter 4,8kHz Event = 1200Hz andi IWRK,$03 brne TIM59 ; sbrs SEMA,1 ; Wenn Sende Semaphore gesetzt rjmp TIM56 ; cbr SEMA,$02 ; Semaphore löschen sbi DDRB,2 ; Startbit senden ldi SERCNT,128 ; Counter auf Senden ldi IWRK,$05 ; Prüfbyte generieren, Startwert eor IWRK,SHIFT0 ; .. ExOr der drei Halbbytes eor IWRK,SHIFT1 swap IWRK eor IWRK,SHIFT1 andi IWRK,$F0 mov IWRK2,IWRK mov IWRK,SHIFT0 ; in Byte 0 einbauen andi IWRK,$0F or IWRK,IWRK2 mov SHIFT0,IWRK ; rjmp TIM59 ; TIM56: sbrs SERCNT,7 ; Wenn Counter >= 128 rjmp TIM59 inc SERCNT ; .. Counter hochzählen cpi SERCNT,145 ; Wenn Counter = +145 (=fertig) brne TIM57 cbi DDRB,2 ; .. Leitungstreiber aus clr SERCNT ; .. und Counter wieder auf 0 rjmp TIM59 ; TIM57: sbrs SHIFT0,7 ; Für Counter = 127..144: sbi DDRB,2 ; .. Bit 7 von Shift0 senden sbrc SHIFT0,7 cbi DDRB,2 sec ; .. und 16 bit Shiftregister links schieben rol SHIFT1 rol SHIFT0 ; TIM59: ; ++ Conclusion of Interrupt Service ; TIM99: cli ; No interrupts during conclusion pop IWRK out SREG,IWRK reti ; Interrupt-Handling beendet ; ;****************** Ende der Fuchsjagdsender-Steuerung ********************* ; ; **************************** ; ******* Drucktasten-Konfigurator ********************************* ; **************************** ; Der folgende Codeteil ist vom obigen Sendersteuerungsprogramm völlig ; getrennt. Er wird ausgeführt, wenn beim Einschalten Pin PB2 auf Ground ; liegt. Er erlaubt es, mit einem einfachen Drucktaster-/Piezosummer- ; Bediengerät (µ-FoxPro) die im EEPROM gespeicherte Konfiguration zu ; ändern, also: Fuchsnummer, Modulation, Tastgeschwindigkeit. Ausserdem ; kann der Oszillator-Abgleichmodus gestartet werden. ; ;++++ Wenn Taster > 2,5 sec gedrückt, Oszillator-Testmodus starten CONFIG: clr R16 ; Wie lange ist Taster gedrückt? CONF10: rcall DEL10M ; 10 msec-Schritte zählen inc R16 brne CONF11 ; Nach 2,5 sec Oszillatortest starten rcall OSCOUT CONF11: sbis PINB,2 rjmp CONF10 ; sbi DDRB,1 ; LED-Pin auf Output schalten ; ;++++ Fuchsnummer einstellen SETFN: mov R17,FOXID ; Fuchsnummer aus FOXID holen SETFN1: ldi R16,$24 ; Morse-F rcall MORSE dec R17 andi R17,$07 rcall MORSNN ; Eingestellte # ausgeben inc R17 rcall GETKEY ; Auf Tastendruck warten tst R18 ; Bei langem Druck breq SETFN9 ; .. nächstes item inc R17 ; Sonst Parameter inkrementieren rjmp SETFN1 SETFN9: mov R16,FOXID ; Fuchsnummer in FOXID zurückschreiben andi R16,$F0 andi R17,$07 or R16,R17 mov FOXID,R16 ; ;++++ Tast-Gechwindigkeit einstellen SETTG: mov R17,FOXID rol R17 rol R17 rol R17 andi R17,$03 SETTG1: ldi R16,$81 ; Morse-T rcall MORSE rcall MORSNN ; Eingestellte # ausgeben rcall GETKEY ; Auf Tastendruck warten tst R18 ; Bei langem Druck breq SETTG9 ; .. nächstes item inc R17 ; Sonst Parameter inkrementieren andi R17,$03 rjmp SETTG1 SETTG9: ror R17 ; Tastgeschwindigkeit in Fox-ID zurückschreiben ror R17 ror R17 andi R17,$C0 mov R16,FOXID andi R16,$3F or R16,R17 mov FOXID,R16 ; ;++++ Modulation einstellen SETMOD: mov R17,FOXID swap R17 andi R17,$03 SETMO1: ldi R16,$C2 ; Morse-M rcall MORSE rcall MORSNN ; Eingestellte # ausgeben rcall GETKEY ; Auf Tastendruck warten tst R18 ; Bei langem Druck breq SETMO9 ; .. nächstes item inc R17 ; Sonst Parameter inkrementieren andi R17,$03 rjmp SETMO1 SETMO9: swap R17 ; Modulation in Fox-ID zurückschreiben mov R16,FOXID andi R16,$CF or R16,R17 mov FOXID,R16 ; ;++++ Fertig, FoxID ins EEPROM ldi R16,$55 ; Quittung (ar) ausgeben rcall MORSE ; ldi ZL,0 ; FoxID ins EEPROM schreiben out EEAR,ZL ; EEPROM Adresse 0 out EEDR,FOXID rcall WEEP ; rjmp START ; Reset und Neustart ; ;**** Einen Tastendruck abwarten und Länge in R18 zurückgeben ; R18 = 0 für > 500 ms GETKEY: sbic PINB,2 ; Warten bis Taster gedrückt rjmp GETKEY ldi R18,200 ; Zeitzähler auf Start GETK1: rcall DEL10M tst R18 ; Zeitzähler alle 10 ms erhöhen bis 0 (=256) brne GETK2 cbi PORTB,1 ; LED On rjmp GETK3 GETK2: inc R18 GETK3: sbis PINB,2 ; Abbrechen, wenn Taster nicht mehr gedrückt rjmp GETK1 rcall PIPOFF ; 100 ms warten sbi PORTB,1 ; LED Off ret ; ;**** Zahl in R17 ausgeben, 0..4 als 1 bis 5 Dots ; 5 als - 6 als -- 7 als --- MORSNN: mov R20,R17 cpi R17,5 brne MONN1 ldi R16,$81 rjmp MORSE MONN1: cpi R17,6 brne MONN2 ldi R16,$C2 rjmp MORSE MONN2: cpi R17,7 brne MONN3 ldi R16,$E3 rjmp MORSE ; MONN3: inc R20 MONN5: rcall PIPON rcall PIPOFF dec R20 brne MONN5 rcall PIPOF3 ret ; ;**** Morsezeichen in R16 ausgeben ; Morseformat MMMM MLLL ; LLL = Zeichenlänge 1..5 Pu+Stri ; MMMMM = 0:Punkt, 1:Strich, erstes Element in Bit 7 ; MORSE: mov R22,R16 ; BitZähler separieren andi R22,$07 mov R20,R16 MO1: rol R20 ; Ein Element holen brcc MO2 rcall PIPON ; Strich bzw. Punkt ausgeben rcall PIPON MO2: rcall PIPON rcall PIPOFF ; Ein Punkt Pause dec R22 ; Wenn BitZähler noch nicht auf 0 brne MO1 ; .. nächstes Bit rcall PIPOF3 ; Letzte Pause = Strich ret ; ;**** 150 msec keinen Sound PIPOFF: ldi R21,15 POFF: rcall DEL10M dec R21 brne POFF ret ; ;**** 3 * 150 msec keinen Sound PIPOF3: ldi R21,45 rjmp POFF ; ;**** 6 * 150 msec keinen Sound PIPOF6: ldi R21,90 rjmp POFF ; ;**** 150 msec 1 kHz Sound PIPON: cbi PORTB,1 ; LED On ldi R21,150 sbi DDRB,2 PLO: rcall DEL500 ; 0,5 ms High cbi PORTB,2 rcall DEL500 ; 0,5 ms Low sbi PORTB,2 dec R21 brne PLO cbi DDRB,2 sbi PORTB,1 ; LED Off ret ; ;**** 500 µsec Delay (2500 Cycles) DEL500: clr R1 D51: inc R1 ; 3 ~ loop brne D51 D52: inc R1 ; 3 ~ loop brne D52 D53: inc R1 ; 3 ~ loop brne D53 ret ; ;**** 10 msec Delay (50000 Cycles) DEL10M: push R21 ldi R21,20 D10M: rcall DEL500 dec R21 brne D10M pop R21 ret ; ;**************************** The End ***************************** ;