;******************************************************************************
;** Serielle Schnittstelle, voll gepufferte E/A, „halbes“ XON/XOFF-Protokoll **
;******************************************************************************
.equ CPUCLK =8000000
.equ BAUDRATE =9600
.equ OBUFLEN =16 ;Ausgabepuffer-Größe
.equ IBUFLEN =8 ;Eingabepuffer-Größe
;.equ XON_THRESHOLD =2 ;Schwelle für Senden von XON
;.equ XOFF_THRESHOLD =IBUFLEN-4 ;Schwelle für Senden von XOFF
.equ XON =0x11 ;^Q
.equ XOFF =0x13 ;^S
.set ubr =(CPUCLK/16/BAUDRATE)-1 ;Baudraten-Register-Wert (12 bit)
.dseg
obuf: .byte OBUFLEN ;Ausgabepuffer
ibuf: .byte IBUFLEN ;Eingabepuffer
.def obufrd =r10 ;2 Zeiger in Ausgabepuffer
.def obufwr =r11
.def ibufrd =r12 ;2 Zeiger in Eingabepuffer
.def ibufwr =r13
.def uflags =r14 ;Flag-Bits: Bit0=XOFF
.def inchar =r25 ;Letztes gelesenes Zeichen/Byte
.cseg
;** ISR Zeichenausgabe
isend: cbi UCSRB,UDRIE ;UDRIE=0, „lokale“ Interrupts gesperrt
sei ;globale Interrupts frei
push r16
push XL
mov XL,obufrd ;UDR=*obufrd++;
ld r16,X+
out UDR,r16
ldi r16,obuf+OBUFLEN ;if (obufrd==obuf+OBUFLEN) obufrd=obuf;
cpse XL,r16
rjmp is1
ldi XL,obuf
is1: mov obufrd,XL
cpse obufrd,obufwr ;if (obufrd!=obufwr) UDRIE=1;
sbi UCSRB,UDRIE ; // weitere Zeichen
pop XL
pop r16
reti
;** ISR Zeicheneingabe mit direkter XON/XOFF-Behandlung
irecv: cbi UCSRB,RXCIE ;RXCIE=0, „lokale“ Interrupts gesperrt
sei ;globale Interrupts frei
push r16
in r16,SREG
push r16
in r16,UDR ;temp=UDR;
cpi r16,XOFF ;if (temp==XOFF) {
brne ir1
cbi UCSRB,UDRIE ; UDRIE=0; // Senden einstellen
set ; uflags.xoff=1;
rjmp ir2 ; return;
ir1: ;}
cpi r16,XON ;if (temp==XON) {
brne ir3
cpse obufwr,obufrd ; if (obufrd!=obufwr) UDRIE=1;
sbi UCSRB,UDRIE ; // weiter senden
clt ; uflags.xoff=0;
ir2: bld uflags,0
rjmp ire ; return;
ir3: ;}
push XL
mov XL,ibufwr ;*ibufwr++=UDR
st X+,r16
cpi XL,ibuf+IBUFLEN ;if (ibufwr==ibuf+IBUFLEN) ibufwr-=IBUFLEN
brne ir4
subi XL,IBUFLEN
ir4: mov ibufwr,XL
cp ibufrd,ibufwr ;if (ibufrd==ibufwr) { // Überlauf
brne ir6 ;bei Überlauf das älteste Zeichen löschen
mov XL,ibufrd
inc XL ; ibufrd++;
cpi XL,ibuf+IBUFLEN ; if (ibufrd==ibuf+IBUFLEN) ibufrd-=IBUFLEN;
brne ir5
subi XL,IBUFLEN
ir5: mov ibufrd,XL
ir6: pop XL
ire: ; }
pop r16
out SREG,r16
pop r16
sbi UCSRB,RXCIE ;RXCIE=1, „lokale“ Interrupts wieder zulassen
reti
spac: ldi r16,' ' ;Leerzeichen ausgeben
;** void putc(char r16)
;VR: XL
putc: mov XL,obufwr ;X=obufwr
st X+,r16 ;*X++=r16; //diese Stelle ist stets frei
cpi XL,obuf+OBUFLEN ;if (X==obuf+OBUFSIZE) X-=OBUFSIZE;
brne pu1
subi XL,OBUFLEN
pu1: cp XL,obufrd ;while (X==obufrd) sleep(); //solange voll
brne pu2
sleep
rjmp pu1
pu2: mov obufwr,XL ;obufwr=X; // nicht mehr voll, vorschieben
sbrs uflags,0
sbi UCSRB,UDRIE ;ISR anschubsen, wenn kein XOFF
ret
;** bool[NZ] peekc(void) ;setzt „inchar“
;VR: XL
cp ibufwr,ibufrd
breq pe2 ;Z=1, kein Zeichen vorhanden
mov XL,ibufrd
ld inchar,X+
cpi XL,ibuf+IBUFLEN
brne pe1
subi XL,IBUFLEN
pe1: clz ;Z=0, Zeichen vorhanden
pe2: ret
Detected encoding: UTF-8 | 0
|