; ******************************************************** ; * CW.asm gibt Morsezeichen aus, die im EEPROM-Speicher * ; * gespeichert sind und die über die serielle Schnitt- * ; * stelle des STK200-Boards eingegeben werden. Die Aus- * ; * gabe der NF erfolgt an PD5. Baudrate 9k6. Takt 4 MHz.* ; * AVR AT90S8515. Programm (C)2002 by DG4FAC G.Schmidt * ; * Version 0.1-200 vom 12.1.2002 * ; * Bugs und Dankschreiben an info@avr-asm-tutorial.net * ; ******************************************************** ; .NOLIST .INCLUDE "C:\avrtools\appnotes\8515def.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 = 4000000 ; Quarzfrequenz des AVR .EQU fbd = 9600 ; Baudrate des UART .EQU pctrl = PORTB ; Control-Port für RTS/CTS (nicht benutzt) .EQU pdrr = DDRB ; Datenrichtungsregister Controlport .EQU brts = PB2 ; RTS bit Input (beim STK nicht benutzt) .EQU bcts = PB4 ; CTS bit Output (beim STK nicht benutzt) .EQU pnfd = DDRD ; Port für Richtung NF-Ausgabe (8515) .EQU doc1 = PD5 ; NF-Ausgabe über OC1B-Pin (8515) ; ; 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 8515 ; 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 A reti ; Timer 1 Compare Match B reti ; Timer 1 Overflow, nicht benutzt reti ; Timer 0 Overflow, nicht benutzt reti ; SPI STC, nicht benutzt rjmp iurxc ; UART Rx Complete reti ; UART Tx data register empty, nicht benutzt reti ; UART Tx All sent, nicht benutzt reti ; ANA_COMP, 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 EEARH,YH ; Leseadresse im EEPROM out EEARL,YL ; 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 EEARH,XH ; Schreibadresse im EEPROM einstellen out EEARL,XL 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 XH,$02 ; 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 = ccm / 200 ; 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 4 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 ; rcall txreg ; Debug-Code!!! mov rcmh,R7 ; Ergebnis in Speicher rcmh:rcml mov rcml,R6 ldi rmp,HIGH(cint) ; Konstante für Anzahl Ints mov R1,rmp ; bei 4 MHz und Teiler 200: 1250 ldi rmp,LOW(cint) mov R0,rmp lds R4,sfrq ; Mal NF-Frequenz in Hz lds R5,sfrq+1 rcall mul16 ; Multplizieren 16 Bit * 16 Bit ; rcall txreg ; Debug code!!! 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 code!!! 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,HIGH(RAMEND) ; Init stack pointer im SRAM out SPH,rmp ldi rmp,LOW(RAMEND) out SPL,rmp 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 pnfd,doc1 ; Ausgabe Pin OC1B=PD5 auf Ausgang (8515) 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? brne getpar1a rjmp getpars ; geh zum Speichern getpar1a: cpi rmp,'l' ; Lesen gewählt? brne getpar1b rjmp getparl ; geh zum Lesen getpar1b: cpi rmp,'d' ; Default-Werte gewählt? brne getpar1c rjmp getpard ; Setze Default Werte getpar1c: cpi rmp,'x' ; Testtext gewählt? brne getpar1d rjmp getparx getpar1d: ldi ZH,HIGH(2*txtf); Zeiger auf Frequenzzeile ldi ZL,LOW(2*txtf) ; im Menue cpi rmp,'f' ; Frequenzeingabe gewählt? brne getpar1e rjmp getpar2 ; ja, hole Zahl getpar1e: ldi ZH,HIGH(2*txtg); Geschwindigkeitseingabe ldi ZL,LOW(2*txtg) ; Zeiger setzen cpi rmp,'g' ; Geschwindigkeitseingabe gewählt? brne getpar1f rjmp getpar2 ; ja, hole Zahl getpar1f: 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 ; Default-text in Speicher 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 getparx: ; Test-Text ausgeben (nur in der STK-Version!) ldi XH,HIGH(srtx) ; Zeiger X auf SRAM-Text ldi XL,LOW(srtx) ldi ZH,HIGH(2*tsttext) ; Zeiger Z auf Testtext ldi ZL,LOW(2*tsttext) getparx1: lpm ; Lese Zeichen st x+,R0 ; Zeichen in SRAM-Puffer adiw ZL,1 ; nächstes Zeichen tst R0 ; Zeichen eine Null? brne getparx1 ; weiter mit Zeichen rjmp getpara ; fertig 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 ; eingefügt bis hier 2313=>8515 ; ; 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 ; # = ~n .DB 0b01101000,5 ; $ = á, °a .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 ; ; Testtext, nur in der STK-Version implementiert! tsttext: .DB "",chcr,cnul ChkT: .DW ChkT ; ; 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, x=Test, ESC=Ende! ",chcr .DB "(f,g,t,s,l,d,x,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 ;