; 2mMidi.ASM ; ; ********************* ; * Fuchsjagd Sender * ; ********************* ; ; Code für Fuchsjagd-Sender-Steuerung ; ; Created 25.1.2007 ; Version 0.0: Code-Import von 2mMiniTX.asm 0.2 ; Umgestellt auf Attiny12, Ext.Xtal, andere I/O s ; 29. 1.07 0.1: Register-Definitionen ; 30. 1.07 0.2: Interrupt-Handler codiert, Kennungsausgabe getestet ; 31. 1.07 0.3: Hauptprogramm codiert (ausser EEPROM access), ungetestet ; 1. 2.07 0.4: LED blinken + EEPROM Zugriff codiert, Basisablauf getestet ; 2. 2.07 0.5: Serielles I/F ok, Commands 0,1,7 ok, FoxPro kann zugreifen ; 8. 2.07 0.6: Commands 2,3 eingebaut, Defaultmodus, SerOut Fix, BrownOut an ; 10. 2.07 0.7: Sendedauer jetzt n x 10' ; 12. 2.07 0.8: Fix für 'Übergang Mode 1 > 2', Initialisierung STA ; 24. 2.07 0.9: OSCON während Sendedurchgangs dauernd an ; 2. 3.07 1.0: Kommentar für A1-Variante eingefügt ; 26. 3.07 1.1: Fixes für Assembler2 ; 30. 3.07 1.2: Neues Command 4 = Oscillator Calibration ; OscOn wird nach Reset 5 sec auf inaktiv gehalten ; 12. 6.07 1.3: Neu: Fuchs #6 = Spar-Rückholer mit langer Pause (für OE6GC) ; 19. 8.07 1.4: Fuchs #6: OscOn-Signal geht auf Low zwischen Sendephasen ; 6. 3.08 1.5: Modulationsfrequenz über MODFRQ zur Assembly-Zeit wählbar (für OE2WUL) ; 11. 3.08 1.6: Modulationsfrequenz und Tastgeschwindigkeit aus EEPROM (via FoxPro) ; 22. 3.08 1.7: Command 'Lade Fuchs ID' geändert (für FoxPro Cloning) ; 25. 3.08 1.8: Fuchsnummer 6 und 7 sind Spar-Rückholer mit 4/8 bzw 8/16 s Zyklus ; Langsame Tastung ist 40 BpM statt 30 BpM ; 28. 3.08 1.9: Software-Level wird bei 'Lese FoxID' in Byte 2 übertragen ; 26.10.08 2.0: Unterstützung für Abstimmtaster an -PAOn-Leitung ; 18.12.08 2.1: Fix für Oszillator Abgleich Modus Fehler in V2.0 ; .equ VERSHL =$21 ; Software-Level ; ;***** Specify Device .device ATtiny12 ; ; Fuses (für Quarzoszillator) sind wie folgt eingestellt: ; Brown-Out detection level at 2,7 V ; Brown-Out detection enabled ; SPI enabled ; CKSEL = 1010 'External Crystal/Ceramic Resonator' ; Fuse-Pattern 0x1A ; ;***** I/O Register Definitions .equ SREG =$3f .equ GIMSK =$3b .equ GIFR =$3a .equ TIMSK =$39 .equ TIFR =$38 .equ MCUCR =$35 .equ MCUSR =$34 .equ TCCR0 =$33 .equ TCNT0 =$32 .equ OSCCAL =$31 .equ WDTCR =$21 .equ EEAR =$1e .equ EEDR =$1d .equ EECR =$1c .equ PORTB =$18 .equ DDRB =$17 .equ PINB =$16 .equ ACSR =$08 .equ E2END =$3F ; Last EEPROM Location .equ FLASHEND=$1FF ; Last FLASH Location ; ;**** Register Useage (the ATtiny12 has no RAM) ; ; r0 reserved for Flash Access, also general work .DEF SRSAVE =r1 ; Status-Register Save während Interrupt ; .DEF SHIFT0 =r2 ; Serial I/F Shift Register First Byte, Bit7 shifted first .DEF SHIFT1 =r3 ; Second Byte .DEF SHIFT2 =r4 ; Third Byte .DEF SHIFT3 =r5 ; Fourth = Last Byte .DEF SHIFT4 =r6 ; Fifth Byte = Checkbyte ; .DEF DEL1 =r7 ; Used by Delay Routines .DEF DEL2 =r8 ; " .DEF DEL3 =r9 ; " ; .DEF PODEL =r10 ; Power-On Delay, zählt ab Reset 1*/s runter bis 0 ; Solange PODEL > 0 wird OscOn auf 0 gehalten .DEF MODCTR =r11 ; Modulationszähler, teilt 4,8 kHz in Modulationsfrequenz .DEF FOXID =r12 ; Fuchs-Nr./Modulation wie im EEPROM, Format 00MMSFFF ; Modulationsfrequenz MM: 00=1200Hz, 01=800Hz, 10=600Hz, 11=A1 (80m) ; Tastgeschwindigkeit S: 0=60Bpm, 1 = 40Bpm ; Fuchsnummer NNN: siehe unten STA0 ; .DEF WRK =r16 ; Work register for Main .DEF STA0 =r17 ; Status Byte 0 Bit 7,6,5: Nummer dieses Fuchs 1..5 (MOE..MO5) ; Fuchs 0 = Rückholer (MO) ; Fuchs 6 = dto, lange Pause, 4/6 s Zyklus ; Fuchs 7 = dto, lange Pause, 8/12 s Zyklus ; 4,3: Mode 0=Vorlauf,1=Operate,2=Fertig ; 2,1,0: Zahl der Füchse 1..5 .DEF STA1 =r18 ; Status Byte 1 Bit 7: Sendedauer 0=30s, 1=60s ; 6..0: Sendedauer 0..127 = 1..128 x 10' ; Im Mode Operate: dekrementiert nach je 10' .DEF STA2 =r19 ; Status Byte 2,3.. .DEF STA3 =r20 ; im Mode Vorlauf: Zeit bis Start in s (MSB,LSB) ; im Mode Operate: STA2/7..3: Timer 0..19 x 30s ; STA2/2..0: Aktueller Fuchs 1..5 ; STA3/7,6: Unused ; STA3/5..0: Aktuelle Sekunde 0..59 .DEF CWCTR =r21 ; CW-String-Bit-Zähler 0..127 .DEF DELTIM =r22 ; Delay Time (Main -> Delay Routinen) .DEF SERCNT =r23 ; Serial Interface Bit Counter <192 Receive, >=192 Send ; 0 = Warten auf Startbit, ab Vorflanke zählen mit 4800 Hz ; 6,10,14..162 Abtastzeitpunkte für die 40 Datenbits ; 166 zurücksetzen auf 0 ; 192 = Startbit senden ; 193..232 = Bit 0..39 senden ; 233 = fertig, zurück auf 0 .DEF TXTIMR =r24 ; TX-Timer für Command 2,3: Restsendezeit (*Key events), MSb=Com 3 .DEF SEMA =r25 ; Semaphores Main to Interrupt-Handler and Back ; Bit 0: 1=TX On, 0= TX Off ; Bit 1: Send Shift Register ; Bit 2: LED 1=On, 0 = Off ; Bit 3: Pausenblinken an (1x Mode 0, 2 * Mode 1) ; Bit 4: 1 sec Timing Event (für Fuchs-Ablauf) ; Bit 5: Key Timing Event (für CW Senden) ; Bit 6: Serial Receive complete .DEF IWRK =r26 ; Interrupt Work Register .DEF TIK4K8 =r27 ; Interrupt-Hdlr: Zählt alle 4,8 kHz bis 240 = 20 Hz .DEF TIKKEY =r28 ; Interrupt-Hdlr: Zählt alle 20 Hz bis 120/BpM (2 für 60 BpM) .DEF TIK20 =r29 ; Interrupt-Hdlr: Zählt alle 20 Hz bis 20 = 1 sec .DEF ZL =r30 ; Used for Flash access and as General Work .DEF ZH =r31 ; dto ; ;**** Serial Interface Data Format ; ; Datenformat für die serielle Übertragung: ; Pegel: Ruhezustand = High, Treiber OD, Pull-Up auf Empfangsseite ; Geschwindigkeit 1200 baud ; Format 1 Startbit, 40 Datenbits (4B Daten, 1B Checksum) ; Format Fuchs -> FoxPro: STA0, STA1, STA2, STA3, Checksum ; Checksum ist B0 x B1 x B2 x B3 x Pattern (x = Exor) ; Pattern ist $A5 -> Fuchs, $C3 -> Bediengerät ; Format Foxpro -> Fuchs: dto, ausser STA0/7..5 = Command ; Command = 0: Laden STA0..STA3, ausser STA0/7..5: Fuchs # aus EEPROM ; Command = 1: Lesen STA0..STA3 ; Command = 2: Senden für 0,5s ; Command = 3: Senden für 0,5s ohne Modulation ; Command = 4: Start Oszillator Abgleich Modus: ; Fosc/4 an Pin6/PB1 bis Reset ; Command = 5: Lese Fuchs ID, Format $FF, FoxID, SW-Version, $00 ; Command = 6: Lade Fuchs ID (auch ins EEPROM), Neue ID im Byte 1 ; Command = 7: Im Fuchs ignorieren, nur für Clonen benutzt ; Formate: Lade Uhrzeit $E0 hh mm ss ; Lade Aktueller Fuchs, Start-, Endezeit $Fa hh mh hm ; ;**** Code starts here ***************************************************** .CSEG .ORG 0 ; ; ;++++ Interrupt Vectors ; RJMP START ; 0 Reset RJMP START ; 1 External 0 RJMP START ; 2 Pin Change RJMP TIMER ; 3 Timer 0 Overflow RJMP START ; 4 EEPROM Ready RJMP START ; 7 Analog Comparator ; START: ;++++ 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 R16,$01 out DDRB,R16 ldi R16,$02 out PORTB,R16 ; ;++++ Intialize Timer/Counter 0 as 4800 Hz Timing Interrupt ; (4,9152 Mhz/64/16) ldi R16,$03 ; Set Clock Divider to 64 out TCCR0,R16 ldi R16,-16 ; Set Counter to 256-16 out TCNT0,R16 ldi R16,$02 out TIMSK,R16 ; Enable Counter 0 Overflow Interrupt ; ; ---- Initialize some Register-Variables -------------------------- ; ; Fuchs ID aus EEPROM holen clr ZL ; Adresse 0 in EEPROM out EEAR,ZL ldi ZL,$01 out EECR,ZL ; Set EEPROM Read Cmd STAR2: in ZL,EECR ; Wait for EEPROM Read complete andi ZL,$01 brne STAR2 in WRK,EEDR ; Fuchs ID lesen sbrc WRK,7 ; Wenn EEPROM leer = $FF ldi WRK,0 ; .. Fuchs ID auf Fuchs 0, 1200Hz, 60BpM setzen mov FOXID,WRK ; In FOXID speichern für Modulation andi WRK,$07 ; Auf 3 bit begrenzen ; ; Default-Status-Record: 5x60s, Aktueller Fuchs = dieser, Gesamt 3h mov STA2,WRK ; Aktueller Fuchs = dieser swap WRK ; Fuchsnummer 5 bits links schieben lsl WRK ldi STA0,$0D ; Mode Ein, 5 Füchse or STA0,WRK ; Diese Fuchs # dazu ldi STA1,$9D ; 60s/Fuchs, Gesamtsendezeit 5h ldi STA3,0 ; Sekunde = 0 ; clr CWCTR clr SERCNT clr SEMA clr TXTIMR clr TIK4K8 clr TIK20 clr TIKKEY clr MODCTR ldi WRK,5 ; OscOn nach Reset 5 sec auf inaktiv mov PODEL,WRK ; ; ---- Start Interrupt Handler ------------------------------------- ; sei ; Global Interrupt enable ; ;**** Main Loop **************************************************** ; MAIN: ; ; ++++ On Key Timing Event: Send MOe .. MO5 ; if Mode = Operate and current Fox = this Fox ; else Mode anzeigen durch blinken ; Wenn aber Tune-Taster gedrückt: OSCOn einschalten ; 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 gerdrückt sbi PORTB,0 ; .... Dann Oszillator einschalten rjmp MAIN2 ; .... und fertig mit Sendersteuerung ; M10: mov WRK,STA0 ; Wenn Fuchsnummer = 0,6,7 (Rückholer) andi WRK,$E0 breq MAIN10 ; .. auf jeden Fall senden andi WRK,$C0 cpi WRK,$C0 breq MAIN10 ; mov WRK,STA0 ; Sonst: Wenn Mode <> 1 andi WRK,$18 cpi WRK,$08 brne M11 mov ZH,STA2 ; oder Aktueller <> Dieser Fuchs andi ZH,$07 mov ZL,STA0 swap ZL ror ZL andi ZL,$07 cp ZH,ZL breq MAIN10 ; M11: ldi CWCTR,6 ; Counter vorbereiten für nächsten Durchgang cbr SEMA,$05 ; und TX-Semaphore auf aus tst TXTIMR ; Wenn nicht im Testmodus breq M115 rjmp MAIN19 M115: cbi PORTB,0 ; .. Oszillator ausschalten ; ; Sendet nicht: LED blinken lassen; Mode 0 = 1*/Sekunde, Mode 1 = 2*/s sbr SEMA,$08 M19: rjmp MAIN19 ; ; Status 1 und Aktueller = Dieser Fuchs oder Rückholer: CW-Kennung 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: 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,STA0 ; Sonderfall: Wenn Fuchs = 6,7 andi WRK,$C0 cpi WRK,$C0 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, LED Off sbrc ZL,7 sbr SEMA,$01 ; inc CWCTR ; Counter hochzählen mov WRK,STA0 ; Eigene Fuchsnummer aus Status holen swap WRK andi WRK,$0E ; Gibt 2 * Fuchsnummer 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 MAIN19 ; (bzw. bei Fuchs 6 CWCTR = wie oben) clr CWCTR ; .. Counter auf 0 setzen ; MAIN19: tst TXTIMR ; Wenn TX-Timer > 0 breq MAIN1A sbi PORTB,0 ; Oszillator einschalten dec TXTIMR ; .. dekrementieren cpi TXTIMR,$80 ; Wenn auf 0 bei Command 3 brne MAIN1A clr TXTIMR ; .. Mode-Flag auch noch löschen MAIN1A: ; ; +++ On 1 sec Event: Update Timers ; MAIN2: sbrs SEMA,4 ; Wenn 1 s Event rjmp MAIN29 cbr SEMA,$10 ; .. Semaphore löschen ; tst PODEL ; Wenn Power On Delay noch > 0 breq M2 dec PODEL ; .. runterzählen ; M2: mov WRK,STA0 ; Verzweigen, je nach Mode (0,1,2) andi WRK,$18 breq M20 cpi WRK,$08 breq M21 rjmp MAIN29 ; Bei Mode 2 (Fertig) ist nix mehr zu tun ; ; ++ 1 s Service Mode 0 = Vorlauf M20: tst STA3 ; Zeit runterzählen brne M201 dec STA2 M201: dec STA3 ; brne M209 ; Wenn Zähler auf 00:00 steht tst STA2 brne M209 ; ori STA0,$08 ; Status auf 1 weiterschalten ldi STA2,$01 ; STA2,3 auf Anfangsposition ldi STA3,$00 ; M209: rjmp MAIN29 ; Fertig mit Mode 0 ; ; ++ 1 s Service Mode 1 = Operate M21: inc STA3 ; Sekunden hochzählen mov WRK,STA3 ; .. und nach WRK kopieren andi WRK,$3F ; ldi ZL,60 ; Wenn Sekunden-Endwert erreicht sbrs STA1,7 ldi ZL,30 cp WRK,ZL brne M215 andi STA3,$C0 ; Sekunden auf 0 ; mov WRK,STA2 ; Aktueller Fuchs nach WRK/2..0 andi WRK,$07 mov ZL,STA0 ; N Füchse nach ZL andi ZL,$07 cp WRK,ZL ; Wenn Aktueller Fuchs < letzter Fuchs breq M212 inc STA2 ; .. Aktuellen Fuchs hochzählen rjmp M215 M212: andi STA2,$F8 ; .. sonst Aktueller Fuchs = letzter, Fuchs auf 1 ori STA2,$01 ; M215: ldi WRK,8 ; mov ZL,STA3 ; Falls Sekundenzähler andi ZL,$3F cpi ZL,00 ; .. auf 0 breq M217 cpi ZL,30 ; .. oder 30 brne M219 M217: add STA2,WRK ; .... n x 30s-Zähler inkrementieren mov WRK,STA2 ; Wenn n x 30s-Zähler andi WRK,$F8 cpi WRK,160 ; auf 20 (x 8) brne M219 andi STA2,$07 ; .. auf 0 setzen ; dec STA1 ; .. und Durchlaufzähler dekrementieren mov WRK,STA1 ; .. Wenn Zähler jetzt auf -1 andi WRK,$7F cpi WRK,$7F brne M219 cbr STA0,$08 ; .... Mode auf 2 weiterschalten sbr STA0,$10 ; M219: rjmp MAIN29 ; .... Fertig mit Mode 1 ; MAIN29: ; ; ; +++ 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 andi WRK,$E0 breq M30 ; Command 0 = Load cpi WRK,$20 breq M31 ; Command 1 = Read cpi WRK,$40 breq M32 ; Command 2 = Senden mit Mod (1/2 s) cpi WRK,$60 breq M33 ; Command 3 = Senden ohne Mod (1/2 s) cpi WRK,$80 breq M34 ; Command 4 = Oscillator Calibration cpi WRK,$A0 breq M35 ; Command 5 = Read Fox ID cpi WRK,$C0 breq M367 ; Command 6 = Set Fox ID rjmp MAIN39 ; Ignore command 7 ; M30: clr TIK20 ; Command 0: 20 Hz Timer auf Start neue Sekunde andi STA0,$E0 ; Fuchsnummer in STA0 erhalten or STA0,SHIFT0 ; Alles andere in Statusregistern ersetzen mov STA1,SHIFT1 mov STA2,SHIFT2 mov STA3,SHIFT3 rjmp MAIN39 ; Fertig ; M31: mov SHIFT0,STA0 ; Command 1: Status -> Shift kopieren mov SHIFT1,STA1 mov SHIFT2,STA2 mov SHIFT3,STA3 sbr SEMA,$02 ; und Sende Shift Register Semaphore setzen rjmp MAIN39 ; M32: ldi TXTIMR,$05 ; Command 2: ca 1/2 sec Senden mit Mod rjmp MAIN39 ; M33: ldi TXTIMR,$85 ; Command 3: ca 1/2 sec Senden ohne Mod rjmp MAIN39 ; M34: rjmp OSCOUT ; Command 4: Oszillator/4 -> PB1 ; M35: clr SHIFT0 ; Command 5: Fox-ID -> Shift kopieren dec SHIFT0 ; Format $FF, FOXID, SW-Version, $00 mov SHIFT1,FOXID ldi WRK,VERSHL mov SHIFT2,WRK clr SHIFT3 sbr SEMA,$02 ; und Sende Shift Register Semaphore setzen rjmp MAIN39 ; M367: mov WRK,SHIFT1 ; Command 6: Neue Fuchs ID mov FOXID,WRK ; ; Fuchs ID ins EEPROM schreiben clr ZL out EEAR,ZL ; EEPROM Adresse 0 out EEDR,WRK 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 M38: sbic EECR,1 ; Wait for Write complete rjmp M38 ; swap WRK ; Fuchs # in Registerposition bringen lsl WRK andi WRK,$E0 andi STA0,$1F ; und in STA0 einsetzen or STA0,WRK rjmp MAIN39 ; MAIN39: ; MAIN9: rjmp MAIN ; Repeat forever ; ;**** Oscillator Calibration Mode ; Output Fosc/4 on Pin6/PB1 until Reset OSCOUT: cli ; No more interrupts sbi DDRB,1 ; Switch PB1 to Output ldi R16,$00 ; Patterns to toggle PB1 ldi R17,$02 OSCOU1: out PORTB,R16 ; 1~ Toggle PB1.. out PORTB,R17 ; 1~ rjmp OSCOU1 ; 2~ .. forever ; ; ;**** Delay-Subroutines ************************************************ ; ; ++++ Delay x ms, x in R25 (x * 6 * 256 * 3 Cycle / 4,9 MHz) DELXMS: mov DEL1,DELTIM DXMS: CLR DEL2 D1MS: INC DEL2 ; 3 cycle inner loop BRNE D1MS ; " " " " D2MS: INC DEL2 ; 3 cycle inner loop BRNE D2MS ; " " " " D3MS: INC DEL2 ; 3 cycle inner loop BRNE D3MS ; " " " " D4MS: INC DEL2 ; 3 cycle inner loop BRNE D4MS ; " " " " D5MS: INC DEL2 ; 3 cycle inner loop BRNE D5MS ; " " " " D6MS: INC DEL2 ; 3 cycle inner loop BRNE D6MS ; " " " " DEC DEL1 BRNE DXMS RET ; ; ++++ Delay x secs, X in DELTIM DELXS: mov DEL3,DELTIM LDI DELTIM,250 ; 250 ms Basis Delay ; DXS: RCALL DELXMS RCALL DELXMS RCALL DELXMS RCALL DELXMS DEC DEL3 BRNE DXS ; RET ; ; *********************************** ; ******* 4800 Hz Timer Interrupt Handler ********************************** ; *********************************** ; TIMER: in SRSAVE,SREG ; Save Statusreg ; ldi IWRK,-16 ; Reset Counter 0 for next interrupt out TCNT0,IWRK ; ; ++ TX-Output Service ; tst TXTIMR ; IF TX-Testmode breq TIMA sbrs TXTIMR,7 ; .. with Modulation? rjmp TIM0 ; .... yes sbi DDRB,1 ; .... no, Dauerträger cbi PORTB,1 rjmp TIM1 ; TIMA: sbrc SEMA,0 rjmp TIM0 ; If TX Flag Off .. sbrs SEMA,3 ; .. and Pausenblinken an rjmp TIMA8 ; mov IWRK,STA0 ; Aktuellen Mode holen andi IWRK,$18 cpi TIK20,0 ; Zur Zeit 0/20 s brne TIMA2 cpi IWRK,$10 ; .. und wenn Mode <> 2 brne TIMA7 TIMA2: cpi TIK20,6 ; oder zur Zeit 6/20 s brne TIMA8 cpi IWRK,$08 ; .. und wenn Status = 1 brne TIMA8 TIMA7: sbi DDRB,1 ; .... LED On cbi PORTB,1 rjmp TIMA9 TIMA8: cbi DDRB,1 ; .... LED Off sbi PORTB,1 ; TIMA9: rjmp TIM1 ; TIM0: mov IWRK,FOXID ; Modulationsfrequenz aus FoxID separieren swap IWRK andi IWRK,$03 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: inc TIK4K8 ; Increment 4,8 kHz Timer cpi TIK4K8,240 ; .. up to 240 (20 Hz) brne TIM5 clr TIK4K8 ; ; ++ 20 Hz Service ; TIM2: inc TIK20 ; Increment 20 Hz Timer cpi TIK20,20 ; Wrap on 20 brne TIM3 clr TIK20 sbr SEMA,$10 ; .. and set 1s Timing Event Flag ; TIM3: inc TIKKEY ldi IWRK,2 ; CW-Geschwindigkeit Schnell = 60 BpM sbrc FOXID,3 ldi IWRK,3 ; .. bzw. langsam = 40 BpM (3 = 40 BpM, 4 = 30 BpM) cp TIKKEY,IWRK ; Wenn TIKKEY-Endwert brcs TIM5 clr TIKKEY ; .. Tikkey auf 0 sbr SEMA,$20 ; .. und Key Timing Event Flag setzen ; ; ++ Serial Interface Service ; + Receive + TIM5: mov IWRK,SERCNT ; Wenn Counter >= 192 andi IWRK,$C0 cpi IWRK,$C0 breq 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 ; .. und fertig ; TIM51: inc SERCNT ; Wenn Counter > 0 : inkrementieren sbrc SERCNT,0 ; Prüfen, ob Counter = n*4 + 2 rjmp TIM55 sbrs SERCNT,1 rjmp TIM55 cpi SERCNT,166 ; Bei Counterwert 166: Fertig brne TIM52 clr SERCNT ; .. Counter auf 0 ldi IWRK,$A5 ; Prüfbyte generieren eor IWRK,SHIFT0 eor IWRK,SHIFT1 eor IWRK,SHIFT2 eor IWRK,SHIFT3 cp IWRK,SHIFT4 ; .. und vergleichen brne TIM55 ; .. wenn ok sbr SEMA,$40 ; .... RX complete Semaphore setzen rjmp TIM55 ; TIM52: clc ; Bei Counterwert 2, 6, ..162 sbic PINB,2 ; .. ein Bit von Leitung nach Carry einlesen sec rol SHIFT4 ; 40 bit Shiftregister links schieben rol SHIFT3 rol SHIFT2 rol SHIFT1 rol SHIFT0 ; ; + Send + TIM55: mov 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,192 ; Counter auf Senden ldi IWRK,$C3 ; Prüfbyte generieren eor IWRK,SHIFT0 eor IWRK,SHIFT1 eor IWRK,SHIFT2 eor IWRK,SHIFT3 mov SHIFT4,IWRK rjmp TIM59 ; TIM56: mov IWRK,SERCNT ; Wenn Counter >= 192 andi IWRK,$C0 cpi IWRK,$C0 brne TIM59 inc SERCNT ; .. Counter hochzählen cpi SERCNT,233 ; Wenn Counter = +40 (=fertig) brne TIM57 cbi DDRB,2 ; .. Leitungstreiber aus clr SERCNT ; .. und Counter wieder auf 0 rjmp TIM59 ; TIM57: sbrs SHIFT0,7 ; Bit 7 von Shift0 senden sbi DDRB,2 sbrc SHIFT0,7 cbi DDRB,2 rol SHIFT4 ; .. und 40 bit Shiftregister links schieben rol SHIFT3 rol SHIFT2 rol SHIFT1 rol SHIFT0 ; TIM59: ; ++ Conclusion of Interrupt Service ; TIM99: cli ; No interrupts during conclusion out SREG,SRSAVE reti ; Interrupt-Handling beendet ; ;**************************** The End *****************************