Pfad:
Home =>
cq-dl-Beiträge =>
Teil 4 => Cw01.asm
cq-dl-Beiträge zu ATMEL-AVR-Mikrocontrollern
Assembler-Quellcode des CW-Programmes
; **********************************************************
; * CW.asm gibt Morsezeichen aus, die im EEPROM-Speicher *
; * gespeichert sind und die über die serielle Schnitt- *
; * stelle des 2313-Experimentier-Boards eingegeben wer- *
; * den. Ausgabe NF an PB3. Baudrate 9k6. Takt 10 MHz. *
; * AVR AT90S2313. Programm (C)2002 by DG4FAC G.Schmidt *
; * Version 0.1 vom 28.12.2001 *
; * Bugs und Dankschreiben an info!at!avr-asm-tutorial.net *
; **********************************************************
;
.NOLIST
.INCLUDE "C:\avrtools\appnotes\2313def.inc"
.LIST
;
; Benutzte Register
;
; Register R0 wird für Lesen im Programmspeicher benutzt
; Register R0..R9 werden für Berechnungen benutzt
;
.DEF rcml = R10 ; Compare Match-Zahl, LSB
.DEF rcmh = R11 ; dto., MSB
.DEF rikl = R12 ; Interrupt-Anzahl kurz, LSB
.DEF rikh = R13 ; dto., MSB
.DEF rill = R14 ; Interrupt-Anzahl lang, LSB
.DEF rilh = R15 ; dto., MSB
.DEF rmp = R16 ; Multipurpose register, nicht bei Ints
.DEF rim = R17 ; Interrupt multi-purpose
.DEF rfl = R18 ; Flag Register, bei Ints und Normal
.DEF rst = R19 ; Statusregister bei Interrupts
.DEF rnsc = R20 ; Anzahl Punkte/Striche beim Senden
.DEF rmcd = R21 ; Morsecode beim Senden
.DEF x22 = R22 ; unbenutzt
.DEF x23 = R23 ; unbenutzt
.DEF rctl = R24 ; Zähler für Interrupt Tonerzeugung
.DEF rcth = R25 ; (wird als Doppelregister verwendet)
;
; Register XH:XL R27:R26 Zeiger in den Empfangspuffer
; Register YH:YL R29:R28 Zeiger beim Senden
; Register ZH:ZL R31:R30 Zeiger für Lesen im Programmspeicher
;
; Bits im Flagregister
;
.EQU besc = 7 ; ESCape-Sequenz, hole Parameter
.EQU bmesc = 0x80 ; Maskenbyte für ESC
.EQU bstx = 6 ; Starte Sendeprozess
.EQU bmstx = 0x40 ; Maskenbyte für bstx
.EQU bctx = 5 ; Beende Sendeprozess nach Leerzeichen
.EQU bmctx = 0x20 ; Maskenbyte für bctx
.EQU btxa = 4 ; Sendeprozess aktiv
.EQU bmtxa = 0x10 ; Maskenbyte für btxc
.EQU btxe = 3 ; Abschluss des Sendens
.EQU bmtxe = 0x08 ; Maskenbyte für btxe
.EQU bpl = 2 ; Lange Pause zur Buchstabentrennung
.EQU bmpl = 0x04 ; Maskenbyte für bpl
.EQU bpk = 1 ; Kurze Pause zur Punkt/Strich-Trennung
.EQU bmpk = 0x02 ; Maskenbyte für bpk
.EQU bquiet = 0 ; Dauerhaft inaktiviert bei Leerzeichen
.EQU bmquiet = 0x01 ; Maskenbyte für bquiet
;
; Default-Werte
;
.EQU cfrq=1000 ; NF-Frequenz
.EQU cbpm=60 ; Gebegeschwindigkeit
;
; Basisdefinitionen variabel nach Schaltung
;
.EQU fqu = 10000000 ; Quarzfrequenz des AVR
.EQU fbd = 9600 ; Baudrate des UART
.EQU pctrl = PORTB ; Control-Port für RTS/CTS
.EQU pdrr = DDRB ; Datenrichtungsregister Controlport
.EQU brts = PB2 ; RTS bit Input
.EQU bcts = PB4 ; CTS bit Output
.EQU boc1 = PB3 ; NF-Ausgabe über OC1-Pin
;
; Umrechnungen in Timer- und Counterwerte
;
.EQU nps = 8 ; Prescaler-Einstellung von Timer 1
.EQU ccm = fqu/nps/2; Konstante für Compare Match
.EQU cint =2941 ; Konstante für Int-Berechnung,
; experimentell ermittelt
;
; Definitionen fix
;
.EQU bddv = (fqu/(16*fbd))-1 ; Baudraten-Teiler
.EQU cnul = 0x00 ; Ende für nullterminierte Strings
.EQU chbsp = 0x08 ; Backspace character
.EQU chcr = 0x0D ; Carriage Return character
.EQU chlf = 0x0A ; Line Feed character
.EQU chff = 0x0C ; Form Feed character
.EQU chesc= 0x1B ; ESCape-Zeichen
;
; Definitionen I/O
;
; Definitionen für Timer-Controlregister TCCR1A
.EQU t1aus = 0b10000000 ; Schaltet den NF-Ausgang aus
.EQU t1ein = 0b01000000 ; Schaltet den NF-Ausgang ein
; Definition für Timer-Interrupt-Mask-Register TIMSK
.EQU t1CompInt=0b01000000 ; Interrupt bei Compare Match
; Definition für Timer-Controlregister TCCR1B
.EQU t1TaktInt=0b00001010 ; Timer-Takt CLK / 8, Clear Comp
; Definitionen für UART-Betrieb in UCR
.EQU siorxtx = 0b00011000 ; Betrieb RX und TX ohne Int
.EQU siorxint= 0b10011000 ; Betrieb RX mit Int, TX ohne Int
; Definition für den SLEEP-Mode in MCUCR
.EQU sleepmode=0b00100000 ; Aufwachen bei Interrupt
;
; Positionen im SRAM
;
.EQU sfrq = 0x0060 ; Eingestellte NF-Frequenz, Wort
.EQU sbpm = 0x0062 ; Eingestellte Geschwindigkeit, Byte
.EQU srtx = 0x0063 ; RAM-Puffer für Ein-/Ausgabezeile
.EQU srte = 0x00B3 ; Ende des nutzbaren Puffers, benutzt werden
; auch zwei weitere Folgebytes
;
; Programm beginnt hier
;
.CSEG
.ORG 0x0000
;
; Reset- und Interrupt-Sprungtabelle
;
rjmp start ; Reset-Vector
reti ; Ext Int 0, nicht benutzt
reti ; Ext Int 1, nicht benutzt
reti ; Timer 1 Capture Event, nicht benutzt
rjmp itc1m ; Timer 1 Compare Match
reti ; Timer 1 Overflow, nicht benutzt
reti ; Timer 0 Overflow, nicht benutzt
rjmp iurxc ; UART Rx Complete
reti ; UART Tx data register empty, nicht benutzt
reti ; UART Tx All sent, nicht benutzt
;
; Interrupt-Service-Routinen
;
itc1m: ; Timer 1 Compare Match Interrupt
in rst,SREG ; Rette Statusregister
sbiw rctl,1 ; Zähler eins abzählen
brne itc1mz ; Raus, wenn nicht Null
mov rcth,rikh ; Setze Zähler auf kurze Dauer
mov rctl,rikl
ldi rim,t1aus ; Ton auf aus
tst rnsc ; Zeichen fertig gesendet?
breq itc1m0 ; Verzweige, wenn Zeichen fertig
sbrc rfl,bpk ; kurze Pausen-Flag?
rjmp itc1ms ; Pause zwischen Punkt/Strich war schon
sbr rfl,bmpk ; Setze kurze Pause-Flag
rjmp itc1my ; und Ausgabe auf inaktiv, fertig
itc1ms: ; Sende nächsten Punkt/Strich
cbr rfl,bmpk ; Lösche kurze Pause-Flag
ldi rim,t1ein; Ton an = Toggle
dec rnsc ; Weiteren Punkt/Strich gesendet
rol rmcd ; Punkt oder Strich senden?
brcc itc1my ; Punkt senden
mov rcth,rilh ; Lange Dauer einstellen
mov rctl,rill
rjmp itc1my
itc1m0: ; Zeichen fertig gesendet
sbrc rfl,bctx ; Sendung beenden?
rjmp itc1mx
sbrc rfl,bpl ; Lange Pause senden?
rjmp itc1mn ; Nächsten Buchstaben beginnen
sbr rfl,bmpl ; Setze langes Pausen-Flag
mov rcth,rilh ; Dauer auf lang stellen
mov rctl,rill
itc1my: ; Stelle Modus inaktiv/toggle ein
sbrc rfl,bquiet ; bei Leerzeichen Ton aus
ldi rim,t1aus ; Ton auf aus
out TCCR1A,rim
itc1mz:
out SREG,rst ; Stelle Status wieder her
reti
itc1mn:
cbr rfl,bmpl ; Langes Pausen-Flag aus
ld rim,y+ ; Nächsten Buchstaben lesen
tst rim ; Null-Terminator
breq itc1mn1
cpi rim,chcr ; Ende der Zeile?
brne itc1mn2
itc1mn1:
sbr rfl,bmctx ; Setze beenden-Flag
ldi rim,' ' ; Sende noch ein Leerzeichen
itc1mn2:
out UDR,rim ; Debug
subi rim,0x20 ; ASCII-Control-Zeichen weg
brcc itc1mn3
ldi rim,'?'-0x20 ; Sende Fragezeichen
itc1mn3:
cpi rim,0x40 ; Kleinbuchstabe?
brcs itc1mn4
subi rim,0x20 ; in Grossbuchstaben wandeln
cpi rim,0x40
brcs itc1mn4
ldi rim,'?'-0x20
itc1mn4:
add rim,rim ; Mal 2 für Tabelle
push ZH ; Register retten
push ZL
push R0
ldi ZH,HIGH(2*morse) ; Zeichentabelle laden
ldi ZL,LOW(2*morse)
add ZL,rim ; Zeichen dazu zählen
brcc itc1mn5 ; Kein Übertrag?
inc ZH ; Übertrag
itc1mn5:
lpm ; Lese Zeichencode aus Tabelle
mov rmcd,R0 ; in Zeichencode-Register
adiw ZL,1 ; Zeiger auf nächstes Byte
lpm ; aus Tabelle lesen
mov rnsc,R0 ; Anzahl Striche/Punkte
pop R0 ; Wieder herstellen der Register
pop ZL
pop ZH
tst rnsc ; Undefiniertes Zeichen?
breq itc1mn ; Überspringe Zeichen
sbr rfl,bmquiet ; Leerzeichen
sbrs rnsc,7 ; Leerzeichen?
cbr rfl,bmquiet ; Kein Leerzeichen
cbr rnsc,0x80 ; Lösche höchstes Bit
mov rim,YL ; CTS einschalten?
sub rim,XL
brcs itc1mn6 ; Ausschalten
cpi rim,3
brcs itc1mn6
cbi pctrl,bcts ; CTS einschalten
rjmp itc1ms
itc1mn6:
sbi pctrl,bcts ; CTS ausschalten
rjmp itc1ms ; Sende ein Zeichen
itc1mx: ; Sendung einstellen
clr rim ; Timer 1 abschalten
out TCCR1B,rim ; Timer-Takt aus
out TCNT1H,rim ; Timer auf Null stellen
out TCNT1L,rim
out TIMSK,rim ; Timer Interrupts aus
out TCCR1A,rim ; Timer Compare Mode aus
cbr rfl,bmctx+bmtxa ; Ende-Flag und aktiv ausschalten
sbr rfl,bmtxe ; Beenden-Flag einschalten
ldi YH,HIGH(srte) ; Buffer auf Ende
ldi YL,LOW(srte)
st Y,rim ; Null-terminieren
rjmp itc1mz
;
; UART Rx Complete Interrupt
;
iurxc:
in rst,SREG ; Rette Statusregister
in rim,UDR ; Lese Zeichen von SIO
cpi rim,chesc ; ESCape-Sequenz?
brne iurx1
sbr rfl,bmesc ; Setze ESCape-Bit
rjmp iurxz
iurx1:
cpi rim,chbsp ; Backspace-Char?
brne iurx2
cpi XL,LOW(srtx) ; Schon auf Anfang?
breq iurxz
sbiw XL,1 ; Eine Position zurück
ldi rim,chcr ; Zeilenabschluss
st x+,rim
clr rim ; Null-terminieren
st x,rim
sbiw XL,1 ; zurück
ldi rim,chbsp ; Backspace zurücksenden
rjmp iurxe ; Echo character
iurx2:
cpi XL,low(srte) ; Pufferüberlauf?
brcs iurx3 ; Nein, weiter
ldi rim,chcr ; Character überschreiben
iurx3:
cpi rim,chcr ; Zeilenende?
brne iurxw ; Nein, in Puffer und fertig
sbrs rfl,btxa ; Überspringe Ausgabe wenn aktiv
out UDR,rim ; Carriage Return schon mal ausgeben
st x+,rim ; CR-Zeichen anhängen
clr rim ; Null terminieren
st x,rim
ldi XH,HIGH(srtx) ; Puffer auf Anfang
ldi XL,LOW(srtx)
sbr rfl,bmstx ; Über Flag Sender starten
ldi rim,chlf ; Sende Zeilenvorschub
rjmp iurxe ; Echo Line-Feed
iurxw:
st x+,rim ; Speichere character
ldi rim,chcr ; Abschluss terminieren
st x+,rim ; mit Carriage return
clr rim ; Null-terminieren
st x,rim
sbrs rfl,btxa ; Sender aktiv?
rjmp iurxs ; Nein, CTS nicht prüfen
mov rim,YL ; CTS ein oder aus?
sub rim,XL ; Distanz zwischen Ein- und Ausgabe
brcs iurxo ; Eingabe > Ausgabe: CTS aus
cpi rim,3 ; mindestens zwei Zeichen Vorlauf?
brcs iurxo ; Nein, dann CTS ausschalten
cbi pctrl,bcts ; CTS einschalten
rjmp iurxs ; Zeichen herstellen und raus
iurxo:
sbi pctrl,bcts ; CTS ausschalten
iurxs:
sbiw XL,2 ; Char wieder herstellen
ld rim,x+ ; durch Lesen im SRAM
iurxe:
sbrs rfl,btxa ; Keine Ausgabe, wenn aktiv
out UDR,rim ; Echo character an SIO zurück
iurxz:
out SREG,rst ; Stelle Status wieder her
reti ; Ende des Interrupts
;
; Diverse eigenständige Unterprogramme
;
; Kopiert den EEPROM-Inhalt in das SRAM
;
ecopy:
sbic EECR,EEWE ; Warte, bis EEPROM bereit
rjmp ecopy ; Noch nicht bereit
clr YH ; Startadresse im EEPROM auf Null
clr YL
ldi ZH,HIGH(sfrq) ; Startadresse im SRAM
ldi ZL,LOW(sfrq) ; auf ersten Parameter
ecopy1:
out EEAR,YL ; Leseadresse im EEPROM
; 2313 hat nur 128 Bytes, daher nur unteres Register
sbi EECR,EERE ; Lese-Strobe setzen
cbi EECR,EERE ; und wieder ausschalten
in rmp,EEDR ; Byte aus EEPROM-Datenregister lesen
st Z+,rmp ; und in SRAM schreiben
adiw YL,1 ; nächste EEPROM-Adresse anwählen
tst rmp ; Null-Terminator?
brne ecopy1 ; Nein: weiter kopieren
ret
;
; Schreibe Parameter in das EEPROM zurück
;
ewrite:
ldi ZH,HIGH(sfrq) ; Zeiger auf SRAM
ldi ZL,LOW(sfrq)
clr XH ; Zeiger in das EEPROM
clr XL
ewrite1:
sbic EECR,EEWE ; Frage Write-Bit im EEPROM
rjmp ewrite1 ; ab und wiederhole bis EEPROM ready
out EEARL,XL ; Schreibadresse im EEPROM einstellen
; Hat nur 7 Bit, daher nur LSB
ld rmp,Z+ ; Lese Byte aus SRAM in Register
out EEDR,rmp ; in das EEPROM-Datenregister
cli ; Keine Interrupts mehr beim Schreibvorgang
sbi EECR,EEMWE ; Setze EEPROM Master Write Enable
sbi EECR,EEWE ; Löse Schreibvorgang im EEPROM aus
sei ; Jetzt Interrupts wieder zulassen
adiw XL,1 ; Nächste EEPROM-Adresse in X-Zeiger
cpi XL,128 ; Ende EEPROM erreicht?
brcc ewrite2 ; Überlänge! Null fehlt! Abbrechen!
tst rmp ; Nullterminiert?
brne ewrite1 ; Noch weitere Bytes schreiben
ewrite2:
ret
;
; Lese16 wandelt eine ASCII-Zahl im Puffer in binär
; in R1:R0, bei Fehler Rückkehr mit gesetztem Carry-Bit
;
lese16:
clr R0 ; Leeren Resultat-Register R1:R0
clr R1
ldi ZH,HIGH(srtx) ; Zeige auf Pufferanfang
ldi ZL,LOW(srtx)
lese16a:
ld rmp,Z+ ; Lese ASCII-Ziffer aus SRAM
cpi rmp,chcr ; Ende der Zahl mit Carriage Return?
breq lese16ok ; Zahl mit Carriage Return beendet
cpi rmp,cnul ; Ende der Zahl mit Nullterminiert?
breq lese16ok ; Ende mit Nullterminierung
cpi rmp,'9'+1 ; Ziffer > ASCII-9?
brcc lese16no ; Ja, Fehler!
cpi rmp,'0' ; Ziffer < ASCII-0
brcs lese16no ; Ja, auch Fehler
subi rmp,'0' ; Wandle Ziffer in binär
; Ab hier wird das bisherige Resultat mit 10 multi-
; pliziert
mov R2,R0 ; Kopiere Binärzahl in Hilfsregister R3:R2
mov R3,R1
add R0,R0 ; Multipliziere mit 2 durch Addieren 16 Bit
adc R1,R1
brcs lese16no ; Überlauf beim Addieren, Fehler!
add R0,R0 ; Multipliziere mit 2 durch Addieren
adc R1,R1
brcs lese16no ; Überlauf beim Addieren, Fehler!
add R0,R2 ; Addiere die Kopie der Zahl
adc R1,R3
brcs lese16no ; Überlauf beim Addieren, Fehler!
add R0,R0 ; Multipliziere mit 2 durch Addieren
adc R1,R1
brcs lese16no ; Überlauf beim Addieren, Fehler!
; Hier ist das Multiplizieren mit 10 beendet.
add R0,rmp ; Addiere Ziffer zum Resultat hinzu
brcc lese16a ; Kein Überlauf des unteren Bytes
inc R1 ; Überlauf, oberes Byte erhöhen
brne lese16a ; Kein Überlauf des oberen Bytes
lese16no:
sec ; Setze Carry-Bit bei Fehler und kehre zurück
ret
lese16ok:
clc ; Clear Carry bei fehlerfrei
ret
;
; Wandle 16-Bit-Zahl in R1:R0 in ASCII in R4..R9 (nullterm.)
; unterdrücke führende Nullen, sende Ergebnis ohne führende
; Nullen über die SIO
;
b16asc:
clr ZH ; Z zeigt auf höchste ASCII-Ziffer in
ldi ZL,4 ; Register R4 (Zeiger in Register!)
ldi rmp,HIGH(10000) ; Beginne mit Zehntausendern
mov R3,rmp ; oberes Byte in R3
ldi rmp,LOW(10000)
mov R2,rmp ; unteres Byte in R2
rcall b16sub ; Ermittle ASCII-code der Zehntausender
; Stelle durch fortgesetztes Subtrahieren von 10000
ldi rmp,HIGH(1000) ; Weiter mit Tausendern
mov R3,rmp
ldi rmp,LOW(1000)
mov R2,rmp
rcall b16sub ; Ermittle ASCII-Code der Tausender
clr R3 ; Weiter mit Hunderten
ldi rmp,100
mov R2,rmp
rcall b16sub ; Ermittle ASCII-Code der Hunderter
ldi rmp,10 ; Weiter mit Zehnern
mov R2,rmp
rcall b16sub ; Ermittle ASCII-Code der Zehner
ldi rmp,'0' ; Rest sind Einer
add rmp,R0
mov R8,rmp ; R8 kriegt die ASCII-Einer
clr R9 ; Nullterminieren in R9
ldi ZL,4 ; Z auf 10000-er Zeichen
b16asc1:
cpi ZL,9 ; Ende der Zeichenkette erreicht?
breq b16asc2 ; Ja, raus
ld rmp,z+ ; Zeichen aus Register kopieren
cpi rmp,'0' ; Führende Null?
breq b16asc1 ; Ja, weitermachen
b16asc2:
dec ZL ; auf vorheriges Zeichen setzen
;
; Sende nullterminierten Text aus SRAM an SIO
; Z zeigt nicht ins SRAM, sondern in die Register mit
; dem Ergebnis!
; Das Registerpaar Z zeigt auf das erste Zeichen
;
txstxt:
ld rmp,z+ ; Lese Zeichen aus SRAM/Register
tst rmp ; Nullterminator erreicht?
breq txstxt1 ; Ja, raus und fertig
rcall txch ; Sende character über SIO
rjmp txstxt ; Weitermachen mit nächstem Zeichen
txstxt1:
ret
;
; Ermittle ASCII-Code einer Ziffer der 16-Bit-Binärzahl in
; R1:R0 durch fortgesetztes Subtrahieren einer 16-Bit-
; Hilfszahl (10000, 1000, 100, 10) in R3:R2. Tritt ein
; Überlauf ab, dann ist die Ziffer gefunden
; (Unterroutine für b16asc)
;
b16sub:
ldi rmp,'0' ; Setze ASCII-Null
b16sub1:
sub R0,R2 ; Subtrahiere die Hilfszahl
sbc R1,R3 ; in 16-bit
brcs b16sub2 ; Ende subtrahieren erreicht?
inc rmp ; Einer geht noch!
rjmp b16sub1 ; Weiter mit subtrahieren!
b16sub2:
add R0,R2 ; Zu weit, addiere wieder zurück
adc R1,R3
st Z+,rmp ; ASCII-Ziffer in Register schreiben
ret ; und zurück
;
; Sende nullterminierten Text aus dem Programmspeicher
; über die SIO aus
;
txtext:
lpm ; Lese Zeichen aus Programmspeicher mit Zeiger Z
tst R0 ; Ergebnis im Register R0 hat Null erreicht?
breq txtend ; Ja, raus aus der Routine
mov rmp,R0 ; Kopiere Zeichen in Senderegister
rcall txch ; Sende character mit Prüfung
adiw zl,1 ; Zeiger auf nächstes Zeichen
rjmp txtext ; Weitermachen bis Null
txtend:
ret ; Kehre zurück
;
; Liste alle Parameter über die SIO-Schnittstelle auf
;
txpar:
ldi ZH,HIGH(2*txtpar1) ; Sende Parametervorspann
ldi ZL,LOW(2*txtpar1) ; für NF-Frequenz
rcall txtext
lds R0,sfrq ; Zeige eingestellte Frequenz an
lds R1,sfrq+1
rcall b16asc ; Wandle in ASCII und sende Zahl
ldi ZH,HIGH(2*txtpar2) ; Zeige Vorspann für
ldi ZL,LOW(2*txtpar2) ; Geschwindigkeit an
rcall txtext
lds R0,sbpm ; Zeige Geschwindigkeit an
clr R1 ; nur 8 Bit!
rcall b16asc ; Wandle in ASCII und sende Zahl
ldi ZH,HIGH(2*txtpar3) ; Zeige Vorspann für Counter-
ldi ZL,LOW(2*txtpar3) ; Compare-Match-Zahl ccm an
rcall txtext
mov R1,rcmh ; Compare-Match-Zahl in R1:R0
mov R0,rcml
rcall b16asc ; Wandle in ASCII und sende
ldi ZH,HIGH(2*txtpar4) ; Zeige Vorspann für
ldi ZL,LOW(2*txtpar4) ; Anzahl NF-Ints bei Punkt an
rcall txtext
mov R1,rikh ; Anzahl Ints bei Punkt in R1:R0
mov R0,rikl
rcall b16asc ; Wandle in ASCII und sende
ldi ZH,HIGH(2*txtpar5) ; Zeige Vorspann für
ldi ZL,LOW(2*txtpar5) ; Anzahl NF-Ints bei Strich an
rcall txtext
mov R1,rilh ; Anzahl Ints bei Strich in R1:R0
mov R0,rill
rcall b16asc ; Wandle in ASCII und sende
ldi ZH,HIGH(2*txtpar6) ; Zeige Vorspann für
ldi ZL,LOW(2*txtpar6) ; Ausgabetext an
rcall txtext
ldi ZH,HIGH(srtx) ; Zeiger Z auf Ausgabetext im SRAM
ldi ZL,LOW(srtx)
rjmp txstxt ; Sende Inhalt SRAM nullterminiert
;
; 32-Bit durch 16-Bit-Division
;
; Dividiert 32-Bit-Zahl in R3:R2:R1:R0 durch R5:R4
; Ergebnis in R7:R6 (Ergebnis darf nicht > 16 Bit sein!)
;
div32:
clr R7 ; Clear Ergebnis-Register R7:R6
clr R6
inc R6 ; Stopbit setzen für 16 Divisionsschritte
div32a:
clc ; Null in Carry schieben
rol R0 ; Multipliziere Divident mit 2
rol R1
rol R2
rol R3
brcs div32e ; Carry ist herausgerollt? Dann 1!
cp R3,R5 ; Vergleiche oberes Byte
brcs div32n ; Ergebnis ist kleiner, also eine 0
brne div32e ; Ergebnis ist größer, also eine 1
cp R2,R4 ; Vergleich MSB gleich, vergleiche unteres
; Byte
brcs div32n ; Unteres Byte kleiner, also eine 0
div32e:
sub R2,R4 ; Ziehe den Divisor von den oberen 16 Bit ab
sbc R3,R5
sec ; Setze das Carry-Bit, Ergebnis ist eine 1
rjmp div32s ; Zum Reinschieben in das Ergebnis
div32n:
clc ; Lösche Carry-Bit, Ergebnis ist eine 0
div32s:
rol R6 ; Schiebe Carry-Bit von rechts in Ergebnis
rol R7
brcc div32a ; Ende, wenn eine 1 links herausrollt
ret
;
; Multipliziert 16-Bit-Zahl in R1:R0 mit 16-Bit-Zahl in R5:R4
; Ergebnis 32 Bit in R9:R8:R7:R6, für jeden Zahlenbereich
;
Mul16:
clr R3 ; Leere obere zwei Bytes der 16-Bit-Zahl
clr R2
clr R9 ; Leere Ergebnis-Register R9:R8:R7:R6
clr R8
clr R7
clr R6
Mul16a:
clc ; Null ins Carry-Bit
ror R5 ; Schiebe unterstes Bit Divisor in Carry
ror R4 ; und dividiere Multiplikant durch 2
brcc Mul16b ; Bit war eine 0, Addition überspringen
add R6,R0 ; addiere Multiplikator 32 Bit zum
adc R7,R1 ; bisherigen Ergebnis, jeweils mit
adc R8,R2 ; Überlauf
adc R9,R3
Mul16b:
tst R4 ; Schon alle Bits ausmultipliziert?
brne Mul16c ; Nein, LSB nicht Null, weiter
tst R5 ; Teste auch oberes Byte
brne Mul16c ; Nein, MSB nicht Null, weiter
ret ; Fertig
Mul16c:
clc ; Null in Carry-Bit schieben
rol R0 ; Zahl durch Linksschieben mit 2
rol R1 ; multiplizieren
rol R2
rol R3
rjmp Mul16a ; und weiter dividieren
;
; Dividiert 32 Bit-Zahl in R3:R2:R1:R0 durch eine
; 8-Bit-Zahl in R4 und durch 256, Ergebnis gerundet
; in R8:R7, Wertebereich beachten!
;
Div32_8:
clr R8 ; Ergebnisspeicher R8:R7:R6 leeren
clr R7
clr R6
inc R6 ; Stopbit nach 24 Schritten setzen
Div32_8a:
clc ; Carry-Bit leeren
rol R0 ; Divident mit 2 multiplizieren
rol R1 ; durch Linksschieben
rol R2
rol R3
brcs Div32_8e ; 1 herausgerollt, Ergebnis=1
cp R3,R4 ; Vergleiche oberstes Byte mit Divisor
brcs Div32_8n ; Kleiner, Ergebnis = 0
Div32_8e:
sub R3,R4 ; Ziehe Divisor von oberstem Byte ab
sec ; Setze Carry für Ergebnis = 1
rjmp Div32_8b ; Ins Ergebnis schieben
Div32_8n:
clc ; Clear Carry für Ergebnis = 0
Div32_8b:
rol R6 ; Ergebnis-Bit von rechts her hineinrotieren
rol R7
rol R8
brcc Div32_8a ; Weiter, wenn eine Null herausrollt
rol R6 ; Binäre Kommastelle eine 1, aufrunden?
brcc Div32_8z ; Nein, wenn Null
inc R7 ; Aufrunden LSB Ergebnis
brne Div32_8z ; Kein Überlauf bei LSB-Erhöhung
inc R8 ; Aufrunden MSB
Div32_8z:
ret
;
; Rechne Parameter um in Timer- und Zählerwerte
; Oben definiert: ccm = Taktfrequenz / Prescale 8 / 2
; cint = Konstante
; Compare-Match-Zahl für Timer 1 = ccm / NF-Frequenz
; Anzahl Ints bei Punkt = cint * NF-Frequenz / Speed /256
; Anzahl Ints bei Punkt = Anzahl Ints bei Strich * 3
;
calctc:
ldi rmp,BYTE4(ccm) ; Taktabhängige Konstante ccm
mov R3,rmp ; in R3:R2:R1:R0, bei 10 MHz: 625.000
ldi rmp,BYTE3(ccm) ; oder 0x00098968
mov R2,rmp
ldi rmp,BYTE2(ccm)
mov R1,rmp
ldi rmp,BYTE1(ccm)
mov R0,rmp
lds R4,sfrq ; durch NF-Frequenz in R5:R4
lds R5,sfrq+1
rcall div32 ; ergibt Compare Match-Zahl 16-Bit
mov rcmh,R7 ; Ergebnis in Speicher rcmh:rcml
mov rcml,R6
ldi rmp,HIGH(cint) ; Konstante für Anzahl Ints
mov R1,rmp ; bei 10 MHz und Teiler 200: 3125
ldi rmp,LOW(cint)
mov R0,rmp
lds R4,sfrq ; Mal NF-Frequenz in Hz
lds R5,sfrq+1
; rcall txreg ; Debug info
rcall mul16 ; Multplizieren 16 Bit * 16 Bit
; rcall txreg ; Debug info
mov R3,R9 ; Ergebnis in R9..R6 nach R3..R0 kopieren
mov R2,R8
mov R1,R7
mov R0,R6
lds R4,sbpm ; durch Gebegeschwindigkeit teilen
rcall div32_8 ; teilen 32-Bit durch 8-Bit
; rcall txreg ; Debug info
mov rikh,R8 ; in Kurzspeicher kopieren
mov rikl,R7
mov rilh,R8 ; und in Langspeicher kopieren
mov rill,R7
add rill,rill ; Langspeicher mit 2 malnehmen
adc rilh,rilh ; durch Addieren
add rill,rikl ; und noch einmal dazu zählen
adc rilh,rikh ; macht 3 mal so lang
ret
;
; Debug code
;
; Display Byte in rmp in Hex an die SIO
;
;txbhx:
; push rmp
; swap rmp
; rcall txnhx1
; pop rmp
;txnhx1:
; cbr rmp,0b11110000
; subi rmp,-'0'
; cpi rmp,'9'+1
; brcs txnhx2
; subi rmp,-7
;txnhx2:
; rcall txch
; ret
;
; Display Register R0..R9 in Hex an SIO
;
;txreg:
; ldi rmp,chcr
; rcall txch
; clr ZH
; clr ZL
;txreg1:
; ld rmp,Z+
; rcall txbhx
; ldi rmp,' '
; rcall txch
; cpi ZL,11
; brcs txreg1
; ldi rmp,chcr
; rcall txch
; ret
;
; Hauptprogramm-Loop, Restart-Vektor
;
start:
ldi rmp,low(RAMEND) ; Init stack pointer im SRAM
out SPL,rmp ; nur 8-Bit-Pointer bei 2313
ldi rmp,bddv ; Baudrate des UART einstellen
out UBRR,rmp
ldi rmp,siorxtx ; UART Tx und Rx ein, Ints aus
out UCR,rmp
cbi pdrr,brts ; Bit Richtung ist RTS-Eingang
sbi pdrr,bcts ; Bit Richtung ist CTS-Ausgang
sbi pctrl,bcts ; CTS ausschalten (invertiert!)
rcall ecopy ; Kopiere EEPROM-Inhalt nach RAM
ldi ZH,high(2*txtid) ; Sende ID-Text an SIO
ldi ZL,low (2*txtid)
rcall txtext
clr rfl ; Flag auf Anfangswert leer
;
; Bedingungen für Interrupt-Betrieb herstellen
;
start1:
rcall calctc ; Rechne Timerwerte und Ints aus
rcall txpar ; Gib die eingestellten Werte über SIO
ldi ZH,HIGH(2*txtcur) ; Sende Cursor-String
ldi ZL,LOW(2*txtcur)
rcall txtext
ldi rmp,sleepmode ; Mode Idle für Sleep einstellen
out MCUCR,rmp ; Aufwachen durch Interrupts
ldi rmp,siorxint ; Enable RX mit Interrupt
out UCR,rmp
cbi pctrl,bcts ; Aktiviere CTS-Leitung
sei ; Enable General Interrupt Flag
ldi XH,HIGH(srtx) ; Puffer auf Anfang stellen
ldi XL,LOW(srtx)
rcall starttx ; und Text in CW aussenden
ldi YH,HIGH(srte+3) ; Ausgabepointer hinter Ende
ldi YL,LOW(srte+3) ; des Puffers stellen
ldi XH,high(srtx+1) ; Puffer wieder auf Anfang
ldi XL,low(srtx+1) ; und überschreiben des Textes
clr rmp ; Null-Terminierung schreiben
st -x,rmp
ldi rmp,chcr ; Setze leeres Textfeld mit CR
st -x,rmp ; Jetzt zeigt X-Zeiger auf Anfang
;
; Interrupt loop, ab jetzt praktisch nur Kreisverkehr
; mit Ausbruch bei gesetzten Flagbits
;
loop:
sleep ; CPU schlafen schicken
nop ; Dummy-Befehl, bleibt bei Schlaf hier stehen
nop ; nach dem Aufwachen ausgeführt
sbrc rfl,bstx ; Sendeflag von Int-Routine gesetzt?
rjmp starttx ; Ja: Starte Sendevorgang
sbrc rfl,btxe ; Senden-beenden von Int-Routine?
rjmp stoptx ; Beende Sendevorgang
sbrc rfl,btxa ; Ist die Sendeausgabe aktiv?
rjmp loop ; (Während Aussendung keine Parameter!)
sbrc rfl,besc ; Parameter mit Menue holen?
rjmp getpar ; Hole Parameter über SIO
rjmp loop ; weiter im Kreis herum
;
; Startet Sendeprozess
;
starttx:
sbrc rfl,btxa ; Nicht neu starten, wenn schon aktiv
rjmp loop ; Wieder raus!
cbr rfl,bmstx ; Setze Flag bit zurück
sbi pctrl,bcts ; Stop CTS-Leitung
ldi YH,HIGH(srtx) ; Sende-Pointer auf Pufferanfang
ldi YL,LOW(srtx)
mov rcth,rikh ; Kurze Verzögerung bis zum Start
mov rctl,rikl
clr rnsc ; Auszugebendes Zeichen beendet, provoziert
; Laden des nächsten Zeichens bei der Senderoutine
sbi pdrr,boc1 ; Ausgabe Pin OC1=PB3 auf Ausgang
clr rmp ; Setze Timer-Werte
out TCCR1A,rmp ; OC1 inaktivieren
out TCNT1H,rmp ; Timer-Register auf Null setzen
out TCNT1L,rmp
out OCR1AH,rcmh ; Compare Match auf Dauer ent-
out OCR1AL,rcml ; sprechend der NF-Frequenz
ldi rmp,t1CompInt ; Ermögliche Compare Int
out TIMSK,rmp
ldi rmp,t1TaktInt ; Clear Timer on Compare
; Match und Prescaler CK/8
out TCCR1B,rmp ; Timer-Takt starten
rjmp loop ; und CPU bis zum Timer-Int schlafen legen
; ab jetzt läuft wieder alles automatisch ab
;
; Beendet Sendevorgang
;
stoptx:
cbr rfl,bmtxe ; Setze Beenden-Flag zurück
cbi pctrl,bcts ; CTS wieder einschalten
ldi ZH,HIGH(2*txtcur) ; Gib Cursor an SIO aus
ldi ZL,LOW(2*txtcur)
rcall txtext
cpi XL,LOW(srtx) ; Schon Zeichen eingegeben?
breq loop ; Nein, schlafen legen bis SIO-RX kommt
ldi ZH,HIGH(srtx) ; Gepufferte Zeichen auf Cursor-
ldi ZL,LOW(srtx) ; zeile ausgeben an SIO-TX
stoptx1:
ld rmp,z+ ; Zeichen aus Puffer lesen
rcall txch ; an SIO senden
cp ZL,XL ; Schon alle ausgegeben?
brcs stoptx1 ; Weiter ausgeben
rjmp loop ; Alles ausgegeben, schlafen legen
;
; Getpar holt menuegesteuert Parameter vom User
;
getpar:
ldi rmp,siorxtx ; Rx-Interrupts abschalten
out UCR,rmp ; reiner Polling-Betrieb
getpar0:
rcall calctc ; Rechne aktuelle Parameter um
getpara:
rcall txpar ; Gib die Parameter aus
getparb:
ldi ZH,HIGH(2*txtmenue) ; Gib Menue aus
ldi ZL,LOW(2*txtmenue)
rcall txtext
rcall rxch ; Hole ein Zeichen von SIO
cpi rmp,chesc ; Ende-Zeichen ESCAPE?
brne getpar1 ; Nein, mach weiter im Menue
cbr rfl,bmesc ; Setze Menue-Flag zurück
rjmp start1 ; Ende, starte fast alles neu
getpar1:
cpi rmp,'s' ; Speichern gewählt?
breq getpars ; geh zum Speichern
cpi rmp,'l' ; Lesen gewählt?
breq getparl ; geh zum Lesen
cpi rmp,'d' ; Default-Werte gewählt?
breq getpard ; Setze Default Werte
ldi ZH,HIGH(2*txtf); Zeiger auf Frequenzzeile
ldi ZL,LOW(2*txtf) ; im Menue
cpi rmp,'f' ; Frequenzeingabe gewählt?
breq getpar2 ; ja, hole Zahl
ldi ZH,HIGH(2*txtg); Geschwindigkeitseingabe
ldi ZL,LOW(2*txtg) ; Zeiger setzen
cpi rmp,'g' ; Geschwindigkeitseingabe gewählt?
breq getpar2 ; ja, hole Zahl
ldi ZH,HIGH(2*txtt) ; Zeiger auf Texteingabe
ldi ZL,LOW(2*txtt)
cpi rmp,'t' ; Texteingabe gewählt?
brne getpar0 ; Nein, gib dem User noch mal das Menue
getpar2: ; Hole eine Zahlen- oder Texteingabe in den Puffer
push rmp ; wird noch gebraucht (gewählter Menuepunkt)
rcall txch ; Echo char an SIO zurück
ldi rmp,chcr ; Mache neue Zeile
rcall txch
rcall txtext ; Gib den ausgewählten Menuetext aus
ldi XH,HIGH(srtx) ; Empfangspuffer auf Anfang
ldi XL,LOW(srtx)
getpar3:
rcall rxch ; Hole char von SIO
st x+,rmp ; in Puffer
out UDR,rmp ; Echo an SIO
cpi rmp,chcr ; Ende der Eingabe?
brne getpar3 ; Weiter mit Eingabe
clr rmp ; String Nullterminieren
st x,rmp
pop rmp ; Menuepunkt wieder vom Stapel holen
cpi rmp,'t' ; Texteingabe gewählt?
breq getpara ; Ja, schon fertig, gib die Parameter aus
push rmp ; Wird weiterhin gebraucht (Menuepunkt)
rcall lese16 ; ASCII-Zahl im Puffer in binär
; in R1:R0 umwandeln
pop rmp ; Menuepunkt wieder herstellen
brcs getpare ; Fehler in Zahl, Fehlermeldung ausgeben
cpi rmp,'f' ; Frequenz gewählt?
brne getparg ; Nein, Geschwindigkeit gewählt!
mov rmp,R1 ; Zahl zu groß?
cpi rmp,0x10 ; Frequenz > 4095 Hz?
brcc getparh ; Fehlermeldung Zahl zu groß
cpi rmp,0x01 ; Frequenz < 256 Hz?
brcs getpark ; Fehlermeldung Zahl zu niedrig
sts sfrq,R0 ; Zahl ok, übertragen
sts sfrq+1,R1
rjmp getpar0 ; Rechne Parameter neu aus und gebe aus
getparg: ; Neue Geschwindigkeit eingegeben
tst R1 ; Zahl <256?
brne getparh ; Nein, Fehlermeldung Zahl zu groß
mov rmp,R0
cpi rmp,201 ; Zahl >200?
brcc getparh ; Fehlermeldung Zahl zu groß
cpi rmp,10 ; Zahl <10?
brcs getpark ; Zahl zu niedrig
sts sbpm,R0 ; Zahl ok, übertragen
rjmp getpar0 ; Beginne Neu mit Berechnung und Ausgabe
getpars: ; Speichern der eingestellten Werte im EEPROM
rcall ewrite ; Alles übertragen
ldi ZH,HIGH(2*txteepw); Meldung ausgeben
ldi ZL,LOW(2*txteepw)
rcall txtext
rjmp getparb ; Menuepunkte ausgeben und weiter
getparl: ; Lesen der Werte aus dem EEPROM
rcall ecopy ; Alles ins SRAM übertragen
rjmp getpar0 ; Alle Parameter neu berechnen und weiter
getpard: ; Default-Werte setzen
ldi ZH,HIGH(sfrq) ; Zeiger auf Frequenz
ldi ZL,LOW(sfrq)
ldi rmp,LOW(cfrq) ; LSB Default-Frequenz setzen
st z+,rmp ; in SRRAM-Speicher
ldi rmp,HIGH(cfrq) ; MSB Default-Frequenz setzen
st z+,rmp ; in SRAM-Speicher
ldi rmp,cbpm ; Default-Geschwindigkeit
st z+,rmp ; in SRAM-Speicher
rcall getdeftext ;
rjmp getpar0 ; Alle Parameter neu berechnen und weiter
getpare: ; Fehlermeldung ausgeben
ldi ZH,HIGH(2*txtzahl) ; Fehler in Zahl
ldi ZL,LOW(2*txtzahl)
rcall txtext
rjmp getpara
getpark: ; Fehlermeldung ausgeben
ldi ZH,HIGH(2*txtklein) ; Zahl zu niedrig
ldi ZL,LOW(2*txtklein)
rcall txtext
rjmp getpara
getparh: ; Fehlermeldung ausgeben
ldi ZH,HIGH(2*txthoch) ; Zahl zu hoch
ldi ZL,LOW(2*txthoch)
rcall txtext
rjmp getpara
getdeftext: ; Default text in Speicher ab Z
ldi rmp,'<' ; Verkehrsanfang, eingefügt 2313=>8515
st z+,rmp
ldi rmp,10 ; Testtext in Speicher
mov R0,rmp ; in Zähler
getdeftext1:
ldi rmp,'P' ; Paris
st z+,rmp
ldi rmp,'A'
st z+,rmp
ldi rmp,'R'
st z+,rmp
ldi rmp,'I'
st z+,rmp
ldi rmp,'S'
st z+,rmp
ldi rmp,' '
st z+,rmp
dec R0
brne getdeftext1
sbiw ZL,1 ; Eins zurück
ldi rmp,'>'
st z+,rmp
ldi rmp,chcr ; Textpuffer mit Carriage Return
st z+,rmp
clr rmp ; und Nullterminator
st z,rmp ; entleeren
ret
;
; Warte auf char von der SIO mit Echo
;
rxch:
in rmp,USR ; Lese Control register
sbrs rmp,RXC ; Character vorhanden?
rjmp rxch ; Noch nicht, weiter warten
in rmp,UDR ; Lese character aud Datenregister
ret ; und zurück
;
; Sende text character in rmp an SIO mit Prüfung
;
txch:
push rmp ; Rette Zeichen auf Stapel
txch1:
in rmp,USR ; Senderegister leer?
sbrs rmp,UDRE ; Ist das UDRE-Bit gesetzt
rjmp txch1 ; Nein, weiter warten
pop rmp ; Hole Zeichen vom Stapel
out UDR,rmp ; Character senden
cpi rmp,chcr ; Nach Carriage Return noch ein
brne txch2 ; Linefeed?
ldi rmp,chlf ; auch den noch senden!
rcall txch
ldi rmp,chcr ; und Zeichen wieder herstellen
txch2:
ret
;
; Morsecode der ASCII-Zeichen 0x20 bis 0x5F
; unteres Byte = Code (0=Punkt, 1=Strich)
; oberes Byte = Anzahl Punkte/Striche
; Bit 7 = 1: Leerzeichen
;
morse:
; Zeichen 20 .. 2F
.DB 0b11100000,0b10000011 ; Blank
.DB 0b01000000,5 ; ! = Warten
.DB 0b01001000,6 ; "
.DB 0b11011000,5 ; # = ñ
.DB 0b01101000,5 ; $ = á, å
.DB 0b01000000,5 ; % = é
.DB 0b00000000,0 ; & = nicht benutzt
.DB 0b01111000,6 ; '
.DB 0b10110000,5 ; (
.DB 0b10110100,6 ; )
.DB 0b00000000,0 ; * = nicht benutzt
.DB 0b00010100,6 ; + = Spruchende
.DB 0b11001100,6 ; ,
.DB 0b10000100,6 ; -
.DB 0b01010100,6 ; .
.DB 0b10010000,5 ; /
;Zeichen 30 .. 3F
.DB 0b11111000,5 ; 0
.DB 0b01111000,5 ; 1
.DB 0b00111000,5 ; 2
.DB 0b00011000,5 ; 3
.DB 0b00001000,5 ; 4
.DB 0b00000000,5 ; 5
.DB 0b10000000,5 ; 6
.DB 0b11000000,5 ; 7
.DB 0b11100000,5 ; 8
.DB 0b11110000,5 ; 9
.DB 0b11100000,6 ; :
.DB 0b10101000,6 ; ;
.DB 0b10101000,5 ; < = Verkehrsanfang
.DB 0b10001000,5 ; =
.DB 0b01010000,5 ; > = Verkehrsende
.DB 0b00110000,6 ; ?
;Zeichen 40 .. 4F
.DB 0b11110000,4 ; @ = ch
.DB 0b01000000,2 ; A
.DB 0b10000000,4 ; B
.DB 0b10100000,4 ; C
.DB 0b10000000,3 ; D
.DB 0b00000000,1 ; E
.DB 0b00100000,4 ; F
.DB 0b11000000,3 ; G
.DB 0b00000000,4 ; H
.DB 0b00000000,2 ; I
.DB 0b01110000,4 ; J
.DB 0b10100000,3 ; K
.DB 0b01000000,4 ; L
.DB 0b11000000,2 ; M
.DB 0b10000000,2 ; N
.DB 0b11100000,3 ; O
;Zeichen 50 .. 5F
.DB 0b01100000,4 ; P
.DB 0b11010000,4 ; Q
.DB 0b01000000,3 ; R
.DB 0b00000000,3 ; S
.DB 0b10000000,1 ; T
.DB 0b00100000,3 ; U
.DB 0b00010000,4 ; V
.DB 0b01100000,3 ; W
.DB 0b10010000,4 ; X
.DB 0b10110000,4 ; Y
.DB 0b11000000,4 ; Z
.DB 0b01010000,4 ; [ = Ä
.DB 0b11100000,4 ; \ = Ö
.DB 0b00110000,4 ; ] = Ü
.DB 0b00000000,8 ; ^ = Irrung
.DB 0b00110100,6 ; _
morseende:
.DW morseende-morse ; Prüfzahl, muss 0x0040 sein
;
; Texte für die serielle Schnittstelle
; Hinweis: Die chk-Werte sind zum Überprüfen im Listing
; eingefügt. Es gibt einen Bug im AVR-Assembler von ATMEL,
; der zu falschen Adressen führt, wenn bestimmte Kombina-
; tionen von Byte-Konstanten verwendet werden. Dieser Bug
; ist seit zwei Jahren gemeldet und noch immer nicht besei-
; tigt! Teilweise sind die abenteuerlichen Konstruktionen
; in dieser Liste zur Umgehung dieses Bugs verwendet.
;
; Eingangsmeldung zu Beginn
txtid:
.DB chff,chcr
.DB "+---------------------------------+",chcr
.DB "| Morseprogramm (C)2002 by DG4FAC |",chcr
.DB "+---------------------------------+",chcr
.DB cnul,cnul
chk1:
.DW chk1 ; für Assembler Bug
; Text für Parameterliste
txtpar1:
.DB chcr,'E',"ingestellte Parameter:",chcr,'*'
txtf:
.DB "NF-Frequenz (256..4095 Hz) = ",cnul
chk2: ; Bug-Check
.DW chk2
txtpar2:
.DB " Hz ",chcr,'*'
txtg:
.DB "Geschwindigkeit (10..200 BpM) = ",cnul
chk3: ; Bug-Check
.DW chk3
txtpar3:
.DB " BpM",chcr,' ',"ccm = ",cnul,cnul
chk4: ; Bug-Check
.DW chk4
txtpar4:
.DB ", Ints (kurz) = ",cnul,cnul
chk5: ; Bug-Check
.DW chk5
txtpar5:
.DB ", Ints (lang) = ",cnul,cnul
chk6: ; Bug-Check
.DW chk6
txtpar6:
.DB chcr,'*'
txtt:
.DB "Text = ",cnul
chk7: ; Bug-Check
.DW chk7
txtcur:
.DB chcr,'=','>',cnul
chk8: ; Bug-Check
.DW chk8
txtmenue:
.DB "Einstellungen: f=NF-Frequenz, g=Geschwindigkeit,"
.DB " t=Text, s=Speichern,",chcr
.DB " l=Lesen, d=Default, ESC=Ende! ",chcr
.DB "(f,g,t,s,l,d,ESC) => ",cnul
chk9: ; Bug-Check
.DW chk9 ; Prüfzahl für Assembler-Bug
txtzahl:
.DB chcr,'F',"ehler in Ziffer oder Zahl bzw. Zahl zu gross!",cnul
chk10: ; Bug-Check
.DW chk10 ; Prüfzahl für Assembler-Bug
txtklein:
.DB chcr,'*',"* Zahl zu niedrig! **",cnul,cnul
chk11: ; Bug-Check
.DW chk11 ; Prüfzahl für Assembler-Bug
txthoch:
.DB chcr,'*',"* Zahl zu hoch! **",cnul,cnul
chk12: ; Bug-Check
.DW chk12 ; Prüfzahl für Assembler-Bug
txteepw:
.DB chcr,'P',"arameter ins EEPROM geschrieben.",chcr,cnul
chk13: ; Bug-Check
.DW chk13
;
; Copyright-Info
.DB "C(2)00 2ybD 4GAF C"
;
; Programm-Code Ende
;
; ******************************************
; * EEPROM-Inhalt mit Default beginnt hier *
; ******************************************
;
.ESEG
.ORG 0x0000
;
efrq:
; Die Default-NF-Frequenz
.DW cfrq
ebpm:
; Die Default-Geschwindigkeit in BpM
.DB cbpm
etxt:
; Dieser Text wird zu Beginn ausgegeben
.DB "hello!"
.DB chcr,cnul
etxte:
;
; Copyright-Info
;
.DB "(C)2002 by DG4FAC"
;
; Ende des EEPROM-Segmentes
;
©2002 by Gerhard Schmidt, DG4FAC
Webseite mit den Beiträgen:
http://www.avr-asm-tutorial.net/cq-dl/index.html
Benutzung, Kopie und Weiterverbreitung der Seiten zulässig, solange die Copyright-Angaben im Text bleiben.