; FJRX84.ASM ; ; *************************** ; * 80m Fuchsjagd Empfänger * ; *************************** ; ; Code für 80m Fuchsjagd-Empfänger-Steuerung ; ; Unterstützt den 80m-Fuchsjagdempfänger Version 4 (2* SA612) ; ; Autor: Nick Roethe, DF1FO, DF1FO at darc.de ; ; Dieser Codestand basiert auf der Version_2-80m-Fuchsjagd-Empfänger-Steuerung FJRX82 2.2 ; ; Versionsverlauf: ; 22. 7.08 0.0: Code-Import von FJRX82, umgestellt auf Assembler V.2 ; Für ATMega168 I/O-Register, Interrupts, Adressbereiche angepasst ; Assembliert ok, Grundfunktionen laufen noch ; Clean-Up bis zur Funktionalität der ATMega8-Version ; 23. 7.08 0.1: Beginn Umbau für Version_3-Hardware: ; PWM auf OC0A für Abschwächer, Provisorische Einstellung ; 25. 7.08 0.2: Abschwächermechanismus aus 2m-Empfänger: eichen, einstellen, anzeigen ; 26. 7.08 0.3: Timer_0-Interrupt auf 5 kHz erhöht, -> 256-Stufen PWM mit 5 kHz für Uregel ; Automatik-Abschwächer und Abschwächertaster-Handling aus FJRX2 ; Automatik unterdrücken, wenn V/R-Taster gedrückt ; Im Modus Peilen: <*> = +/- 100 Hz ; Entfernungsschätzung 3 Stufen weiter (8 -> 5) ; 27. 7.08 0.4: ACSM einschalten wenn V/R-Taster gedrückt ; 30. 7.08 0.5: S-Meter-Empfindlichkeit 6 dB höher (dafür 2. OpAmp 6 dB mehr Verstärkung) ; Abschwächerautomatik macht 10 dB Schritte bei S-Meter > 2* Vollausschlag ; 6. 9.08 0.6: PFox <= 3mW Abschwächertaster 1. Klick öffnet auf 10 dB statt 0 dB ; 22. 9.08 0.7: EEPROM-Anfangswerte aus Prototypen übernommen ; Mittelwert Frequenz-Feinverstimmung von 455 kHz auf 460 kHz verschoben ; Entfernungsschätzung zwei Stufen näher ; Entfernungsschätzung bis <1m statt <5m (für Foxoring) ; 3-Sprachen-Unterstützung Deutsch/English/Nederlands wie beim 2m-Peiler ; Abschwächerbereich von 110 dB auf 120 dB erweitert ; EEPROM-Layout geändert, daher neuer Valid Key ; Fix für 'nur dB'-Anzeige (ging bisher nicht) ; 30. 9.08 0.8: ACSM nur für V/R-Peilung, Schwellwert ist Max. der letzten 10*100ms vor V/R ; V/R-ACSM lässt sich im Einstellmenü abschalten ; Doppelklick im Modus Peilen schaltet Frequenz weiter ; 7.10.08 0.9: Batterie-A/D nur alle 300 ms für stabilere Anzeige ; 21.10.08 1.0: V/R-Taster-Knacken unterdrücken ; 11.11.08 1.1: ACSM V/R heisst jetzt V/R-Lupe ; 13.11.08 1.2: Entfernungsschätzung eine Stufe näher (Basis-Offset=6), entspricht damit FJRX82 ; 30.11.08 1.3: Fix für 'V/R-Lupe Aus wird nicht im EEPROM gespeichert' (tnx DJ1MHR) ; EEPROM-Layout geändert! Abgleichwerte nach Code-Update neu eingeben! ; 23.10.09 1.4: Fix für: bei 'Automatik Aus' wird kein '*' angezeigt (tnx DJ7JE) ; 15. 3.10 1.5: Zeitraster für Abschwächer, Töne etc von 100 auf 60 msesc verringert ; 10. 5.10 1.6: Entfernungsschätzung bis auf 9 km erweitert (keine dB-Anzeige mehr) ; 3. 2.11 1.7: Fix für 'Kein Automatik-Aus-Stern bei NFuchs=1 (Foxoring)' (Tnx DG3KPW) ; .equ VERSHI= '1' .equ VERSLO= '7' ; .equ VALKEY= $AA ; EEPROM Valid Key auf Adresse EEPCLR ; ; **** 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 unterste Auswahl ; - BOOTSZ unterste Auswahl (eigentlich egal) ; Richtiges Hex-Pattern X-H-L $F9-D4-FF ; Beim Auslesen kommt L-H-X $FF-D4-F9 zurück ; .listmac; Macro Expansion Listing On ; ;-------------------------------------------------------- ; ; **** I/O Register Definitions ; MEMORY MAPPED I/O REGISTER DEFINITIONS (&FF-$60) .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 ($3F-$00) .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 ; ; **** Constant-Register Definitions .def C0 =r8 ; Constant 0 .def C1 =r9 ; Constant 1 ; ; **** Index-Register Definitions .def XL =r26 .def XH =r27 .def YL =r28 .def YH =r29 .def ZL =r30 .def ZH =r31 ; ; **** Memory Sizes .equ RAMBEG = $100 ; First SRAM Location .equ RAMEND = $4FF .equ XRAMEND = $4FF .equ E2END = $1FF .equ FLASHEND = $1FFF ; ; **** S-Meter Scaling Factor .equ SMSCAL =$C0 ;S-Meter-Scaling-Factor (Higher = more sensitivity) ; ; **** Variablen *************************************************** .DSEG .ORG RAMBEG ; Start of RAM address range ($0100) ; VOID: .BYTE 16 ; Unused RAM Area (because of LCDSTR-Limitation) ; ++ Eingestellte Parameter, werden im EEPROM gerettet EEPCLR: .BYTE 1 ; $FF wenn EEPROM gelöscht, VALKEY wenn gültig, sonst ungültig/alt ; EEP0: ; Beginn des Frequenz-Bereichs FRQ1: .BYTE 2 ; Frequenz-Codewert 100 Hz-Schritte Frequenz 1 ; 0..3200 = 3,49..3,81, LSB,MSB FRQ2: .BYTE 2 ; Frequenz-Codewort Frequenz 2 FRQ3: .BYTE 2 ; Frequenz-Codewort Frequenz 3 FRQ4: .BYTE 2 ; Frequenz-Codewort Frequenz 4 FRQX: .BYTE 1 ; Aktive Frequenz 1..4 ; EEP1: ; Grenze zwischen Frequenz- und HW-SetUp-Bereich NFOX: .BYTE 2 ; Zahl der Füchse Z,E 1..10 TFOXS: .BYTE 2 ; Fuchs-Laufzeit Sekunden Z,E 1..99 TFOXMS: .BYTE 2 ; Fuchs-Laufzeit Milli-Sekunden H,Z 0..98 in 2er Schritten PFOXBN: .BYTE 1 ; Sendeleistung Coded 0=1µW, 1=3µW..15=30W, 16=Nur dB Anzeige NFREQ: .BYTE 1 ; Zahl der Frequ. 1..4 TALARM: .BYTE 2 ; EOT Alarm Vorlaufzeit 0..31 sec, 0 = Aus Z,E ACSMON: .BYTE 1 ; Akustisches S-Meter bei V/R 1=Ein SPARE: .BYTE 2 ; Reserve für Ergänzungen ; EEP2: ; Grenze zwischen HW-SetUp und Abgleich-Bereich ABSTAB: .BYTE 13 ; Tabelle Level-Werte 0,10,20..120 dB FFINE: .BYTE 1 ; Frequenz Fein 128 -/+ 99 = -9,9..+9,9 kHz UBFINE: .BYTE 1 ; Skalierungswert für Ub-Messung 0..255 UBWBIN: .BYTE 1 ; Schwelle Batteriewarnung in 1/10 V (60..80) DISTCF: .BYTE 1 ; Anpassung Entfernungsschätzung 0..10 (Anz. -5..+5) FRQBER: .BYTE 1 ; Frequenzbereich 0 = 3,49-3,66, 1 = 3,49-3,81 SPRACH: .BYTE 1 ; Sprachwahl 1=Deu, 2=Eng, 3=Ned EEPEND: ; Ende der geretteten Einstellungen ; ; ++ Zustands-Variablen MODE: .BYTE 1 ; Mode (Beschreibung siehe Texte ganz unten) ; 0 = RX aus, 2 = Frequenzeingabe, 3 = Peilen ; 4..x = Hauptmenü ; $10..$1x = Untermenü Einstellungen ; $20..$2x = Untermenü Abgleich FRQBIN: .BYTE 2 ; Aktuelle Frequenz ; 0..3200 = 3490.0 .. 3810.0, LSB,MSB FRQ: .BYTE 4 ; Frequenz-Dezimalstellen 1M,100k,10k,1k FRQXSY: .BYTE 1 ; Symbol für Frequenz 1..4 (1..4 Punkte) STOPW: .BYTE 5 ; Stopuhr Eh,Zm,Em,Zs,Es STOPWR: .BYTE 1 ; 1 = Stopuhr läuft, 0 = steht TIMER: .BYTE 4 ; Count Down Timer Zs,Es,Hms,Zms zählt in 20 ms Schritten FOX: .BYTE 2 ; Current Fox Z,E 1..16 ABSBIN: .BYTE 1 ; Abschwächer Binaer-Wert 0..24 für 0, 5, 10..120 dB ABSCHW: .BYTE 3 ; Abschwächer Anzeige 0..120 dB in 5 dB Stufen H,Z,E ABSVAL: .BYTE 3 ; Abschwächer Analogwert 0..255 H,Z,E DIST: .BYTE 4 ; Distanz-Anzeige H,Z,E FFIVAL: .BYTE 3 ; FFINE Anzeigewert -/+0..99 VZ,Z,E UBFVAL: .BYTE 3 ; UBat Korrektur UBFINE Anzeigewert 0..255 H,Z,E DCFVAL: .BYTE 2 ; Distanz Korrekturfaktor Anzeigewert VZ,E PFOX: .BYTE 4 ; Sendeleistung Watt Anzeigewert Z,E,h,z KLKLK: .BYTE 1 ; Doppel Klick Erkennung, nach 1. Klick für 800 ms > 0 AAWAIT: .BYTE 1 ; Wartezeit nach 5dB-Auto-Abschwächung oder V/R (n * 100 ms) VRWAIT: .BYTE 1 ; V/R-Taster Wartezeit, > 0 = ist/war gedrückt (n * 100 ms) VRPREV: .BYTE 1 ; V/R-Taster vorheriger Status, 1 = gedrückt FLATIM: .BYTE 1 ; Verbleibende Flashtime für Text-Flash (n * 100 ms) FLASTR: .BYTE 2 ; Pointer auf aktuellen Flash String H,L SOUPNT: .BYTE 2 ; Pointer auf Soundstring LSB,MSB; Fertig bei MSB = 0 UBWARN: .BYTE 2 ; Batteriewarnungsschwelle V/mV E,h AUTOON: .BYTE 1 ; Abschwächer-Automatik ein = ' ', aus = '*' ACSMTH: .BYTE 1 ; Akustisches S-Meter > Schwelle = 1, < = 0 ; ++ Analog-Werte UBATT: .BYTE 3 ; Batterie-Spannung in V/mV Z,E,h UMESSA: .BYTE 1 ; Messspannung für akustisches S-Meter UMESSP: .BYTE 4 ; Spitzenwertspeicher Umess für S-Meter, Ältester Wert in *+3 UMESSR: .BYTE 10 ; Spitzenwertspeicher Umess als Referenz für ASM bei V/R UMREF: .BYTE 1 ; Spitzenwert aus UMESSR, begrenzt auf 64..127 UMESS: .BYTE 8 ; Messspannung Bargraph 8 Stellen ;++ Display-Ansteuerung LCDDAT: .BYTE 16 ; Data to be displayed in LCD ; ++ 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=Schnell-Taster Kurz, 6=Schnell-Taster Lang TICK: .BYTE 1 ; 60 ms Timing Flag TACK: .BYTE 1 ; 1 s Timing Flag ALATIM: .BYTE 1 ; EOT Alarm Flag, 1 = Alarm auslösen BATTIM: .BYTE 1 ; Batterie-Prüf-Zeit-Timer, 1 = prüfen, 0 = fertig VRMUTE: .BYTE 1 ; V/R-Taster-Knacken Mute-Timer FSOLLH: .BYTE 1 ; Sollfrequenz High Byte (Soll ist $2HHLL) FSOLLL: .BYTE 1 ; Sollfrequenz Low Byte FISTH: .BYTE 1 ; Istfrequenz High Byte (Ist ist $2HHLL) FISTL: .BYTE 1 ; Istfrequenz Low Byte ; ++ Interrupt-Handler DEBP1: .BYTE 1 ; Debounce Counter Drehgeber DEBDD: .BYTE 1 ; Debounce Drücker Drehgeber DEBST: .BYTE 1 ; Debounce Schnell-Taster TIK5K: .BYTE 1 ; Zaehlt jede 200 us bis 5 (1 msec) TIK1M: .BYTE 1 ; Zaehlt jede 1 ms bis 20 (20 msec) TIK20M: .BYTE 1 ; Zaehlt jede 20 msec bis 50 (1 sec) TIK60: .BYTE 1 ; Zaehlt jede 20msec bis 3 (60 ms) TIK300: .BYTE 1 ; Zaehlt jede 60ms bis 5 (300 ms, für Batterie-A/D-Wandlung) TIK1S: .BYTE 1 ; Zaehlt jede 1 s bis 60 (1 min) TIK150: .BYTE 1 ; Zaehlt jede 1 msec bis 50 (für TUNE) TUNLEN: .BYTE 1 ; Abstimmpulslänge in ms (für TUNE) ; ; ********************** ; **** Macro Definitionen ****************************************** ; ********************** ; ; ++++ Store to SRAM Location @0 Immediate Value @1 ; USES R21 ! 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 R21,@1 sts @0,R21 .ENDIF .ENDMACRO ; ; ++++ Show Text String @0 .MACRO SHOW ldi ZL,low(2*@0) ; Ausgabe-Kommand-String ldi ZH,high(2*@0) call LCDSTR ; .. ausführen call OUTLCD ; .. und Ergebnis anzeigen .ENDMACRO ; ; ++++ Flash Text String @0 for @1*60ms .MACRO FLASH ldi ZL,low(2*@0) ; Ausgabe-Kommand-String ldi ZH,high(2*@0) sts FLASTR,ZH sts FLASTR+1,ZL call LCDSTR ; .. ausführen call OUTLCD ; .. und Ergebnis anzeigen ldi ZL,@1 ; Flash Timer aufsetzen sts FLATIM,ZL ; .ENDMACRO ; ; ++++ Start F-String @0 .MACRO SOUND ldi ZL,low(2*@0) ; Sound-String sts SOUPNT,ZL ldi ZH,high(2*@0) sts SOUPNT+1,ZH .ENDMACRO ; ; ++++ Increment 2 Digit BCD within Boundaries .MACRO I2BCD push R16 push XL push XH ldi XL,LOW(@0) ; Pointer auf BCD-String ldi XH,1 rcall BCD2B ; Wandelt 2B BCD @ X,X+1 nach Bin in R16 ldi XL,@1 ; Lower Limit ldi XH,@2 ; Upper Limit rcall INCLIM ; Increment R16 within limits in XH,XL ldi XL,LOW(@0) ; Pointer auf BCD-String ldi XH,1 rcall B2BCD ; Wandelt Bin in R16 in 2B BCD @ X, X+1 pop XH pop XL pop R16 .ENDMACRO ; ; ++++ Decrement 2 Digit BCD within Boundaries .MACRO D2BCD push R16 push XL push XH ldi XL,LOW(@0) ; Pointer auf BCD-String ldi XH,1 rcall BCD2B ; Wandelt 2B BCD @ X,X+1 nach Bin in R16 ldi XL,@1 ; Lower Limit ldi XH,@2 ; Upper Limit rcall DECLIM ; Decrement R16 within limits in XH,XL ldi XL,LOW(@0) ; Pointer auf BCD-String ldi XH,1 rcall B2BCD ; Wandelt Bin in R16 in 2B BCD @ X, X+1 pop XH pop XL pop 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 ; ; ++++ Initialisiere Steuer-Parameter ; Called if EEPROM is empty or by menu item 'EEPROM Reset' EEPNEW: stsi FRQ1,$20 ; Frequenz 1 3,570 stsi FRQ1+1,$03 stsi FRQ2,$A4 ; Frequenz 2 3,660 stsi FRQ2+1,$06 stsi FRQ3,$00 ; Frequenz 3 3,490 stsi FRQ3+1,$00 stsi FRQ4,$84 ; Frequenz 4 3,580 stsi FRQ4+1,$03 stsi FRQX,1 ; Frequenz 1 aktiv stsi NFOX,0 ; Zahl Füchse = 5 stsi NFOX+1,5 stsi TFOXS,6 ; Zeit Füchse = 60 sec stsi TFOXS+1,0 stsi TFOXMS,0 stsi TFOXMS+1,0 stsi PFOXBN,12 ; Sendeleistung 1 Watt stsi NFREQ,3 ; 3 Frequenzen stsi TALARM,1 ; Alarmzeit 10s stsi TALARM+1,0 stsi ABSTAB+0,0 ; Leveltabelle laden stsi ABSTAB+1,52 stsi ABSTAB+2,82 ; 0..120 dB in 10 dB Schritten stsi ABSTAB+3,95 stsi ABSTAB+4,105 stsi ABSTAB+5,114 stsi ABSTAB+6,125 stsi ABSTAB+7,135 stsi ABSTAB+8,148 stsi ABSTAB+9,162 stsi ABSTAB+10,177 stsi ABSTAB+11,191 stsi ABSTAB+12,205 stsi FFINE,128+30 ; Feinverstimmung + 30 * 100 Hz (für 455kHz Filter) stsi UBFINE,119 ; Batterieanzeigekorrektur Mittelwert stsi UBWBIN,70 ; Batteriewarnschwelle 7 Volt stsi DISTCF,5+0 ; Entfernungsanzeige-Korrektur, Mittelwert (+0) stsi FRQBER,0 ; Frequenzbereich 3,49 - 3,66 stsi SPRACH,1 ; Sprache Deutsch stsi ACSMON,1 ; Akustisches S-Meter bei V/R Ein ; ret ; ; ***************************** ; **** 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) STA01: st X+,C0 cpi XL,LOW(RAMEND+1) brne STA01 cpi XH,HIGH(RAMEND+1) brne STA01 ; ; ++++ Initialize Port B Bit 0 as Input P0 with Pull-Up ; 1 as Input P1 with Pull-Up ; 2 as Output Uabst in HZ ; 3 as Output Sound in HZ ; 4 as Input Dreh-Drücker with Pull-Up ; 5 as Input Abschwächertaster with Pull-Up ; PB3..PB5 also SPI-I/F ldi R16,$00 out DDRB,R16 ldi R16,$33 out PORTB,R16 ; ; ++++ Initialize Port C Bit 0..2 as Analog In URicht, Uv/r, Ub ; 3 as Input (Unused) ; 4 as Output Mute in HZ ; 5 as Display E Output ldi R16,$20 out DDRC,R16 ldi R16,$00 out PORTC,R16 ; ; ++++ Initialize Port D Bit 0..4 as Output for Display ; 5 as Counter Input Timer 1 ; 6 as Output PWM Attenuator ; 7 as Input w P-Up for Menu-Switch ldi R16,$5F out DDRD,R16 ldi R16,$80 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 = 125 kHz STS ADCSRA,R16 ; = 250 usec Conversion Time ; ; ++++ Intialize Timer/Counter 0 as 200 us Interrupt (10,24MHz/8/256) ldi R16,$02 ; Set Clock Divider to 8 out TCCR0B,R16 ldi R16,$83 ; Set Comparator A as PWM for Attenuator out TCCR0A,R16 ldi R16,255 ; Start value for PWM out OCR0A,R16 ldi R16,$01 sts TIMSK0,R16 ; Enable Counter 0 Overflow Interrupt ; ; ++++ Intialize Timer/Counter 1 as Frequency Counter ldi R16,$00 ; Count Rising Edges on T1 Input sts TCCR1A,R16 ldi R16,$07 sts TCCR1B,R16 ; ; ++++ Intialize Timer/Counter 2 as Frequency Generator for Sounds stsi TCCR2A,$42 ; Clock Divider 128, CTC, Toggle on Compare stsi TCCR2B,$05 ; ; ; ++++ Get Steuer-Parameter from EEPROM ; Wenn EEPROM ungültig: initialisieren call GETEEP ; Parameter aus EEPROM holen ; lds R16,EEPCLR ; Hat EEPROM gültigen Inhalt? cpi R16,VALKEY breq STA03 ; .. sonst Parameter initialisieren rcall EEPNEW ; .. aber nicht ins EEPROM kopieren! ; ; ++++ Initialize some Variables STA03: stsi STOPWR,1 ; Stopuhr läuft nach Power-On an stsi BATTIM,150 ; Erste Batteriespannungsprüfung nach 10s stsi AUTOON,' ' ; Abschwächer-Automatik Ein ; sbic PINB,4 ; Wenn Drücker gedrückt rjmp STA031 ; stsi MODE,$20 ; .. dann Abgleichmode ; STA031: rcall GETFRQ ; Aktuelle Frequenz laden rcall CONVF ; Frequenz Dezimal ausrechnen rcall CONVPF ; Leistung Dezimal ausrechnen rcall CONVBW ; Batterie-Warnung Dezimal ausrechnen ; ; ++++ Start Interrupt Handler rcall CLRTIM ; Fuchstimer auf Startwert sei ; Global Interrupt enable ; ; ++++ Initialize LCD and show Start Text call INILCD flash STRPO,10 ldi R25,100 ; Wait 100 ms call DELXMS stsi SWIFLG,0 ; Clear any Drehgeber Flags lds R16,EEPCLR ; Wenn EEPROM Valid cpi R16,VALKEY brne STA04 sound SOUPO ; Power-On-Fanfare rjmp STA09 STA04: sound SOUHI ; Sonst 'Hi' ; STA09: rjmp MAIN6 ; Start Main Loop with A/D of UBat ; ; ************* ; **** Main Loop *************************************************** ; ************* ; MAIN: ; ++++ Mode Updaten MAIN2: lds R16,MODE ; Mode holen ; sbis PIND,7 ; Wenn Schalter nicht auf Menü (=Peilen) rjmp M21 ldi R16,3 ; .... dann Mode 3 rjmp M29 ; M21: sbic PIND,7 ; Wenn Schalter auf Menü rjmp M29 mov R18,R16 andi R18,$FC ; und Mode < 4 brne M29 cpi R16,2 ; aber nicht 2 breq M29 ldi R16,7 ; .. dann Mode = 7 flash STRMEN,30 ; Start Menu Message ; M29: sts MODE,R16 ; Mode speichern ; ; ++++ Je nach Mode: Drehdrücker + Taster handeln MAIN3: lds R16,MODE ; Mode holen cli lds R17,SWIFLG ; Switch Flags holen clr R18 ; .. und löschen sts SWIFLG,R18 sei tst R17 ; Wenn irgendein Flag gesetzt breq MAIN30 clr R18 ; .. dann laufende Flashes abbrechen sts FLATIM,R18 ; ; ++++ Abschwächertaster behandeln ; MAIN30: sbrs R17,6 ; Lang drücken rjmp M300 lds R18,AUTOON ; Abschwächer-Automatik toggeln ldi R19,$0A ; .. ' ' <> '*' eor R18,R19 sts AUTOON,R18 cpi R18,' ' ; Passenden Quittungston + Text erzeugen breq M30X sound SOUAA0 flash STRAA0,10 rjmp M309 M30X: sound SOUAA1 flash STRAA1,10 rjmp M309 ; M300: sbrs R17,5 ; Kurz drücken rjmp M309 lds R16,ABSBIN ; = Abschwächer öffnen ; lds R18,PFOXBN ; Wenn PFOX <= 7 (3 mW) cpi R18,7 brcc M3002 cpi R16,3 ; Wenn >10 dB brcs M3001 stsi ABSBIN,2 ; .. dann Abschwächer auf 10dB rjmp M303 M3001: stsi ABSBIN,0 ; .. sonst auf 0 dB rjmp M303 ; Wenn PFox > 3 mW: M3002: cpi R16,11 ; Wenn < 300m @ 1W brcs M301 stsi ABSBIN,10 ; .. dann auf 300m rjmp M303 M301: cpi R16,6 ; Wenn 1,5km..300m @ 1W brcs M302 stsi ABSBIN,5 ; .. dann auf 2km rjmp M303 M302: stsi ABSBIN,0 ; .. sonst auf 0 dB ; M303: push R17 rcall CONVAB ; Neuen Abschwächerwert einstellen pop R17 M309: andi R17,$9F ; Flag Bits 5, 6 löschen ; ; Bei Mode 0 (RX Off) sonst nix tun, nur Flags löschen ; lds R16,MODE cpi R16,3 ; Bei Mode 3 brne M3020 ; M3011: sbrs R17,4 ; Wenn Klick Flag gesetzt.. rjmp M3012 ; andi R17,$10 lds R18,KLKLK ; Ist dies der 2te Klick in 300 ms? tst R18 breq M30111 rcall UDFRQ ; .. dann Frequenz weiterschalten clr R18 ; .. und Klicktimer löschen rjmp M30112 M30111: ldi R18,8 ; .. Sonst Klicktimer auf 800 ms setzen M30112: sts KLKLK,R18 ; M3012: lds R18,ABSBIN ; Drehen ohne Drücken: Abschwächer stellen sbrc R17,0 ; Up Flag inc R18 ; sbrc R17,1 ; Down Flag dec R18 ; cpi R18,-1 ; Limit to 0..24 brne M3013 ldi R18,0 M3013: cpi R18,25 brne M3014 ldi R18,24 M3014: sts ABSBIN,R18 ; sbrs R17,0 ; Wenn Up Flag rjmp M3015 rcall UMR50P ; .. ACSM-Referenzwert-Buffer halbieren stsi AAWAIT,3 ; .. und Abschwächerautomatik kurz unterdrücken ; M3015: andi R17,$0C ; Drehen mit Drücken: +/- 100 Hz abstimmen breq M3019 rcall UDFRQ flash STR02,10 ; M3019: rjmp M399 ; fertig ; M3020: cpi R16,2 ; Bei Mode 2 brne M3021 rcall UDFRQ ; Frequenz ändern rjmp M399 ; fertig ; M3021: mov R18,R16 ; Bei Mode > = 4 andi R18,$FC brne M331 rjmp M399 ; M331: sbrc R17,0 ; Wenn Up Flag inc R16 ; .. Mode erhöhen sbrc R17,1 ; Wenn Down Flag dec R16 ; .. Mode verringern cpi R16,8 ; Mode Range auf 4..7, $10..$16 ,$20..$28 brne M332 ; beschränken ldi R16,4 M332: cpi R16,3 brne M333 ldi R16,7 M333: cpi R16,$17 brne M334 ldi R16,$10 M334: cpi R16,$0F brne M335 ldi R16,$16 M335: cpi R16,$29 brne M336 ldi R16,$20 M336: cpi R16,$1F brne M337 ldi R16,$28 M337: sts MODE,R16 ; Mode speichern ; M34: cpi R16,4 ; Wenn Mode = 4 brne M35 sbrs R17,4 ; .. und Drückerpuls rjmp M35 lds R18,STOPWR ; .. und Stopuhr steht tst R18 brne M342 rcall CLRSTW ; .... dann Stopuhr löschen und starten rjmp M35 M342: clr R18 ; sts STOPWR,R18 ; .... sonst Stopuhr anhalten rjmp M399 ; M35: cpi R16,5 ; Wenn Mode = 5 brne M36 rcall UDCTMR ; .. dann Timer löschen/ändern rjmp M399 ; M36: cpi R16,6 ; Wenn Mode = 6 (Einstellungen?) brne M37 sbrs R17,4 ; .. und Drehdrücker Click rjmp M37 ldi R16,$13 ; .. dann neuer Mode 13 sts MODE,R16 rjmp M399 ; M37: cpi R16,7 ; Wenn Mode = 7 (Frequ. ändern?) brne M310 sbrs R17,4 ; .. und Drehdrücker Click rjmp M310 ldi R16,$02 ; .. dann neuer Mode 2 (Vary Frq.) sts MODE,R16 rjmp M399 ; M310: cpi R16,$10 ; Wenn Mode = 10 brne M311 rcall UDNF ; .. dann N Füchse verändern rjmp M399 ; M311: cpi R16,$11 ; Wenn Mode = 11 brne M312 rcall UDTFS ; .. dann T Fuchs Sekunden verändern rjmp M399 ; M312: cpi R16,$12 ; Wenn Mode = 12 brne M313 rcall UDTFMS ; .. dann T Fuchs ms verändern rjmp M399 ; M313: cpi R16,$13 ; Wenn Mode = 13 brne M314 rcall UDPF ; .. dann Leistung Fuchs verändern rjmp M399 ; M314: cpi R16,$14 ; Wenn Mode = 14 brne M315 rcall UDNFRQ ; .. dann Zahl Frequenzen verändern rjmp M399 ; M315: cpi R16,$15 ; Wenn Mode = 15 brne M316 rcall UDTA ; .. dann EOT Alarmzeit verändern rjmp M399 ; M316: cpi R16,$16 ; Wenn Mode = 16 brne M320 sbrs R17,4 ; .. und Drehdrücker Click rjmp M320 lds R18,ACSMON ; .... dann Akustisches SM V/R Ein/Aus com R18 andi R18,$01 sts ACSMON,R18 rjmp M399 ; M320: cpi R16,$20 ; Wenn Mode = 20 brne M321 rcall UDSPRA ; .. Sprache einstellen rjmp M399 ; M321: cpi R16,$21 ; Wenn Mode = 21 brne M322 sbrs R17,4 ; .. und Drehdrücker Click rjmp M322 rcall EEPNEW ; .... dann EEPROM initialisieren sound SOUOK ; .... und Quittungston rjmp M399 ; M322: cpi R16,$22 ; Wenn Mode = 22 brne M323 rcall CALUB ; .. dann U Bat kalibrieren rjmp M399 ; M323: cpi R16,$23 ; Wenn Mode = 23 brne M324 rcall CALFFI ; .. dann Frequenz kalibrieren rjmp M399 ; M324: cpi R16,$24 ; Wenn Mode = 24 brne M325 sbrc R17,4 ; .. und Drehdrücker Click rcall CALABS ; .. dann Abschwächer-Levels eichen rjmp M399 ; M325: cpi R16,$25 ; Wenn Mode = 25 brne M326 rcall UDUBW ; .. Batterie-Warnungs-Pegel einstellen rjmp M399 ; M326: cpi R16,$26 ; Wenn Mode = 26 brne M327 rcall CALDIS ; .. dann Distanz kalibrieren rjmp M399 ; M327: cpi R16,$27 ; Wenn Mode = 27 brne M328 sbrs R17,4 ; .. und Drehdrücker Click rjmp M399 lds R18,FRQBER ; .. Frequenzbereich toggeln ldi R19,1 eor R18,R19 and R18,R19 sts FRQBER,R18 rjmp M399 ; M328: cpi R16,$28 ; Wenn Mode = 28 brne M399 sbrs R17,4 ; .. und Drehdrücker Click rjmp M399 stsi EEPCLR,VALKEY ; .... EEPROM valid key setzen rcall SAVCAL ; .... Abgleich-Parameter in EEPROM retten flash STRSAV,10 ; .... Anzeige Save to EEPROM sound SOUOK ; .... und Quittungston rjmp M399 ; ; M399: ; rcall ADUM ; Messspannung A/D-Wandeln und behandeln ; ; Gedrückten V/R-Taster erkennen und Timer setzen MAIN4: ldi R16,1 ; Analogkanal 1 = V/R-Taster Flag wandeln ldi R19,$10 rcall ANACON andi R16,$F8 ; Wenn Ergebnis > 7 (600 mV): Taster gedrückt breq MAIN40 stsi VRWAIT,3 ; Dann Automatik 300 ms unterdrücken ; MAIN40: lds R17,VRPREV ; Hat sich Schalterzustand gegen letzten Pass geändert? tst R16 ; Aktuellen Zustand auf 0/1 normieren breq MAIN41 ldi R16,1 MAIN41: sts VRPREV,R16 ; .. und alles neuen alten speichern cp R16,R17 ; Wenn neu <> alt breq MAIN49 stsi VRMUTE,100 ; .. Mute Timer auf 100 ms setzen MAIN49: ; ; ; ++++ Alles weitere nur alle 60 ms: ++++++++++++++++++++++++++++++++++ MAIN5: lds R16,TICK ; 60 ms Flag testen tst R16 brne MAIN51 rjmp MAIN MAIN51: clr R16 sts TICK,R16 ; ; V/R-Taster Timer dekrementieren auf 0 lds R16,VRWAIT tst R16 breq MAIN55 dec R16 MAIN55: sts VRWAIT,R16 ; ; Doppel Klick Timer dekrementieren auf 0 lds R16,KLKLK tst R16 breq MAIN56 dec R16 MAIN56: sts KLKLK,R16 ; ; ; ++++ Wenn Empfänger übersteuert und Automatik Ein ; und Abschwächertaster nicht gedrückt: ; Wenn S-Meter am Anschlag: Abschwächer 10 dB höher, sonst 5 dB höher ; Tatü (je 60 ms 2 kHz und 3 kHz) ; MAINA: lds R16,AAWAIT ; Wartezeit, weil gerade erst abgeschwächt? tst R16 ; Wenn Wert > 1.. breq MAINAC dec R16 sts AAWAIT,R16 ; .. nur Wartezähler dekrementieren breq MAINAC ; Bei altem oder neuem Wert 0 Automatik handeln MAINAB: rjmp MAINB ; MAINAC: lds R16,AUTOON ; Automatik eingeschaltet? cpi R16,' ' brne MAINAB ; .. sonst nix tun ; MAINA0: lds R16,VRWAIT ; V/R-Taster aktiv (oder gerade gewesen)? tst R16 brne MAINAB ; .. dann Abschwächer-Automatik unterdrücken ; MAINA1: lds R17,UMESSP ; Messpannung > Schwelle? cpi R17,128 ; 128 ist S-Meter Vollausschlag brcc MAINA2 rjmp MAINB ; sonst fertig ; MAINA2: lds R16,ABSBIN ; .. ja: Abschwächer hochschalten cpi R16,24 ; .. ausser wenn schon am Anschlag breq MAINB inc R16 sts ABSBIN,R16 rcall UMR50P ; .. ASM-Referenz-Buffer halbieren cpi R17,$FF ; .. falls Messpannung > 2 * Schwelle (Anschlag) brne MAINA4 cpi R16,24 breq MAINA4 inc R16 ; .... um insgesamt 2 Stufen hochschalten sts ABSBIN,R16 rcall UMR50P ; .... ASM-Referenz-Buffer noch mal halbieren MAINA4: rcall CONVAB ; .. neuen Abschwächerwert einstellen stsi AAWAIT,2 ; .. Wartezeit vor nächster Abschwächung (200 ms) lds R16,FLATIM ; .. Wenn Textanzeige nicht aktive tst R16 brne MAINB lds R16,SOUPNT+1 ; .... dann wenn Soundgenerator nicht busy tst R16 brne MAINA3 sound SOUABS ; ...... Zweiton erzeugen rjmp MAINB MAINA3: sound SOUAB2 ; ...... Sonst Folge-Zweiton erzeugen ; ; ACSM Referenzwert ermitteln MAINB: lds R16,VRWAIT ; Wenn V/R nicht gedrückt tst R16 brne MAINB0 lds R16,AAWAIT ; und Abschwächer hat nicht gerade erst runtergeschaltet tst R16 brne MAINB0 rcall UMRNXT ; Referenzwert Buffer weiterschieben, Spitzenwert ermitteln ; ; ++++ Alarm-Tonfolge erzeugen, wenn Flag gesetzt und Mode = 3 ; und mehr als 1 Fuchs MAINB0: lds R17,ALATIM ; Flag holen clr R18 sts ALATIM,R18 ; und löschen tst R17 ; Flag > 0? breq MAINB1 lds R17,MODE ; und Mode = 3 cpi R17,3 brne MAINB1 lds R18,NFOX+1 ; und > 1 Fuchs.. cpi R18,1 breq MAINB1 sound SOUALA ; .. dann Tonsignal flash STRALA,8 ; .. und Meldung zeigen ; ; ++++ Batterie checken ; Interrupthandler setzt Timer BATTIM bei Sendestart F1 auf 150 ; Timer wird hier alle 60 ms dekrementiert ; Bei erreichen von 0 (nach 10 s) wird Batteriespannung gepruft MAINB1: lds R17,BATTIM ; Timer BATTIM holen cpi R17,0 ; Wenn = 0 breq MAINB6 ; ..nix tun dec R17 ; Wenn > 0: dekrementieren sts BATTIM,R17 ; ..und ablegen brne MAINB6 ; Wenn jetzt = 0: Batterie prüfen ; lds R16,UBATT ; Batteriespannung 10V-Stelle holen tst R16 ; Wenn > 0: Bat ok brne MAINB6 ; lds R16,UBATT+1 ; Sonst 1V-Stelle holen lds R17,UBWARN cp R16,R17 breq MAINB3 ; Wenn = Alarmschwelle: nächste Stelle brcs MAINB5 ; Wenn < Alarmschwelle: Alarm rjmp MAINB6 ; Wenn > Alarmschwelle: Bat ok ; MAINB3: lds R16,UBATT+2 ; Wenn 1V-Stelle gleich lds R17,UBWARN+1 ; .. 100mV-Stelle holen cp R16,R17 ; Wenn > Alarmschwelle: Bat ok brcc MAINB6 ; MAINB5: flash STRBAT,50 ; Sonst Alarm-Text und -Sound sound SOUBAT MAINB6: ; ; ++++ Batteriespannung A/D-konvertieren und skalieren MAIN6: lds R16,TIK300 ; Nur alle 300 ms ausführen tst R16 ; Wenn 300 ms Timer > 0 nichts tun brne MAIN61 ldi R16,2 ; Analog-Channel 2 = UBATT lds R19,UBFINE ; Scaling Factor, ist $2xxd swap R19 ; mit xx = UBFINE und d = dont care andi R19,$0F ori R19,$20 lds R18,UBFINE ; Scaling Factor, Low swap R18 rcall ANACON ldi XH,1 ; Pointer auf Anzeige-Fenster ldi XL,LOW(UBATT) rcall B3BCD ; Ergebnis in BCD wandeln und ablegen ; ; ++++ Entfernungsanzeige und S-Meter-Balken erzeugen ; MAIN61: rcall CONVAB ; Abschwächer-Einstellung in Entfernung umrechnen ; rcall CONVUM ; Messspannung in Bargraph-Anzeige wandeln ; ; ++++ Je nach Mode Display laden lds R17,FLATIM ; Flash-Timer > 0 tst R17 breq MAIN7 dec R17 ; .. dann dekrementieren sts FLATIM,R17 lds ZH,FLASTR ; .. Flash-String auffrischen lds ZL,FLASTR+1 rcall LCDSTR rcall OUTLCD ; .. und Ergebnis anzeigen rjmp MAIN8 ; MAIN7: lds R16,MODE cpi R16,0 brne M72 lds R18,NFOX+1 ; Mode RX Aus: Wenn nur 1 Fuchs.. cpi R18,1 breq M701 show STR000 rjmp M72 M701: show STR001 ; .. Stopuhr statt Timer zeigen M72: cpi R16,2 brne M73 show STR02 M73: cpi R16,3 brne M74 lds R18,NFOX+1 ; Mode Peilen: Wenn nur 1 Fuchs.. cpi R18,1 breq M731 show STR030 rjmp M74 M731: show STR031 ; .. Stopuhr statt Timer zeigen M74: cpi R16,4 brne M75 lds R18,STOPWR tst R18 breq M741 show STR040 rjmp M75 M741: show STR041 M75: cpi R16,5 brne M76 show STR05 M76: cpi R16,6 brne M77 show STR06 M77: cpi R16,7 brne M710 show STR07 M710: cpi R16,$10 brne M711 show STR10 M711: cpi R16,$11 brne M712 show STR11 M712: cpi R16,$12 brne M713 show STR12 M713: cpi R16,$13 brne M714 lds R18,PFOXBN ; Wenn PFOXBN = 16 cpi R18,16 brne M7131 show STR130 ; .. Entfernungsanzeige aus rjmp M714 M7131: show STR13 M714: cpi R16,$14 brne M715 show STR14 M715: cpi R16,$15 brne M716 lds R18,TALARM ; Wenn TALARM = 00 tst R18 brne M7151 lds R18,TALARM+1 tst R18 brne M7151 show STR150 ; .. Alarm Aus rjmp M716 M7151: show STR15 ; .. sonst Alarmzeit zeigen M716: cpi R16,$16 brne M720 lds R18,ACSMON ; Wenn ACSM bei V/R ein tst R18 breq M7160 show STR161 ; .. Anzeige 'Ein' rjmp M720 M7160: show STR160 ; .. sonst Anzeige 'Aus' M720: cpi R16,$20 brne M721 show STR20 M721: cpi R16,$21 brne M722 show STR21 M722: cpi R16,$22 brne M723 show STR22 M723: cpi R16,$23 brne M724 show STR23 M724: cpi R16,$24 brne M725 show STR24 M725: cpi R16,$25 brne M726 show STR25 M726: cpi R16,$26 brne M727 show STR26 M727: cpi R16,$27 brne M728 lds R18,FRQBER tst R18 brne M7271 show STR270 rjmp M728 M7271: show STR271 M728: cpi R16,$28 brne M799 show STR28 M799: ; ++++ Sollfrequenz für Regelung bereitstellen MAIN8: rcall SETFRQ ; ++++ Soundgenerator ausführen rcall SOUGEN ; ; ++++ Zur vollen Sekunde: geänderte Parameter ins EEPROM MAIN9: lds R16,TACK ; Wenn volle Sekunde cpi R16,0 breq MAIN99 stsi TACK,0 ; .. Flag löschen rcall SAVCHG ; .. und geänderte Parameter retten ; MAIN99: rjmp MAIN ; ; *************** ; **** Subroutines ************************************************* ; *************** ; ; ################################# ; #### Variablen ändern und anzeigen ############################### ; ################################# ; ; **** Stopuhr löschen und starten CLRSTW: push R16 ldi R16,0 sts STOPWR,R16 ; Run-Flag löschen sts STOPW,R16 ; Zeit auf 0 setzen sts STOPW+1,R16 sts STOPW+2,R16 sts STOPW+3,R16 sts STOPW+4,R16 ldi R16,1 ; und Run-Flag setzen sts STOPWR,R16 pop R16 ret ; ; **** Timer löschen bei Klick, +/- bei Drück + Dreh UDCTMR: sbrc R17,4 ; Wenn Drückerpuls rcall CLRTIM ; .... dann Timer löschen und starten ; UDCT2: andi R17,$0C ; Switch-Flag Up Oder Down gesetzt? breq UDCT9 ; .. dann derzeitige Fuchs# ändern ; push R16 ldi XL,LOW(NFOX) ; Pointer auf NFox-BCD-String ldi XH,1 rcall BCD2B ; Wandelt 2B BCD @ X,X+1 nach Bin in R16 mov R18,R16 ldi XL,LOW(FOX) ; Pointer auf Fox-BCD-String ldi XH,1 cli ; Interrupt aus rcall BCD2B ; Wandelt 2B BCD @ X,X+1 nach Bin in R16 ldi XL,1 ; Lower Limit mov XH,R18 ; Upper Limit sbrs R17,3 ; Up-Flag, dann Fox-Nummer erhoehen rcall INCLIM ; Increment R16 within limits in XH,XL sbrs R17,2 ; Down-Flag rcall DECLIM ; Decrement R16 within limits in XH,XL ldi XL,LOW(FOX) ; Pointer auf BCD-String ldi XH,1 rcall B2BCD ; Wandelt Bin in R16 in 2B BCD @ X, X+1 sei ; Interrupts wieder zulassen pop R16 ; UDCT9: ret ; ; **** Fuchs Timer auf Start-Wert setzen CLRTIM: push R16 cli ; Interrupt unterdrücken lds R16,TFOXS ; Zeit von TFOX nach TIMER kopieren sts TIMER,R16 lds R16,TFOXS+1 sts TIMER+1,R16 lds R16,TFOXS+2 sts TIMER+2,R16 lds R16,TFOXS+3 sts TIMER+3,R16 sei ; Interrupt wieder an stsi FOX,0 ; Fuchszähler auf 1 stsi FOX+1,1 pop R16 ret ; ; **** Zahl der Füchse (1..10) verändern UDNF: sbrs R17,2 ; Up Flag rjmp NF2 i2bcd NFOX,1,10 rjmp NF8 NF2: sbrs R17,3 ; Down Flag rjmp NF9 d2bcd NFOX,1,10 NF8: rcall CLRTIM ; Nach Änderung: Fuchstimer neu starten NF9: ret ; ; **** Zahl der Frequenzen (1..4) verändern UDNFRQ: lds R16,NFREQ dec R16 ; 1..4 -> 0..3 sbrs R17,2 ; Up Flag rjmp NFRQ2 inc R16 rjmp NFRQ8 NFRQ2: sbrs R17,3 ; Down Flag rjmp NFRQ9 dec R16 NFRQ8: andi R16,$03 ; Limit to 0..3 inc R16 sts NFREQ,R16 stsi FRQX,1 ; Nach Änderung: Frequenz 1 aktivieren rcall GETFRQ ; Neue Frequenz holen rcall CONVF ; .. und in Anzeigewert umrechnen NFRQ9: ret ; ; **** EOT Alarm-Zeit (0..30) verändern UDTA: push R16 TA1: sbrs R17,2 ; Up Flag rjmp TA2 i2bcd TALARM,0,30 rjmp TA8 TA2: sbrs R17,3 ; Down Flag rjmp TA8 d2bcd TALARM,0,30 TA8: pop R16 ret ; ; **** Laufzeit Fuchs Sekunden(1..99) verändern UDTFS: sbrs R17,2 ; Up Flag rjmp TFS2 i2bcd TFOXS,1,99 rjmp TFS8 TFS2: sbrs R17,3 ; Down Flag rjmp TFS9 d2bcd TFOXS,1,99 TFS8: rcall CLRTIM ; Nach Änderung: Fuchstimer neu starten TFS9: ret ; ; **** Laufzeit Fuchs ms (0,2..98) verändern UDTFMS: sbrs R17,2 ; Up Flag rjmp TFM2 i2bcd TFOXMS,0,99 i2bcd TFOXMS,0,99 brcs TFM1 rjmp TFM8 TFM1: i2bcd TFOXS,1,99 rjmp TFM8 TFM2: sbrs R17,3 ; Down Flag rjmp TFM9 d2bcd TFOXMS,0,99 brcc TFM3 d2bcd TFOXS,1,99 TFM3: d2bcd TFOXMS,0,99 TFM8: rcall CLRTIM ; Nach Änderung: Fuchstimer neu starten TFM9: ret ; ; **** Leistung der Füchse verändern UDPF: lds R16,PFOXBN sbrs R17,2 ; Up Flag rjmp UDPFA inc R16 rjmp UDPFB UDPFA: sbrs R17,3 ; Down Flag rjmp UDPF9 dec R16 UDPFB: cpi R16,17 ; Limit to 0..16 brne UDPFC ldi R16,16 UDPFC: cpi R16,-1 brne UDPFD ldi R16,0 UDPFD: sts PFOXBN,R16 rcall CONVPF ; Convert Code to Textform UDPF9: ret ; ; **** Sprache auswählen UDSPRA: lds R16,SPRACH ; Get current language sbrc R17,2 ; Up Flag inc R16 sbrc R17,3 ; Down Flag dec R16 UDSP1: cpi R16,0 ; Limit to 1..3 brne UDSP2 ldi R16,3 UDSP2: cpi R16,4 brne UDSP3 ldi R16,1 UDSP3: sts SPRACH,R16 ; Geänderte Sprache speichern UDSP9: ret ; ; **** Textstring für Fuchsleistung in PFOX stellen CONVPF: push R16 clr R16 ; Erst mal alles auf 0 sts PFOX,R16 sts PFOX+1,R16 sts PFOX+2,R16 stsi PFOX+3,'m' ; lds R16,PFOXBN ; Binaer Code für Leistung CPF0: cpi R16,0 brne CPF1 stsi PFOX+1,1 stsi PFOX+3,$E4 ; 'µ' CPF1: cpi R16,1 brne CPF2 stsi PFOX+1,3 stsi PFOX+3,$E4 ; 'µ' CPF2: cpi R16,2 brne CPF3 stsi PFOX+0,1 stsi PFOX+3,$E4 ; 'µ' CPF3: cpi R16,3 brne CPF4 stsi PFOX+0,3 stsi PFOX+3,$E4 ; 'µ' CPF4: cpi R16,4 brne CPF5 stsi PFOX+2,1 CPF5: cpi R16,5 brne CPF6 stsi PFOX+2,3 CPF6: cpi R16,6 brne CPF7 stsi PFOX+1,1 CPF7: cpi R16,7 brne CPF8 stsi PFOX+1,3 CPF8: cpi R16,8 brne CPF9 stsi PFOX+0,1 CPF9: cpi R16,9 brne CPF10 stsi PFOX+0,3 CPF10: cpi R16,10 brne CPF11 stsi PFOX+2,1 stsi PFOX+3,' ' CPF11: cpi R16,11 brne CPF12 stsi PFOX+2,3 stsi PFOX+3,' ' CPF12: cpi R16,12 brne CPF13 stsi PFOX+1,1 stsi PFOX+3,' ' CPF13: cpi R16,13 brne CPF14 stsi PFOX+1,3 stsi PFOX+3,' ' CPF14: cpi R16,14 brne CPF15 stsi PFOX+0,1 stsi PFOX+3,' ' CPF15: cpi R16,15 brne CPF99 stsi PFOX+0,3 stsi PFOX+3,' ' CPF99: pop R16 ret ; ; **** Frequenz erhöhen/erniedrigen je nach Flags in R17 (=SWIFLG) UDFRQ: sbrs R17,4 ; Bit 4 = Druckpuls gesetzt? rjmp UDFRQ0 rcall NEXTF ; .. dann Frequenz weiterschalten rjmp UDFRQ9 ; .. und fertig UDFRQ0: andi R17,$0F ; Bit 0, 1, 2 or 3 set? brne UDFRQ1 rjmp UDFRQ9 ; UDFRQ1: lds R24,FRQBIN ; Low Byte of Frequency Code lds R25,FRQBIN+1 ; sbrc R17,0 ; +/- 1 kHz adiw R24,10 sbrc R17,1 sbiw R24,10 sbrc R17,2 ; +/- 100 Hz adiw R24,1 sbrc R17,3 sbiw R24,1 ; UDFRQ2: tst R25 ; Wenn Ergebnis negativ brpl UDFRQ3 clr R24 ; .. auf 0 setzen clr R25 ; UDFRQ3: lds R18,FRQBER ; Wenn Frequenzbereich bis 3,66 MHz tst R18 brne UDFRQ4 cpi R25,$06 ; und wenn Ergebnis > 1700 = $06A4 brne UDFRQ8 cpi R24,$A4 brcs UDFRQ8 ldi R24,$A4 ; .. auf 1700 setzen rjmp UDFRQ8 ; ; ; Wenn Frequenzbereich bis 3,81 MHz UDFRQ4: cpi R25,$0C ; und wenn Ergebnis > 3200 = $0C80 brne UDFRQ8 cpi R24,$80 brcs UDFRQ8 ldi R24,$80 ; .. auf 3200 setzen ; UDFRQ8: sts FRQBIN,R24 ; Ergebnis abspeichern als Binärwert sts FRQBIN+1,R25 rcall PUTFRQ ; .. und nach FRQ1..4 kopieren ; rcall CONVF ; Dezimale Frequenzanzeige bereitstellen ; UDFRQ9: ret ; ; ; Switch to next Frequency NEXTF: push R17 rcall PUTFRQ ; Put current frequency FRQBIN -> FRQ1..4 ; lds R16,FRQX ; Frequenz-Nummer weiterschalten lds R17,NFREQ ; .. und bei > Maximum nach 1 wrappen cp R16,R17 brne NEXTF1 ldi R16,1 rjmp NEXTF2 NEXTF1: inc R16 NEXTF2: sts FRQX,R16 ; rcall GETFRQ ; Get new Frequency FRQ 1..4 -> FRQBIN rcall CONVF ; Dezimale Frequenzanzeige bereitstellen flash STRFRQ,20 ; Neue Frequenz String flashen ; lds R16,FRQX ; Zu neuem Kanal gehörende Tonfolge ausgeben cpi R16,1 brne NEXTF4 sound SOUF1 ; Neue Frequenz 1 Tonfolge NEXTF4: cpi R16,2 brne NEXTF5 sound SOUF2 ; Neue Frequenz 2 Tonfolge NEXTF5: cpi R16,3 brne NEXTF6 sound SOUF3 ; Neue Frequenz 3 Tonfolge NEXTF6: cpi R16,4 brne NEXTF7 sound SOUF4 ; Neue Frequenz 4 Tonfolge NEXTF7: pop R17 ret ; ; ; Switch to previous Frequency PREVF: push R17 rcall PUTFRQ ; Put current frequency FRQBIN -> FRQ1..4 ; lds R16,FRQX ; Frequenz-Nummer weiterschalten dec R16 brne PREVF1 lds R16,NFREQ ; .. und bei 1 nach Maximum wrappen PREVF1: rjmp NEXTF2 ; Weiter wie bei NEXTF ; ; Put current frequency FRQBIN -> FRQ1..4 PUTFRQ: lds R16,FRQX ; Pointer auf aktive Frequenz bauen dec R16 ldi YL,LOW(FRQ1) ldi YH,1 add YL,R16 add YL,R16 ; lds R16,FRQBIN ; Und 2 Byte kopieren st Y+,R16 lds R16,FRQBIN+1 st Y,R16 ; ret ; Get current frequency FRQBIN <- FRQ1..4 GETFRQ: lds R16,FRQX cpi R16,1 ; Frequenzsymbol erzeugen brne GETF2 ldi R17,'.' GETF2: cpi R16,2 brne GETF3 ldi R17,':' GETF3: cpi R16,3 brne GETF4 ldi R17,$86 GETF4: cpi R16,4 brne GETF5 ldi R17,$87 GETF5: sts FRQXSY,R17 ; lds R16,FRQX ; Pointer auf aktive Frequenz bauen dec R16 ldi YL,LOW(FRQ1) ldi YH,1 add YL,R16 add YL,R16 ; ld R16,Y+ sts FRQBIN,R16 ; Und 2 Byte kopieren ld R16,Y sts FRQBIN+1,R16 ; ret ; ; ; **** Dezimale Frequenzanzeige vorbereiten 2B FRQBIN -> 4B FRQ **** CONVF: lds R24,FRQBIN ; Binäres Frequenzcodewort holen LSB lds R25,FRQBIN+1 ; dto MSB ; Codewort ist im Bereich 0 .. 1700 ldi R16,4 ; 100 kHz Startwert ldi R17,9 ; 10 kHz ldi R18,0 ; 1 kHz ldi R19,0 ; 100 Hz adiw R24,1 ; Codewort inkrementieren ; ; Anzeige = Startwert 3490,0 + Codewort * 100 Hz CONVF4: sbiw R24,1 ; Codewort dekrementieren breq CONVF5 ; Wenn noch nicht 0 inc R19 ; .. Anzeige dezimal inkrementieren cpi R19,10 brne CONVF4 clr R19 inc R18 cpi R18,10 brne CONVF4 clr R18 inc R17 cpi R17,10 brne CONVF4 clr R17 inc R16 rjmp CONVF4 ; CONVF5: sts FRQ,R16 sts FRQ+1,R17 sts FRQ+2,R18 sts FRQ+3,R19 ; ret ; ; **** Zähler-Sollwert ausrechnen und übergeben ****************** SETFRQ: push R16 push R17 push R24 push R25 ; ldi R16,$DC ; Hex von 34900 - 4600 - 128, LSB ldi R17,$75 ; dto MSB ; lds R24,FFINE ; Frequenzabgleichwert 128 +/- 99 dazu clr R25 add R16,R24 adc R17,R25 ; lds R24,FRQBIN ; Frequenz-Codewort dazu (100 Hz Schritte) lds R25,FRQBIN+1 add R16,R24 adc R17,R25 ; mov R24,R16 ; * 5 wg. 20 Hz Counter-Auflösung mov R25,R17 clc rol R24 rol R25 clc rol R24 rol R25 add R16,R24 adc R17,R25 ; sts FSOLLL,R16 ; Als Sollwert ablegen sts FSOLLH,R17 ; pop R25 pop R24 pop R17 pop R16 ret ; ; ; **** UB-Anzeige eichen, dazu UBFINE 0.255 einstellen ; CALUB: push R16 push R17 lds R16,UBFINE ; Aktuellen Wert holen andi R17,$0C ; Wenn kein Flag gesetzt breq CALUB3 ; .. Änderungsteil überspringen ; sbrc R17,2 ; Increment? inc R16 sbrc R17,3 ; Decrement? dec R16 ; sts UBFINE,R16 ; Aktuellen Wert speichern ; CALUB3: ldi XL,LOW(UBFVAL) ; Aktuellen Wert ... ldi XH,1 rcall B3BCD ; .. in 3 BCD in UBFVAL wandeln ; pop R17 pop R16 ret ; ; **** Frequenznachstimmung eichen ; Bereich ist +/- 9,9kHz, Abgelegt in FFINE als 128 +/-..99 CALFFI: push R16 push R17 lds R16,FFINE ; Aktuellen Wert holen andi R17,$0C ; Wenn kein Flag gesetzt breq CALFF3 ; .. Änderungsteil überspringen ; sbrc R17,2 ; Increment? inc R16 sbrc R17,3 ; Decrement? dec R16 cpi R16,228 ; Oberes Limit +99 ? brne CALFF1 ldi R16,227 CALFF1: cpi R16,28 ; Unteres Limit -99 ? brne CALFF2 ldi R16,29 ; CALFF2: sts FFINE,R16 ; Aktuellen Wert speichern ; CALFF3: ldi R17,128 ; Anzeigewert ist FFINE - 128 sub R16,R17 ; .. = -99 .. +99 ldi R17,'+' ; Vorzeichen bestimmen sbrc R16,7 ldi R17,'-' sts FFIVAL,R17 ; .. und ablegen sbrc R16,7 ; Wenn Wert negativ neg R16 ; .. komplementieren ldi XL,LOW(FFIVAL+1) ; ldi XH,1 rcall B2BCD ; .. in 2 BCD in FFIVAL+1,2 wandeln ; CALFF9: pop R17 pop R16 ret ; ; **** Abschwächer eichen ; CALABS: push R16 push R17 cbi DDRB,3 ; Sicherheitshalber: Sound ausschalten cbi DDRC,4 ; .. und Mute ausschalten ldi YL,low(ABSTAB) ; Tabelle mit Abschwächerwerten ldi YH,high(ABSTAB) ; stsi ABSBIN,0 ; Abschwächer auf 0 dB setzen ; CALAB1: sbic PIND,7 ; Wenn Kippschalter nicht mehr auf Menü (FRQ) rjmp CALAB9 ; .. abbrechen ld R16,Y ; Aktuellen Wert holen lds R17,SWIFLG ; Switch Flags holen clr R18 ; .. und löschen sts SWIFLG,R18 sbrc R17,0 ; Increment? inc R16 sbrc R17,1 ; Decrement? dec R16 CALA12: st Y,R16 ; Aktuellen Wert speichern ; sbrs R17,4 ; Click? rjmp CALAB2 lds R16,ABSBIN ; Nächste 10 dB-Abschwächereinstellung inc R16 inc R16 cpi R16,26 ; bis maximal 24 breq CALAB9 sts ABSBIN,R16 ld R16,Y+ ; Tabellenpointer inkrementieren rjmp CALAB1 ; CALAB2: rcall CONVAB ; Abschwächer einstellen ld R16,Y ; Aktuellen Analogwert ldi XL,low(ABSVAL) ; ldi XH,1 rcall B3BCD ; .. in 3 BCD in ABSVAL wandeln rcall ADUM ; S-Meter-Wert D/A-Wandeln rcall CONVUM ; S-Meter updaten show STRCAL ; Display updaten rjmp CALAB1 ; CALAB9: pop R17 pop R16 ret ; ; **** Entfernungsschätzung eichen ; Bereich Korrekturfaktor ist 0..9 CALDIS: push R16 push R17 lds R16,DISTCF ; Aktuellen Wert holen sbrc R17,2 ; Increment? inc R16 sbrc R17,3 ; Decrement? dec R16 cpi R16,11 ; Oberes Limit 10 ? brne CALDI1 ldi R16,10 CALDI1: cpi R16,-1 ; Unteres Limit 0 ? brne CALDI2 ldi R16,0 ; CALDI2: sts DISTCF,R16 ; Aktuellen Wert speichern ; ldi R17,5 ; 0..10 in -5..+5 umwandeln sub R16,R17 ldi R17,'+' ; Für Anzeige: Vorzeichen bestimmen sbrc R16,7 ldi R17,'-' sts DCFVAL,R17 ; .. und ablegen sbrc R16,7 ; Wenn Wert negativ neg R16 ; .. komplementieren sts DCFVAL+1,R16 ; ; CALDI9: pop R17 pop R16 ret ; ; ; **** Increment R16 within limits in XL,XH INCLIM: cp R16,XH ; Am oberen limit? breq INCL1 inc R16 ; Nein: inkrementieren clc ; und Carry Flag loeschen rjmp INCL9 INCL1: mov R16,XL ; Ja: auf unteres Limit setzen sec ; Carry Flag setzen INCL9: ret ; ; **** Decrement R16 within limits in XL,XH DECLIM: cp R16,XL ; Am unteren limit? breq DECL1 dec R16 ; Nein: dekrementieren clc ; Und Carry Flag löschen rjmp DECL9 DECL1: mov R16,XH ; Ja: auf oberes Limit setzen sec ; Und Carry Flag setzen DECL9: ret ; ; **** Convert 2B BCD @ X, X+1 nach Bin in R16 BCD2B: push R17 ld R16,X+ ; Get Zehnerstelle lsl R16 ; Multiply by 10 mov R17,R16 lsl R16 lsl R16 add R16,R17 ld R17,X ; Get Einerstelle add R16,R17 ; And add to result dec XL pop R17 ret ; ; **** Convert Bin in R16 to 2B BCD @ X, X+1 B2BCD: push R16 push R17 push R18 in R17,SREG ; Save Statusreg mit Carry Flag push R17 ; clr R17 ; Einerstelle clr R18 ; Zehnerstelle B2B1: tst R16 ; Bis Bin-Wert auf Null ist breq B2B9 dec R16 ; Binwert dekrementieren inc R17 ; und BCD-Wert inkrementieren cpi R17,10 brne B2B1 clr R17 inc R18 rjmp B2B1 B2B9: st X+,R18 ; Ergebnis ablegen st X,R17 dec XL ; pop R17 out SREG,R17 ; Carry-Flag wiederherstellen pop R18 pop R17 pop R16 ret ; ; **** Convert Bin in R16 to 3B BCD @ X, X+1, X+2 B3BCD: push R16 push R17 push R18 push R19 in R17,SREG ; Save Statusreg mit Carry Flag push R17 ; clr R17 ; Einerstelle clr R18 ; Zehnerstelle clr R19 ; Hunderterstelle B3B1: tst R16 ; Bis Bin-Wert auf Null ist breq B3B9 dec R16 ; Binwert dekrementieren inc R17 ; und BCD-Wert inkrementieren cpi R17,10 brne B3B1 clr R17 inc R18 cpi R18,10 brne B3B1 clr R18 inc R19 rjmp B3B1 B3B9: st X+,R19 ; Ergebnis ablegen st X+,R18 st X,R17 subi XL,2 ; pop R17 out SREG,R17 ; Carry-Flag wiederherstellen pop R19 pop R18 pop R17 pop R16 ret ; ; **** Batterie-Warnungs-Level verändern (von 5,8..8,0 V) UDUBW: lds R16,UBWBIN sbrs R17,2 ; Up Flag rjmp UDUBA inc R16 rjmp UDUBB UDUBA: sbrs R17,3 ; Down Flag rjmp UDUB9 dec R16 UDUBB: cpi R16,81 ; Limit to 58..80 brne UDUBC ldi R16,80 UDUBC: cpi R16,57 brne UDUBD ldi R16,58 UDUBD: sts UBWBIN,R16 rcall CONVBW ; Convert Code to Textform UDUB9: ret ; ; **** Batterie-Warnungs-Level Bin nach Dez wandeln CONVBW: lds R16,UBWBIN ; Binärwert holen clr R17 ; Volt-Stelle clr R18 ; Zehntel-Volt-Stelle ; CVBW1: tst R16 ; Loopen bis Binärwert auf 0 gezählt breq CVBW9 dec R16 ; Binärwert dekrementieren inc R18 ; Dezimalwert inkrementieren cpi R18,10 ; Übertrag handeln brne CVBW1 clr R18 inc R17 rjmp CVBW1 ; CVBW9: sts UBWARN,R17 ; Dezimalwert ablegen sts UBWARN+1,R18 ret ; ############################################ ; #### Analog-In, Entfernungs- und Pegelanzeige ######################### ; ############################################ ; ; **** Einen Analogwert Kanal R16 einlesen und in R16 übergeben ; Scaling Factor in R19,R18 ; 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 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 ; Mp16uH:mp16uL and mc16uH:mc16uL. ; The result is placed in m16u3:m16u2:mp16uH:mp16uL. ; ; Number of words :14 + return ; Number of cycles :153 + return ; Low registers used :None ; High registers used :7 R16..R22 ; ;++ Subroutine Register Variables ; .def mc16uL =r16 ;multiplicand low byte .def mc16uH =r17 ;multiplicand high byte .def mp16uL =r18 ;multiplier low byte / result byte 0 (LSB) .def mp16uH =r19 ;multiplier high byte / result byte 1 .def m16u2 =r20 ;result byte 2 .def m16u3 =r21 ;result byte 3 (MSB) .def mcnt16u =r22 ;loop counter ; ;++ Code ; MPY16u: clr m16u3 ;clear 2 highest bytes of result clr m16u2 ldi mcnt16u,16 ;init loop counter lsr mp16uH ror mp16uL ; m16u_1: brcc noad8 ;if bit 0 of multiplier set add m16u2,mc16uL ;add multiplicand Low to byte 2 of res adc m16u3,mc16uH ;add multiplicand high to byte 3 of res noad8: ror m16u3 ;shift right result byte 3 ror m16u2 ;rotate right result byte 2 ror mp16uH ;rotate result byte 1 and multiplier High ror mp16uL ;rotate result byte 0 and multiplier Low dec mcnt16u ;decrement loop counter brne m16u_1 ;if not done, loop more ret ; ; ; **** Messpannung A/D-wandeln und Maximum speichern ; ADUM: ldi R16,0 ; Analog-Channel 0 = UMESS ldi R19,SMSCAL ; Scaling Factor für S-Meter Empfindlichkeit clr R18 ; .. dto., Low Byte rcall ANACON ; A/D-Wandeln, Ergebnis-Bereich 0..255 sbrc R16,7 ; Ergebnis verdoppeln ldi R16,$FF ; .. begrenzen auf 255 sec rol R16 sts UMESSA,R16 ; Momentanwert speichern für akustische Ausgabe lds R17,UMESSP ; Spitzenwert für Balken-S-Meter bilden cp R16,R17 brcs ADUM8 sts UMESSP,R16 ; ADUM8: rcall ACSM ; S-Meter akustisch ausgeben ret ; ; **** Akustisches S-Meter erzeugen ; Eingangswert ist UMESSA 0..255, Bar-S-Meter ab 127 am Anschlag ; Ton wird nur ausgegeben, wenn der V/R-Taster gedrückt ist ; und das S-Meter mehr als den Referenzwert (Spitzenwert der letzten 10*60ms) zeigt ; ACSM: lds R16,UMESSA ; Messpannung holen lds R17,UMREF ; .. und um Referenzwert verringern sub R16,R17 cpi R16,50 ; Wenn > 50 brcs ACSM0 ldi R16,50 ; auf 50 begrenzen ; ACSM0: ldi R17,66 ; Untere Eckfrequenz ist 66 = 1kHz sub R17,R16 ; Obere Eckfrequenz ist 16 = 4kHz ; ACSM7: lds R19,SOUPNT+1 ; Ist Sound Pointer <> 0 (Sound aktiv)? tst R19 brne ACSM9 ; .. dann nichts ausgeben ; ACSM71: lds R16,TCNT2 ; Wait until Counter <16 andi R16,$F0 ; .. to avoid noise by counter tst R16 ; .. counting to max (< 5ms @ 200 Hz) brne ACSM71 ; sts OCR2A,R17 ; Variablen Oscillator laden ; lds R16,ACSMTH ; ACSM-Schwellwertschalter handeln lds R17,UMESSA ; Wenn Messpannung < Referenzwert lsr R17 lds R18,UMREF lsr R18 sub R17,R18 sbrc R17,7 clr R16 ; .. Schwellwertschalter aus ldi R18,3 sub R17,R18 ; Wenn Messpannung > Referenzwert + 6 sbrs R17,7 ldi R16,1 ; .. Schwellwertschalter ein sts ACSMTH,R16 ; Abspeichern ; lds R16,VRWAIT ; Wenn VRWAIT = 0 (V/R nicht gedrückt) tst R16 breq ACSM80 lds R16,ACSMTH ; .. oder Schwellwertschalter aus tst R16 breq ACSM80 lds R16,AUTOON ; .. oder Abschwächer Automatik aus cpi R16,'*' breq ACSM80 lds R16,ACSMON ; .. oder ACSM im Einstellmenü ausgeschaltet tst R16 brne ACSM81 ; ACSM80: cbi DDRB,3 ; dann Sound ausschalten lds R16,VRMUTE ; .. und wenn nicht V/R-Taster-Knacken-Unterdrückung aktiv tst R16 brne ACSM84 cbi DDRC,4 ; .... Mute ausschalten rjmp ACSM9 ACSM84: sbi DDRC,4 ; .... sonst Mute einschalten (V/R-Mute bei ASM aus) rjmp ACSM9 ; ACSM81: sbi DDRC,4 ; Sonst Mute einschalten lds R16,VRMUTE ; .. und wenn nicht V/R-Taster-Knacken-Unterdrückung aktiv tst R16 brne ACSM82 sbi DDRB,3 ; .... Sound einschalten rjmp ACSM9 ACSM82: cbi DDRB,3 ; .... sonst Sound ausschalten (V/R-Mute bei ASM ein) ; ACSM9: ret ; ;**** Soundgenerator (Alle 60 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 ; .. schon fertig ; SOUG1: lpm ; Get one Byte to R0 adiw ZL,1 ; Increment Z sts OCR2A,R0 ; Variablen Oscillator laden dec R0 ; Sonderfall Wert = 1 breq SOUG10 ; .. Piepser bleibt aus sbi DDRB,3 ; .. sonst Piepser aktivieren rjmp SOUG11 SOUG10: cbi DDRB,3 SOUG11: sbi DDRC,4 ; NF Degate aktivieren ; lpm ; Vorschau auf nächstes Byte tst R0 ; Wenn Wert = $0 brne SOUG2 clr ZH ; .. Fertig, SOUPNT MSB auf 0 SOUG2: sts SOUPNT,ZL ; Sound-Pointer retten sts SOUPNT+1,ZH ; SOUG9: ret ; ; **** Messspannung UMESSP in Bargraph UMESS(0..7) wandeln ; Anzeige hat 8*4 = 32 Bars, Angezeigt wird UMESSP/4, also ; nur der Bereich 0..127 CONVUM: lds R17,UMESSP ; Spitzenwert Messspannung in R17 bilden lds R16,UMESSP+1 cp R17,R16 brcc CUM09 mov R17,R16 CUM09: lds R16,UMESSP+2 ; Spitzenwert-Buffer rechts schieben sts UMESSP+3,R16 lds R16,UMESSP+1 sts UMESSP+2,R16 lds R16,UMESSP sts UMESSP+1,R16 stsi UMESSP,0 ; ;?? lds R17,UMREF ;???? Testausgabe! lsr R17 ; 0..127 für Anzeige auf 0..31 skalieren lsr R17 ldi R16,8 ; Stellenzähler ldi XH,1 ; Pointer auf Bargraph ldi XL,LOW(UMESS) dec R17 ; Um 1 verringern auf -1 .. 30 ; CUM1: ldi R19,$20 ; Blank ist Bargraph-Wert 0 tst R17 ; Wenn Anzeigewert < 0 brmi CUM9 ; .. diese Stelle Blank ; ldi R19,$85 ; Bargraphwert auf 4 voreinstellen cpi R17,$04 ; Wenn Anzeigewert < 4 brcc CUM9 ; mov R19,R17 ; .. Bargraphwert ist 2 LSb von Anzeigewert andi R19,$03 ldi R18,$82 ; .. + $82 add R19,R18 ; CUM9: st X+,R19 ; Bargraphwert speichern ldi R18,4 ; Anzeigewert um 4 verringern sub R17,R18 dec R16 ; Loopcount, 8 Passes brne CUM1 ; ret ; ; *** Referenzwert Puffer halbieren (wenn Abschwächung hochschaltet) UMR50P: push R16 ldi YL,low(UMESSR) ; Pointer auf Referenzwert Puffer ldi YH,1 UMR501: ld R16,Y ; Einen Wert holen lsr R16 ; halbieren st Y+,R16 ; ablegen und Y weiterschalten cpi YL,low(UMESSR+10) ; insgesamt 10 * brne UMR501 stsi UMESSP,0 ; Messspannung Momentanspitzenwert löschen pop R16 ret ; ; *** Referenzwert Puffer Service alle 60 ms ; Alles eins weiterschieben, neuesten Spitzenwert einfügen ; Gesamt-Spitzenwert ermitteln, auf 64..127 begrenzen, Ergebnis in UMREF UMRNXT: push R16 push R17 ldi YL,low(UMESSR+9) ; Pointer auf Referenzwertbuffer (10 Stellen) ldi YH,1 UMRG0: ld R16,-Y ; Bisherigen Inhalt eins nach rechts rücken std Y+1,R16 ; 8->9, 7->8 ... 0->1 cpi YL,low(UMESSR) brne UMRG0 lds R17,UMESSP ; Spitzenwert der letzten 60 ms in Position 0 sts UMESSR,R17 ; ldi YL,low(UMESSR) ; Pointer auf Referenzwert Puffer ldi YH,1 clr R16 UMRG1: ld R17,Y+ ; einen Wert holen cp R16,R17 ; wenn grösser als bisheriges Maximum brcc UMRG2 mov R16,R17 ; als neues Maximum nehmen UMRG2: cpi YL,low(UMESSR+10) ; insgesamt 10 * brne UMRG1 cpi R16,127 ; Wenn Ergebnis > 127 brcs UMRG3 ldi R16,127 ; .. auf 127 begrenzen UMRG3: cpi R16,40 ; Wenn Ergebnis < 40 brcc UMRG4 ldi R16,40 ; .. auf 40 begrenzen UMRG4: sts UMREF,R16 pop R17 pop R16 ret ; ; **** Abschwächercode in Anzeige Dämpfung/Entfernung umrechnen CONVAB: ; ** Abschwächercode in dB wandeln ; lds R16,ABSBIN ; Abschwächer Code holen mov R17,R16 ; .. und mit 5 malnehmen lsl R17 lsl R17 add R16,R17 ; ldi XH,1 ; In BCD wandeln für dB-Anzeige ldi XL,LOW(ABSCHW) rcall B3BCD ; ; ** Abschwächercode in Entfernung wandeln ; lds R16,ABSBIN ; Abschwächer Code holen lds R17,PFOXBN ; Korrekturfaktor Sendeleistung dazu sub R16,R17 lds R17,DISTCF ; Korrekturfaktor aus Abgleichmenü dazu add R16,R17 ldi R17,10 ; Basis-Offset dazu add R16,R17 ; ; DIS3: lds R17,ABSCHW+1 ; Default: Abschwächer-dB-Wert Anzeigen lds R18,ABSCHW+2 ldi R19,$80 ; dB Symbol ; lds R20,PFOXBN ; Wenn PFOXBN = 16 cpi R20,16 ; .. dann immer dB anzeigen brne CUR40 lds R16,ABSCHW ; .. Wenn >= 100 db tst R16 breq CUR39 lds R17,ABSCHW ; .... 3stellig ohne dB anzeigen lds R18,ABSCHW+1 lds R19,ABSCHW+2 CUR39: ldi R16,-1 ; CUR40: sbrc R16,7 ; Wenn Code Negativ ist rjmp CUR499 ; .. dB anzeigen ; ldi R18,'k' ldi R19,'m' ; cpi R16,0 ; 9 km brne CUR41 ldi R17,9 CUR41: cpi R16,1 ; 8 km brne CUR42 ldi R17,8 CUR42: cpi R16,2 ; 7 km brne CUR43 ldi R17,7 CUR43: cpi R16,3 ; 6 km brne CUR44 ldi R17,6 CUR44: cpi R16,4 ; 5 km brne CUR45 ldi R17,5 CUR45: cpi R16,5 ; 4 km brne CUR46 ldi R17,4 CUR46: cpi R16,6 ; 3 km brne CUR47 ldi R17,3 CUR47: cpi R16,7 ; 2 km brne CUR48 ldi R17,2 CUR48: cpi R16,8 ; 1,5 km brne CUR49 ldi R17,1 ldi R19,5 CUR49: cpi R16,9 ; 1 km brne CUR410 ldi R17,1 CUR410: cpi R16,10 ; 700 m brne CUR411 ldi R17,7 clr R18 clr R19 CUR411: cpi R16,11 ; 500 m brne CUR412 ldi R17,5 clr R18 clr R19 CUR412: cpi R16,12 ; 300 m brne CUR413 ldi R17,3 clr R18 clr R19 CUR413: cpi R16,13 ; 200 m brne CUR414 ldi R17,2 clr R18 clr R19 CUR414: cpi R16,14 ; 150 m brne CUR415 ldi R17,1 ldi R18,5 clr R19 CUR415: cpi R16,15 ; 100 m brne CUR416 ldi R17,1 clr R18 clr R19 CUR416: cpi R16,16 ; 50 m brne CUR417 ldi R17,5 clr R18 CUR417: cpi R16,17 ; 30 m brne CUR418 ldi R17,3 clr R18 CUR418: cpi R16,18 ; 20 m brne CUR419 ldi R17,2 clr R18 CUR419: cpi R16,19 ; 10 m brne CUR420 ldi R17,1 clr R18 CUR420: cpi R16,20 ; 5 m brne CUR421 clr R17 ldi R18,5 CUR421: cpi R16,21 ; 2 m brne CUR422 clr R17 ldi R18,2 CUR422: cpi R16,22 ; 1 m brne CUR423 clr R17 ldi R18,1 CUR423: cpi R16,23 ; < 1 m brcs CUR499 ldi R17,'<' ldi R18,1 ; CUR499: sts DIST+0,R17 ; Entfernungsanzeige bereitstellen sts DIST+1,R18 sts DIST+2,R19 ; ; Abschwächer-Spannung aus Tabelle holen, x5dB-Werte interpolieren ; lds R16,ABSBIN ; Abschwächer-Code mov R17,R16 ; .. brauchen wir noch lsr R16 ; .. geteilt durch 2 ldi XL,low(ABSTAB) ; ist Pointer in Tabelle ldi XH,high(ABSTAB) add XL,R16 ld R18,X+ ; Analogwert holen ; sbrs R17,0 ; Wenn Code ungerade rjmp CUR52 ld R17,X ; .. nächsten Tabellenwert auch noch holen add R18,R17 ; .. und Mittelwert bilden ror R18 ; CUR52: com R18 ; 0..255 nach 255..0 wandeln out OCR0A,R18 ; Analogwert an PWM übergeben ; CUR9: ret ; ; ; ################### ; #### EEPROM Handling ############################################# ; ################### ; ; ++++ Geänderte Parameter von EEPCLR bis EEP2-1 ; ins EEPROM speichern ; SAVCHG: LDI YL,LOW(EEPCLR) ; Pointer auf Variablen ldi YH,1 LDI R20,EEPCLR-EEPCLR ; Bytecounter und EEPROM Low Adresse OUT EEARH,C0 ; High Adresse ist 0 SAVCH1: LD R16,Y+ ; 1 Variable holen ; Derzeitigen Wert aus EEPROM holen und vergleichen OUT EEARL,R20 ; EEPROM Entry Adresse laden LDI R17,$01 OUT EECR,R17 ; Set EEPROM Read Cmd SAVCH2: IN R17,EECR ; Wait for EEPROM Read complete ANDI R17,$01 BRNE SAVCH2 IN R17,EEDR ; Daten lesen CP R16,R17 ; .. und vergleichen BREQ SAVCH4 ; Wenn ungleich: ins EEPROM schreiben SAVCH3: IN R17,EECR ; Wait for EEPROM Ready to write ANDI R17,$02 BRNE SAVCH3 OUT EEARL,R20 OUT EEDR,R16 CLI ; Interrupt ausschalten LDI R17,$04 LDI R18,$02 OUT EECR,R17 ; Set EEPROM Master Write Enable OUT EECR,R18 ; Set EEPROM Write SEI ; Interrupt wieder an SAVCH4: INC R20 CPI R20,EEP2-EEPCLR ; Gesamter Bereich geschrieben? BRNE SAVCH1 RET ; ; ++++ Abgleichwerte von EEP2 bis EEPEND-1 ; ins EEPROM speichern ; SAVCAL: LDI YL,LOW(EEP2) ; Pointer auf Variablen ldi YH,1 LDI R20,EEP2-EEPCLR ; Bytecounter und EEPROM Low Adresse OUT EEARH,C0 ; High Adresse ist 0 SAVCA1: LD R16,Y+ ; 1 Variable holen SAVCA2: IN R17,EECR ; Wait for EEPROM Ready to write ANDI R17,$02 BRNE SAVCA2 OUT EEARL,R20 OUT EEDR,R16 CLI ; Interrupt ausschalten LDI R17,$04 LDI R18,$02 OUT EECR,R17 ; Set EEPROM Master Write Enable OUT EECR,R18 ; Set EEPROM Write SEI ; Interrupt wieder an INC R20 CPI R20,EEPEND-EEPCLR ; Gesamter Bereich geschrieben? BRNE SAVCA1 RET ; ; ++++ Alle Parameter aus EEPROM holen +++++++++++++++++++++++++++++++ ; GETEEP: LDI YL,Low(EEPCLR) ; Pointer auf Variablen ldi YH,1 LDI R20,$00 ; Bytecounter und EPROM Low Adresse OUT EEARH,R20 ; High Adresse ist 0 GET1: OUT EEARL,R20 LDI R17,$01 OUT EECR,R17 ; Set EEPROM Read Cmd GET2: IN R17,EECR ; Wait for EEPROM Read complete ANDI R17,$01 BRNE GET2 IN R16,EEDR ; Daten lesen ST Y+,R16 ; Byte bzw low nibble speichern INC R20 ; Loopcounter CPI R20,EEPEND-EEPCLR ; Alle Bytes gelesen? BRNE GET1 RET ; ; ################### ; #### LCD-Ansteuerung ############################################### ; ################### ; ; **** Subroutine to Copy String to LCD Data Field ******************* ; ; String pointed to by Z ; Variables are inserted according to second 16 Bytes in Data String ; Also handles leading zero suppression ; LCDSTR: PUSH R0 PUSH R16 PUSH R17 PUSH XL PUSH XH PUSH YL PUSH YH ; ;++++ Make Y pointer to LCD Data Field LDI YH,HIGH(LCDDAT) LDI YL,LOW(LCDDAT) ; ;++++ Copy Data String LCDST1: LDI R16,2 ; Loopcounter for 2 8B-Strings ; LCDS11: CLR XH ; X is Offset to start of next 8B-String CLR XL ; (used only for multiple language records) LPM ; Get first Byte of line to R0 MOV R17,R0 ; Is it $10 = Multi Language Flag? CPI R17,$10 BRNE LCDS15 ; ADIW ZL,2 ; Read-Pointer skips $1010 LDS R17,SPRACH ; Get selected Language CPI R17,1 ; BRNE LCDS12 LDI XL,16 ; Language 1: Post-Offset 16 LCDS12: CPI R17,2 BRNE LCDS13 ADIW ZL,8 ; Language 2: Pre- and Post-Offset 8 LDI XL,8 LCDS13: CPI R17,3 BRNE LCDS15 ADIW ZL,16 ; Language 3: Pre-Offset 16 ; LCDS15: LDI R17,8 ; Bytecounter 8 to 0 LCDS16: LPM ; Get one Byte to R0 ADIW ZL,1 ; Increment Z ST Y+,R0 ; Store Byte DEC R17 ; Repeat 8 times BRNE LCDS16 ; ADD ZL,XL ; Post-Correct readpointer for multi-language ADC ZH,XH DEC R16 ; Do Two 8-Char Lines BRNE LCDS11 ; ; LDI YH,HIGH(LCDDAT) LDI YL,LOW(LCDDAT) ; ;++++ Insert Variable String LCDST2: LPM ; Get one Byte to R0 ADIW ZL,1 ; Increment Z MOV R16,R0 ; Use High Register for Immediate OpCodes ; CPI YL,LOW(LCDDAT) ; Wenn erstes Byte BRNE LCDS21 TST R16 ; .. und Inhalt = 0 BRNE LCDS21 RJMP LCDSTA ; dann keine Variablen = Fertig ; LCDS21: CPI R16,0 ; 0 is next Digit BREQ 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 CPI R16,10 ; Wenn Im Bereich 0..9 BRCC LCDS51 ; ORI R16,'0' ; Convert 0..9 to ASCII ; 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,$80 ; Codes im Bereich $80-$87 (Sonderzeichen) BRCS LCDST6 CPI R16,$88 BRCC LCDST6 ANDI R16,$07 ; .. nach 0..7 umsetzen ; LCDST6: ST Y,R16 ; Insert character ; LCDST9: INC YL ; Increment Write Pointer CPI YL,LOW(LCDDAT)+16 ; Repeat 16 times BRNE LCDST2 ; LCDSTA: POP YH POP YL POP XH POP XL POP R17 POP R16 POP R0 RET ; ; ; **** LCD-Treiber ********************************************* ; ; Bedient das LCD-Display ueber die standardisierte 4+3-bit Schnittstelle ; ; ++++ Initialize the LCD Display INILCD: push R16 push R25 ; ldi R25,20 ; Wait 20 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,5 ; Wait 5 msec rcall DELXMS ldi R25,$30 ; Initialize LCD rcall LC1CMD ldi R25,16 ; Wait Another 16 msec rcall DELXMS ldi R25,$20 ; Auf 4 bit Betrieb schalten rcall LC1CMD ldi R25,$28 ; System Set: 2zeilig, 5*7 Matrix,4 bit Betrieb rcall LC2CMD ldi R25,$06 ; Cursor Mode: laeuft nach rechts rcall LC2CMD ldi R25,$0C ; Display on, Cursor Off rcall LC2CMD ldi R25,$80 ; DDRAM-Adress auf 0 rcall LC2CMD ldi R25,$01 ; Clear Display, Cursor Home rcall LC2CMD ldi R25,2 ; Wait 2 msec rcall DELXMS ; ; ++ Load 8 character generator fields from table ; 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 16 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,1 ldi R16,8 ;Loop-Counter, erste Zeile OUTLC1: ld R25,Y+ ;Get one Data Byte rcall LC2DAT ;Write to Display dec R16 ;Decrement Loopcounter brne OUTLC1 ; ldi R25,$A8 ;DDRAM-Adress auf 40 = Anfang 2te Zeile rcall LC2CMD ldi R16,8 ;Loop-Counter, zweite Zeile OUTLC2: ld R25,Y+ ;Get one Data Byte rcall LC2DAT ;Write to Display dec R16 ;Decrement Loopcounter brne OUTLC2 ; 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 swap R25 andi R25,$0F ; ori R25,$10 rjmp LC1CM0 ; LC1CMD: push R25 ; Entry for Command Mode swap R25 andi R25,$0F ; LC1CM0: ori R25,$C0 ; Pull-Ups fuer Taster out PORTD,R25 ; Post Data nop nop nop nop nop nop nop sbi PORTC,5 ; Toggle Enable Bit nop nop nop nop nop nop nop cbi PORTC,5 ; ldi R25,213 ; Wait 40 usec = 640 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 * 5 * 256 * 3 Cycle / 4 MHz) DELXMS: PUSH R16 PUSH R17 PUSH R25 ; DXMS: CLR R16 LDI R17,21 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 ; ; ************************************ ; ******* 200 usec 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 R16 PUSH R22 PUSH R23 ; Get some work registers PUSH R24 PUSH XL PUSH XH IN R24,SREG ; Save Statusreg PUSH R24 ; ; ++ 125 us Service ; TIM40: inctim TIK5K,5,TIM599 ; Increment to 1 msec sei ; Enable next Interrupt ; ; ++ 1 ms Service ; TIM50: rcall TUNE ; Tune VCO to target Frequency rcall DEBNCE ; Debounce Drehgeber ; TIM501: inctim TIK1M,20,TIM502 ; Increment to 20 msec rcall DEBNC2 ; Schnelltaster Debounce alle 10 ms rjmp TIM504 TIM502: lds R24,TIK1M cpi R24,10 brne TIM599 rcall DEBNC2 TIM599: rjmp TIM99 ; ; ++ 20 ms Service ; TIM504: d2bcd TIMER+2,0,99 ; Decrement Timer ms in R22,SREG ; Save the Carry Flag d2bcd TIMER+2,0,99 sbrs R22,0 ; Skip if Carry set (after first Decrement) rjmp TIM101 TIM10: d2bcd TIMER,0,99 ; Decrement Timer s ; TIM101: lds R24,TIMER+3 ; Wenn Timer 00:00 erreicht hat tst R24 brne TIM102 lds R24,TIMER+2 tst R24 brne TIM102 lds R24,TIMER+1 tst R24 brne TIM103 lds R24,TIMER tst R24 brne TIM103 rjmp TIM104 TIM102: rjmp TIM20 TIM103: rjmp TIM18 ; TIM104: lds R24,TFOXS ; .. Timer auf Startwert setzen sts TIMER,R24 lds R24,TFOXS+1 sts TIMER+1,R24 lds R24,TFOXS+2 sts TIMER+2,R24 lds R24,TFOXS+3 sts TIMER+3,R24 ; lds R24,FOX ; Aktuelle Fuchs Nr. lds R23,NFOX ; Zahl der Füchse cp R23,R24 ; Wenn derzeitiger Fuchs <> Maxwert brne TIM11 lds R24,FOX+1 lds R23,NFOX+1 cpi R23,1 ; Wenn Maxwert = 1 brne TIM105 ldi R23,5 ; .. auf 5 setzen = Bat-Alarm nur alle 5 min bei Foxoring TIM105: cp R23,R24 breq TIM12 TIM11: i2bcd FOX,1,16 ; Fuchs hochzaehlen rjmp TIM20 TIM12: stsi FOX,0 ; Sonst Fuchs auf 1 setzen stsi FOX+1,1 stsi BATTIM,150 ; Check Battery Timer auf 'in 10 sec' setzen ; TIM18: lds R22,TALARM ; Get Alarm-Time lds R23,TALARM+1 add R22,R23 ; Wenn Zeit = 0 breq TIM20 ; .. nix tun lds R22,TIMER+1 ; Sonst Timer mit Alarm vergleichen cp R22,R23 brne TIM20 lds R23,TALARM lds R22,TIMER cp R22,R23 brne TIM20 stsi ALATIM,1 ; Bei Match: Flag für Main setzen ; TIM20: inctim TIK60,3,TIM21 ; Increment 20 msec Timer up to 3 (60 ms) stsi TICK,1 ; At Time 60 set Timing Flag for Main inctim TIK300,5,TIM21 ; .. and increment 300 ms Timer up to 5 ; TIM21: inctim TIK20M,50,TIM99 ; Increment 20 msec Timer up to 50 (1 s) stsi TACK,1 ; At Time 1 s set Timing Flag for Main ; ; ++ 1 sec Service ; lds R24,STOPWR ; Falls Stopwatch an tst R24 breq TIM30 i2bcd STOPW+3,0,59 ; Uhr hochzählen Sekunden brcc TIM30 ; i2bcd STOPW+1,0,59 ; Minuten brcc TIM30 lds R24,STOPW ; Stunde inc R24 andi R24,$07 ; Bei 8 h wrappen sts STOPW,R24 ; TIM30: inctim TIK1S,60,TIM99 ; Increment 1 sec Timer ; ; ++ 1 min Service ; Derzeit nichts... ; ; ++ Conclusion of Interrupt Service ; TIM99: CLI ; No interrupts during conclusion POP R24 ; Restore Status Reg OUT SREG,R24 POP XH POP XL POP R24 POP R23 POP R22 POP R16 RETI ; Interrupt-Handling beendet ; ; ; ++++ Tune VCO to Target Frequency ; ; Zaehlt für jeweils 50 msec die VCO Frequenz und erzeugt ; einen der Abweichung proportionalen Abstimmimpuls ; This Subroutine is called by the interrupt handler once per ms ; TUNE: PUSH R22 PUSH R23 ; Get some work registers PUSH R24 PUSH R25 ; lds R24,TIK150 ; Increment 1 msec Timer to 50 ms inc R24 sts TIK150,R24 cpi R24,50 ; up to 50 breq TUN50M lds R23,TUNLEN ; Wenn Zeit = Tuning Puls Länge cp R23,R24 brne TUN500 cbi DDRB,2 ; .. Tuning-Ausgang auf High Z cbi PORTB,2 TUN500: rjmp TUN599 ; ; ++ 50 ms Service TUN50M: clr R24 sts TIK150,R24 ; clr R24 lds R22,TCNT1L ; Frequenzzähler auslesen lds R23,TCNT1H ; sts TCNT1H,R24 ; .. und wieder auf 0 setzen sts TCNT1L,R24 sts FISTH,R23 ; Ist-Frequenz ablegen für Diagnose sts FISTL,R22 ; TUN501: lds R24,FSOLLL ; Sollfrequenz holen lds R25,FSOLLH sub R24,R22 ; Soll - Ist berechnen sbc R25,R23 ; mov R23,R25 ; Vorzeichen der Differenz abtrennen andi R23,$80 ; .. und in R23 halten breq TUN502 ; Wenn Negativ: com R24 ; .. 2er Komplement bilden com R25 adiw R24,1 TUN502: cpi R25,11 ; Auf 12*256 begrenzen brcs TUN503 ldi R25,11 ldi R24,$FF TUN503: clc ; 2 Stellen links rotieren rol R24 ; Ergibt 0..47 in MSB rol R25 rol R24 rol R25 ror R24 ; .. und 0..63 in LSB ror R24 tst R25 ; Wenn MSB <> 0 breq TUN504 clr R24 ; Dann LSB auf 0 ; TUN504: sts TUNLEN,R25 ; Puls-Länge in ms ablegen tst R24 ; Wenn Abweichung <> 0 brne TUN505 tst R25 brne TUN505 rjmp TUN599 ; TUN505: sbrc R23,7 ; Wenn Vorzeichen - cbi PORTB,2 ; .. Regelausgang auf 0 sbrs R23,7 ; Sonst sbi PORTB,2 ; .. auf 1 sbi DDRB,2 ; Ausgang enabeln ; tst R24 ; Wenn LSB <> 0 => Kurzpuls < 1 msec breq TUN599 ; TUN506: ldi R25,40 ; Inner Loop ist 3 cyc * 40 = 15 usec TUN507: dec R25 brne TUN507 ; Sie wird 1..63 * durchlaufen dec R24 brne TUN506 ; cbi DDRB,2 ; Tuning-Ausgang wieder auf High Z cbi PORTB,2 ; TUN599: POP R25 POP R24 POP R23 POP R22 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 ; LDS R20,DEBP1 ; Debounce-Counter SBIC PINB,0 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 PINB,1 RJMP DEBINC RJMP DEBDEC ; DEB1: CPI R20,2 ; An oberem Limit (5.5 ms)? BREQ DEB3 INC R20 STS DEBP1,R20 CPI R20,2 ; Jetzt am oberen Limit? BRNE DEB3 SBIC PINB,1 RJMP DEBDEC RJMP DEBINC ; DEBINC: LDI R20,$1 RJMP DEB2 ; DEBDEC: LDI R20,$2 ; DEB2: SBIS PINB,4 ; Wenn Drehgeber gedrückt LSL R20 ; Flags 2 Stellen links schieben SBIS PINB,4 LSL R20 STS SWIFLG,R20 ; Flags speichern LDI R20,60 ; Click-Flag verhindern bei Drück+Dreh STS DEBDD,R20 ; ; ++ Debounce Drehdrücker (alle 1 ms) ; DEB3: LDS R20,DEBDD ; Timer holen SBIS PINB,4 ; Wenn nicht gedrückt RJMP DEB31 CPI R20,50 ; .. und Timer war genau am Limit BRNE DEB30 LDI R20,$10 ; .... dann Drücker-Flag setzen STS SWIFLG,R20 ; ; DEB30: CLR R20 ; Timer auf 0 setzen RJMP DEB39 ; DEB31: CPI R20,50 ; Gedrückt: Counter schon am Limit? BRCC DEB6 ; .. dann nix tun INC R20 ; .. sonst Counter hochzaehlen DEB39: STS DEBDD,R20 ; .. und retten ; ; ++ Mute Timer für V/R-Taster-Knacken dekrementieren DEB6: lds R20,VRMUTE ; Timer holen tst R20 ; .. und wenn grösser 0 breq DEB9 dec R20 ; ....dekrementieren sts VRMUTE,R20 ; DEB9: POP R20 RET ; ; **** Debounce Abschwächertaster (alle 10 ms) ; DEBNC2: PUSH R20 ; Used as Temp Register ; DEB4: LDS R20,DEBST ; Timer holen SBIC PINB,5 ; Wenn Bit (SU) nicht auf 0 rjmp DEB41 ; .. dann Taster offen ; ; Lang drücken handeln CPI R20,100 ; Counter schon am Limit (1 sec)? BREQ DEB8 ; dann nix tun INC R20 ; Counter hochzaehlen STS DEBST,R20 ; und retten CPI R20,100 ; Jetzt am Limit? BRNE DEB8 LDS R20,SWIFLG ; Dann Flag Lang setzen ORI R20,$40 ; STS SWIFLG,R20 ; rjmp DEB8 ; ; Kurz drücken handeln DEB41: cpi R20,5 ; War Taster 50 - 1000 ms gedrückt? brcs DEB42 cpi R20,100 breq DEB42 LDS R20,SWIFLG ; Dann Flag Kurz setzen ORI R20,$20 STS SWIFLG,R20 DEB42: clr R20 sts DEBST,R20 ; DEB8: POP R20 RET ; ; ************************* ; **** Initialisation Tables ********************************************** ; ************************* ; ; ++++ Special Characters 0..7, to be loaded into LCD-Display ; SPECCH: .DB $06,$05,$05,$0E,$15,$15,$0E,$00 ; 0: compressed dB-Symbol .DB $02,$05,$00,$00,$00,$05,$02,$00 ; 1: Up + Down Arrow .DB $10,$10,$10,$10,$10,$10,$10,$10 ; 2: | (S-Meter) .DB $18,$18,$18,$18,$18,$18,$18,$18 ; 3: || .DB $18,$1A,$1A,$1A,$1A,$1A,$1A,$18 ; 4: ||| .DB $18,$1B,$1B,$1B,$1B,$1B,$1B,$18 ; 5: |||| .DB $0C,$0C,$00,$0C,$0C,$00,$0C,$0C ; 6: ... (F3-Symbol) .DB $00,$1B,$1B,$00,$1B,$1B,$00,$00 ; 7: :: (F4-Symbol) ; ; ; ******************* ; **** Display Strings ********************************************* ; ******************* ; ; Die ersten 16 Bytes sind der Festtext-Teil der Anzeige ; ":" in Variablenposition = 0 als Space zeigen (Leading Zero Suppress) ; 0 in Zeichenposition = Komprimiertes dB Zeichen ; 1 " = Pfeile Up + Down ; 2 " = Block 1 Linie breit (S-Meter) ; 3 " = Block 2 Linien breit ; 4 " = Block 3 Linien breit ; 6 " = 3 Punkte (Frequenz) ; 7 " = 4 Punkte ; $E1 = ä, $EF = ö, $F5 = ü, $E2 = ß, kein Ä, Ö, Ü! ; $7E = ->, $7F = <- ; ; Die zweiten 16 Bytes sind jeweils Pointer auf die Variablen ; 1..8 = Leer ; Variablenname = Variable (Adresse <= $FF!) ; 0 = Nächste Stelle der aktuellen Variable ; Variablenwerte 0..9 werden in ASCII '0'..'9' umgesetzt ; " $80..87 werden in Sonderzeichen 0..7 (siehe oben) umgesetzt ; ; Für Texte ohne Variablen genügen 18 Byte: ; Erste 16 Byte wie oben, danach 0,0 ; ; >12345678< Power On STRPO: .DB " FJRX84 " .DB " V. ",VERSHI,".",VERSLO," " .DW 0 ; ; >12345678< RX Off STR000: .DW $1010 ; 1,2,3 .DB " RX Aus " .DB " RX Off " .DB " RX Uit " .DB "F:. :.s" .DB 1,2,3,4,5,6,7,8 .DB 1,FOX,0,4,5,TIMER,0,8 ; ; >12345678< RX Off STR001: .DW $1010 ; 1,2,3 .DB " RX Aus " .DB " RX Off " .DB " RX Uit " .DB ".:..:.. " .DB 1,2,3,4,5,6,7,8 .DB STOPW,2,0,0,5,0,0,8 ; ; >12345678< Frequenz ändern + S-Meter anzeigen STR02: .DB "3...:. ",1 .DB " " .DB 1,FRQ,0,0,FRQXSY,FRQ+3,7,8 .DB UMESS,0,0,0,0,0,0,0 ; ; >12345678< Timer, Entfernung + S-Meter anzeigen STR030: .DB ". :. :.." .DB " " .DB FOX+1,FRQXSY,TIMER,0,AUTOON,DIST,0,0 .DB UMESS,0,0,0,0,0,0,0 ; ; >12345678< Stopuhr, Entfernung + S-Meter anzeigen STR031: .DB ". .. :.." .DB " " .DB STOPW,FRQXSY,STOPW+1,0,AUTOON,DIST,0,0 .DB UMESS,0,0,0,0,0,0,0 ; ; >12345678< Stopuhr stoppen STR040: .DW $1010 ; 1,2,3 .DB "Uhr Stop" .DB "Clk Stop" .DB "Klk Stop" .DB ".:..:.. " .DB 1,2,3,4,5,6,7,8 .DB STOPW,2,0,0,5,0,0,8 ; ; >12345678< Stopuhr neu starten STR041: .DW $1010 ; 1,2,3 .DB "UhrStart" .DB "ClkStart" .DB "KlkStart" .DB ".:..:.. " .DB 1,2,3,4,5,6,7,8 .DB STOPW,2,0,0,5,0,0,8 ; ; >12345678< Timer neu starten STR05: .DB "TmrStart" .DB "F:. :.s" .DB 1,2,3,4,5,6,7,8 .DB 1,FOX,0,4,5,TIMER,0,8 ; ; >12345678< Set-Up-Menu aufrufen STR06: .DW $1010 ; 1,2,3 .DB "Einstell" .DB "Setup- " .DB "Setup- " .DW $1010 ; 1,2,3 .DB $7E," -men",$F5 .DB $7E," menu" .DB $7E," -menu" .DW 0 ; ; >12345678< Frequenz ändern anbieten STR07: .DB "3...:. ",1 .DW $1010 ; 1,2,3 .DB $7E," ",$E1,"ndern" .DB $7E," change" .DB $7E," wijzig" .DB 1,FRQ,0,0,FRQXSY,FRQ+3,7,8 .DB 1,2,3,4,5,6,7,8 ; ; >12345678< Zahl Füchse einstellen STR10: .DW $1010 ; 1,2,3 .DB "N F",$F5,"chse" .DB "N Foxes " .DB "N Vossen" .DB " :. ",1," " .DB 1,2,3,4,5,6,7,8 .DB 1,2,NFOX,0,5,6,7,8 ; ; >12345678< Zeit Füchse Sekunden einstellen STR11: .DW $1010 ; 1,2,3 .DB "T Fuchs",1 .DB "T Fox ",1 .DB "T Vos ",1 .DB ">:.<,..s" .DB 1,2,3,4,5,6,7,8 .DB 1,TFOXS,0,4,5,0,0,8 ; ; >12345678< Zeit Füchse ms einstellen STR12: .DW $1010 ; 1,2,3 .DB "T Fuchs",1 .DB "T Fox ",1 .DB "T Vos ",1 .DB ":.,>..12345678< Sendeleistung Füchse einstellen STR13: .DW $1010 ; 1,2,3 .DB "P Fu :.." .DB "PFox :.." .DB "PVos :.." .DB ":.,. .W",1 .DB 1,2,3,4,5,DIST,0,0 .DB PFOX,0,3,0,5,0,7,8 ; ; >12345678< Sendeleistung Füchse auf 'Nur dB Anzeige' STR130: .DW $1010 ; 1,2,3 .DB "P Fuchs " .DB "P Fox " .DB "P Vos ",1 .DW $1010 ; 1,2,3 .DB "nur dB ",1 .DB "dB only",1 .DB "alleen ",0 .DW 0 ; ; >12345678< Zahl Frequenzen einstellen STR14: .DB "N Freq. " .DB " : ",1," " .DB 1,2,3,4,5,6,7,8 .DB 1,2,3,NFREQ,5,6,7,8 ; ; >12345678< EOT Alarmzeit einstellen STR15: .DB "T Alarm " .DB "- :.s ",1," " .DB 1,2,3,4,5,6,7,8 .DB 1,2,TALARM,0,5,6,7,8 ; ; >12345678< EOT Alarmzeit Aus STR150: .DB "T Alarm " .DW $1010 ; 1,2,3 .DB " Aus ",1," " .DB " Off ",1," " .DB " Uit ",1," " .DW 0 ; ; >12345678< Akustisches S-Meter bei V/R Aus STR160: .DW $1010 ; 1,2,3 .DB "V/R-Lupe" .DB "F/B-Zoom" .DB "V/A-Loep" .DW $1010 ; 1,2,3 .DB " ",$7E," Aus " .DB " ",$7E," Off " .DB " ",$7E," Uit " .DW 0 ; ; >12345678< Akustisches S-Meter bei V/R Ein STR161: .DW $1010 ; 1,2,3 .DB "V/R-Lupe" .DB "F/B-Zoom" .DB "V/A-Loep" .DW $1010 ; 1,2,3 .DB " ",$7E," Ein " .DB " ",$7E," On " .DB " ",$7E," Aan " .DW 0 ; ; >12345678< STR20: .DW $1010 ; 1,2,3 .DB "Sprache " .DB "Language" .DB "Taal " .DW $1010 ; 1,2,3 .DB "Deutsch",1 .DB "English",1 .DB "Nederl.",1 .DW 0 ; ; >12345678< STR21: .DB " EEPROM " .DB $7E," Reset " .DW 0 ; ; >12345678< UBat kalibrieren STR22: .DW $1010 ; 1,2,3 .DB "Abg UBat" .DB "Cal VBat" .DB "Kal VBat" .DB "...:.,.V" .DB 1,2,3,4,5,6,7,8 .DB UBFVAL,0,0,UBATT,0,6,0,8 ; ; >12345678< Frequenz kalibrieren STR23: .DW $1010 ; 1,2,3 .DB "AbgF ..." .DB "CalF ..." .DB "KalF ..." .DB "........" .DB 1,2,3,4,5,FFIVAL,0,0 .DB UMESS,0,0,0,0,0,0,0 ; ; >12345678< Abschwächer kalibrieren STR24: .DW $1010 ; 1,2,3 .DB "Abg Absw" .DB "Cal Att." .DB "KalVerzw" .DB $7E," Start " .DW 0 ; ; >12345678< Batterie-Warnschwelle einstellen STR25: .DB "BatAlarm" .DB "< .,. V",1 .DB 1,2,3,4,5,6,7,8 .DB 1,2,UBWARN,4,0,6,7,8 ; ; >12345678< Entfernung kalibrieren STR26: .DW $1010 ; 1,2,3 .DB "Abg Entf" .DB "Cal Dist" .DB "Kal Afst" .DB " .. :.. " .DB 1,2,3,4,5,6,7,8 .DB 1,DCFVAL,0,4,DIST,0,0,8 ; ; >12345678< Frequenzbereich STR270: .DW $1010 ; 1,2,3 .DB "FBereich" .DB "F-Range " .DB "F-Bereik" .DB "3,5-3,65" .DW 0 ; ; >12345678< STR271: .DW $1010 ; 1,2,3 .DB "FBereich" .DB "F-Range " .DB "F-Bereik" .DB "3,5-3,8 " .DW 0 ; ; >12345678< STR28: .DW $1010 ; 1,2,3 .DB "Abgleich" .DB "Save Cal" .DB "OpslagKa" .DW $1010 ; 1,2,3 .DB $7E,"Sichern" .DB $7E," Values" .DB "libratie" .DW 0 ; ; >12345678< Ein Wert Abschwächer kalibrieren STRCAL: .DB ":.. :..",0 .DB " " .DB ABSVAL,0,0,4,ABSCHW,0,0,8 .DB UMESS,0,0,0,0,0,0,0 ; ; ** Die folgenden Strings sind Flash-Meldungen ; ; >12345678< Geänderte Daten in EEPROM schreiben STRSAV: .DB ">>EEPROM" .DB " " .DW 0 ; ; >12345678< Batteriespannung niedrig STRBAT: .DW $1010 ; 1,2,3 .DB "Batterie" .DB "Battery " .DB "Batterij" .DB " < .,. V" .DB 1,2,3,4,5,6,7,8 .DB 1,2,3,UBWARN,5,0,7,8 ; ; >12345678< Menü neu aufgemacht STRMEN: .DB "3...:. " .DB ".:..:.,." .DB 1,FRQ,0,0,FRQXSY,FRQ+3,7,8 .DB STOPW,1,0,0,UBATT,0,7,0 ; ; >12345678< Kanal geändert STRFRQ: .DB "3...:. " .DB " - . -" .DB 1,FRQ,0,0,FRQXSY,FRQ+3,7,8 .DB 1,2,3,4,5,FRQX,7,8 ; ; >12345678< Abschwächer-Automatik aus STRAA0: .DW $1010 ; 1,2,3 .DB "Automa- " .DB "Auto-Att" .DB "Verzwak." .DW $1010 ; 1,2,3 .DB "tik AUS" .DB " OFF " .DB "Auto UIT" .DW 0 ; ; >12345678< Abschwächerautomatik ein STRAA1: .DW $1010 ; 1,2,3 .DB "Automa- " .DB "Auto-Att" .DB "Verzwak." .DW $1010 ; 1,2,3 .DB "tik EIN" .DB " ON " .DB "Auto AAN" .DW 0 ; ; >12345678< Sendezeit-Ende Alarm STRALA: .DW $1010 ; 1,2,3 .DB " Noch " .DB " Only " .DB " Nog " .DB " :. sec " .DB 1,2,3,4,5,6,7,8 .DB 1,TALARM,0,4,5,6,7,8 ; ; ***************** ; **** Sound Strings ********************************************* ; ***************** ; ; Diese Strings enthalten Tonwertfolgen, die im 60ms-Raster ; abgespielt werden. Frequenz ist 62,5 kHz / Wert: ; 31 = 2 kHz, 62 = 1 kHz, 255 = 250 Hz ; Sonderfälle: 1 = kein Ton, 0 = End of String ; SOUPO: .DB 1,1,60,1,48,48,1,60 ; Power-On-Fanfare .DB 1,78,78,78,1,1,1,1,1,0 ; SOUHI: .DB 1,62,1,62,1,62,1,62,1,1 ; HI = Initial Power-On .DB 1,62,1,62,1,0 SOUABS: .DB 1,1,30,20,1,1,0,0 ; Automatik-Abschwächer SOUAB2: .DB 30,20,30,20,1,1,0,0 ; dto., Sound für Serie ; SOUALA: .DB 18,27,37,55,75,110,150,0 ; 'Ende - x sec'-Alarm ; SOUBAT: .DB 1,48,66,90,120,150,48,66 ; Low Battery Alarm .DB 90,120,150,48,66,90,120,150 .DB 1,0 ; SOUF1: .DB 1,150,110,75,55,33,1,1,60,1,1,0 ; Frequenz 1 SOUF2: .DB 1,150,110,75,55,33,1,1,60,1,60,1,1,0 ; F 2 SOUF3: .DB 1,150,110,75,55,33,1,1,60,1,60,1,60,1,1,0 ; F 3 SOUF4: .DB 1,150,110,75,55,33,1,1,60,1,60,1,60,1,60,1,1,0 ; F 4 ; SOUAA1: .DB 1,150,150,110,110,70,70,50,50,1,0,0 ; Automatik-Abschwächer Ein SOUAA0: .DB 1,50,50,70,70,110,110,150,150,1,0,0 ; Automatik-Abschwächer Aus ; SOUOK: .DB 1,1,96,1,96,96,96,1,96,1,1,0 ; Ok ; SOUPIP: .DB 30,1,0,0 ; Piep ; ; ; ************************ ;******** This is the End..... *************************************** ; ************************ ;