Resultat display
Jo, med rätt definition av "styrs" så kan man kanske säga det... 
Dock så skulle jag säga att ISR'en "styrs" från USART'en genom att det
ju är den som triggar själva interruptet...
Notera att många tror att en "räknare" är något speciellt. Man får
frågor som "hur skapar man en räknare". Frågan är felstäld. En
räknare är bara en variabel som vilken som helst, det är hur man
*hanterar* den som gör den till en "räknare". D.v.s att man t.ex
använder INCF och DECF för att öka/minska variablen/räknaren.
Alla variabler (oavsett om de används som "flaggor", "räknare" eller
något annat) allokeras precis som vanligt med RES.
> skapa en räknare som räknar upp vid varje spar av data och när den är full
Det är bufferten som blir "full", inte räknaren...
Ett tips angående räknaren. Det är enklare att låta den räkna från
4 -> 0 (än t.ex från 1 -> 5) eftersom det är enklare i koden att testa
en variabel för "=0" än för "=5". Kolla instruktionen DECFSZ så ser du
varför.

Dock så skulle jag säga att ISR'en "styrs" från USART'en genom att det
ju är den som triggar själva interruptet...
Notera att många tror att en "räknare" är något speciellt. Man får
frågor som "hur skapar man en räknare". Frågan är felstäld. En
räknare är bara en variabel som vilken som helst, det är hur man
*hanterar* den som gör den till en "räknare". D.v.s att man t.ex
använder INCF och DECF för att öka/minska variablen/räknaren.
Alla variabler (oavsett om de används som "flaggor", "räknare" eller
något annat) allokeras precis som vanligt med RES.
> skapa en räknare som räknar upp vid varje spar av data och när den är full
Det är bufferten som blir "full", inte räknaren...

Ett tips angående räknaren. Det är enklare att låta den räkna från
4 -> 0 (än t.ex från 1 -> 5) eftersom det är enklare i koden att testa
en variabel för "=0" än för "=5". Kolla instruktionen DECFSZ så ser du
varför.
Här är räknaren jag gjorde. Det är inte all kod men du kanske förstår.
EDIT:
Så ditt svar nu att det är enklare att räkna ner och kolla om den är =0
Kod: Markera allt
Counter RES 1
movwf RX_BUFFER ; Kopiera w till RX_BUFFER
incf Counter, 1 ; Öka räknaren med 1
btfss Counter, 5 ; Om räknaren är 5 skippa nästa inst.
goto if_esc
goto done
Så ditt svar nu att det är enklare att räkna ner och kolla om den är =0
Så här?
Kod: Markera allt
Counter RES 1
;********************
movlw d'4' ;Sätt räknare till 4
movwf Counter
if_esc
decf Counter, 1 ; EDIT: minska räknaren med 1
btfsc Counter ; Om räknaren är 0 skippa nästa inst.
goto if_esc
goto done
Precis, ungefär så. Ett par saker.
DECF och BTFSC kan kombineras i DECFSZ, kolla den !
Alltså något i stil med :
I main-loopen får man sedan kolla om buffer_full blir <> 0...
DECF och BTFSC kan kombineras i DECFSZ, kolla den !
Alltså något i stil med :
Kod: Markera allt
if_esc ; tecknet var ett <ESC> !
movlw d'4' ;Sätt räknare till 4
movwf Counter
clrf buffer_full ; Buffer är *inte* full...
goto done ; Avsluta ISR'en...
<här ska det vara kod för att hantera bufferten...>
decfsz Counter, f ; Minska räknaren med 1 och hoppa
; över nästa instruktion om den blev = 0.
goto done ; Räknaren är <> 0, avsluta ISR'en...
; Räknaren är alltså = 0 om vi hamnar här !
incf buffer_full ; Sätt buffer_full = 1 (den var ju = 0 innan...).
goto done ; Avsluta ISR'en...
done
retfie
Så nu är filen uppdaterad, tror att det här bör funka ej testat.
http://rodel.se/resultat_display.asm
http://rodel.se/resultat_display.asm
Är det den här du tänker på?
Så är det för att om det inte är 1B=ESC, så skall den läsa in igen och kolla.
>Jag ser inte heller hur du hanterar andra tecken än <ESC>,
Det har du rätt i tur att det finns fler ögon.
>d.v.s de som ska läggas in i bufferten.
Då måste buffern ökas från 5 till 6, eftersom det är 6 st. tecken som skall skickas till displayen.
Det saknas en pekare till bufferten?
Nu är inte jag me.
Kod: Markera allt
sublw h'1B' ; Om RX_DATA = 1B, så blir Z nu = 0
btfsc STATUS, Z ; D.v.s skippa nästa inst om Z = 0
goto datain ; Z=1, hoppa till datain.
>Jag ser inte heller hur du hanterar andra tecken än <ESC>,
Det har du rätt i tur att det finns fler ögon.
>d.v.s de som ska läggas in i bufferten.
Då måste buffern ökas från 5 till 6, eftersom det är 6 st. tecken som skall skickas till displayen.
Det saknas en pekare till bufferten?
Nu är inte jag me.
Senast redigerad av Stewal 8 februari 2008, 17:04:34, redigerad totalt 1 gång.
OK, det här med interruptstyrd kod, är lite av en AHA-upplevelse.
Du har inte riktigt haft den än...

> Så är det för att om det inte är 1B=ESC, så skall den läsa in igen och kolla.
Ja, men *nästa* gång som ISR'en anropas (d.v.s USART'en triggar ett interrupt).
Kom ihåg, ISR'en körs varje gång det kommer in ett tecken, du ska *inte*
ligga kvar där och vänta på nästa tecken ! Det är själva kärnan i en
interrupt styrd kod !
En gång till...
ISR'en hanterar *ETT* tecken i taget !! D.v.s varje gång den körs!
Så kolla vad du har fått in :
- Är det en <ESC>, sätt räknaren och gör inget mer (d.v.s hoppa till retfie).
(Visst, du bör också sätta pekaren till bufferten rätt...)
- Är det något annat *och* du håller på med ett paket, skriv till bufferten.
*Om* bufferten är full, sätt "full" flaggan.
Det kan alltså behövas en extra flagga som talar om att du har ett
aktivt paket "på gång". Men du kan kanske också klara dig utan den...
> Då måste buffern ökas från 5 till 6, eftersom det är 6 st. tecken som skall skickas till displayen.
Nej, den buffert vi talar om här, lagrar bara det som kommer på RS232 linjen.
Vad som ska till displayen är en helt annan sak, och det har ingenting med ISR'en att göra !
> > Det saknas en pekare till bufferten?
> Nu är inte jag me.
Alltså, när det kommer in ett tecken och du befinner dig i ett "paket", så
måste du veta var nästa tecken ska skrivas i bufferten.
Detta löser man enklast genom att sätta en variabel ("pekare") = RX_BUFFER.
Denna variabel/pekare ökas med ett för varje tecken. Den används
tillsammans med de två registren INDF och FSR. Se kap 2.4 i databladet
för exempel, "Indirect Addressing".
När du ska läsa och analysera bufferten senare så kan det vara enklare att
helt enkelt skriva RX_BUFFER, RX_BUFFER + 1, RX_BUFFER + 2 o.s.v.
Du har inte riktigt haft den än...


> Så är det för att om det inte är 1B=ESC, så skall den läsa in igen och kolla.
Ja, men *nästa* gång som ISR'en anropas (d.v.s USART'en triggar ett interrupt).
Kom ihåg, ISR'en körs varje gång det kommer in ett tecken, du ska *inte*
ligga kvar där och vänta på nästa tecken ! Det är själva kärnan i en
interrupt styrd kod !
En gång till...
ISR'en hanterar *ETT* tecken i taget !! D.v.s varje gång den körs!
Så kolla vad du har fått in :
- Är det en <ESC>, sätt räknaren och gör inget mer (d.v.s hoppa till retfie).
(Visst, du bör också sätta pekaren till bufferten rätt...)
- Är det något annat *och* du håller på med ett paket, skriv till bufferten.
*Om* bufferten är full, sätt "full" flaggan.
Det kan alltså behövas en extra flagga som talar om att du har ett
aktivt paket "på gång". Men du kan kanske också klara dig utan den...
> Då måste buffern ökas från 5 till 6, eftersom det är 6 st. tecken som skall skickas till displayen.
Nej, den buffert vi talar om här, lagrar bara det som kommer på RS232 linjen.
Vad som ska till displayen är en helt annan sak, och det har ingenting med ISR'en att göra !
> > Det saknas en pekare till bufferten?
> Nu är inte jag me.
Alltså, när det kommer in ett tecken och du befinner dig i ett "paket", så
måste du veta var nästa tecken ska skrivas i bufferten.
Detta löser man enklast genom att sätta en variabel ("pekare") = RX_BUFFER.
Denna variabel/pekare ökas med ett för varje tecken. Den används
tillsammans med de två registren INDF och FSR. Se kap 2.4 i databladet
för exempel, "Indirect Addressing".
När du ska läsa och analysera bufferten senare så kan det vara enklare att
helt enkelt skriva RX_BUFFER, RX_BUFFER + 1, RX_BUFFER + 2 o.s.v.
Du har en buffert med 5 (eller 4) positioner.
Du får in ett tecken via USART'en.
Detta ska in på "nästa" position i RX_BUFFER.
Så långt OK ?
För att veta var "nästa" position är så måste du ha något som
håller reda på var du är i RX_BUFFER (d.v.s från en körning av ISR'en
till nästa). Det är det pekaren gör.
När du har fått en <ESC> så sätter du pekaren = RX_BUFFER
(d.v.s den pekar på fösta positionen i RX_BUFFER).
För varje tecken som läggs in ökas pekaren med 1.
När pekaren är lika med RX_BUFFER+4 (eller RX_BUFFER+3 om du inte lagrar
<ESC>) så är bufferten slut (det ersätter den där första räknaren vi hade,
eller så kör du med båda, gör hur du vill...)
Rent praktiskt i koden så använder man INDF och FSR för att adressera
RX_BUFFER "indirekt".
Under inläsning av ett paket till RX_BUFFER så behöver du inte indirekt
adressering till något annat, så värder i FSR kan ligga kvar mellan ISR
anropen.
På vilken plats i koden ? Tja... Då du ska skriva till RX_BUFFER, sannolikt.
> Om man tittar på Icecap´s kod, så finns en buffer Rx_Buffer på 5 byte.
> Sen Rx_Input som jag mistänker är pekaren.
Precis, du gör i stort sätt likadant (rent logiskt, det skrivs naturligtsivs
lite annorlunda...)
Du får in ett tecken via USART'en.
Detta ska in på "nästa" position i RX_BUFFER.
Så långt OK ?
För att veta var "nästa" position är så måste du ha något som
håller reda på var du är i RX_BUFFER (d.v.s från en körning av ISR'en
till nästa). Det är det pekaren gör.
När du har fått en <ESC> så sätter du pekaren = RX_BUFFER
(d.v.s den pekar på fösta positionen i RX_BUFFER).
För varje tecken som läggs in ökas pekaren med 1.
När pekaren är lika med RX_BUFFER+4 (eller RX_BUFFER+3 om du inte lagrar
<ESC>) så är bufferten slut (det ersätter den där första räknaren vi hade,
eller så kör du med båda, gör hur du vill...)
Rent praktiskt i koden så använder man INDF och FSR för att adressera
RX_BUFFER "indirekt".
Under inläsning av ett paket till RX_BUFFER så behöver du inte indirekt
adressering till något annat, så värder i FSR kan ligga kvar mellan ISR
anropen.
På vilken plats i koden ? Tja... Då du ska skriva till RX_BUFFER, sannolikt.
> Om man tittar på Icecap´s kod, så finns en buffer Rx_Buffer på 5 byte.
> Sen Rx_Input som jag mistänker är pekaren.
Precis, du gör i stort sätt likadant (rent logiskt, det skrivs naturligtsivs
lite annorlunda...)
Får nog ta och bena ut vad dom olika registrena är.
Kan man säga att Rx_buffer är samma som FSR?
Får inte ihop det hur man sparar i Rx_buffer och samtidigt sätter pekaren.
Är det så här?
Vi säger att vi sparar allt som börjar på 1B för att klar göra det här.
Om det är 1B som kommit in från RCREG och vi vill spara den i Rx_buffer skrivar man så här då, varje gång det skall sparas i buffern?
Kan man säga att Rx_buffer är samma som FSR?
Får inte ihop det hur man sparar i Rx_buffer och samtidigt sätter pekaren.
Är det så här?
Vi säger att vi sparar allt som börjar på 1B för att klar göra det här.
Om det är 1B som kommit in från RCREG och vi vill spara den i Rx_buffer skrivar man så här då, varje gång det skall sparas i buffern?
Kod: Markera allt
movf rcreg, w
movwf rx_buffer
clrf indf
incf rx_buffer
btfss rx_buffer,5
goto done
incf buffer_full
done
retfie
Glöm inlägget innan.
Nu är en AHA, mycket nära skall bara verifiera.
Kan erkänna att jag trodde att "0x20" var ett värde, men det är ju en adress i FSR minnet.
Tog en stund att klura ut det.
Nu är en AHA, mycket nära skall bara verifiera.
Kan erkänna att jag trodde att "0x20" var ett värde, men det är ju en adress i FSR minnet.

Kod: Markera allt
MOVLW 0x20 ;initialize pointer
Om vi utgår ifrån att du har följande definierad:
Om din Main-loop då kollar om Rx_Input är noll kan den också kolla de andra data. OBS: datan som kommer in sparas på följande sätt: först inkommen står sist i buffern.
Edit: skrivit med en flasksugande 2½ månaders tjej på ena armen, garanti för rätt funktion ges inte!
Kod: Markera allt
BufLen equ 4 ; ESC sparas ju inte, den nollställer
ESC equ d'27'
Rx_Buffer res BufLen ; 4 bytes
Rx_Counter res 1
Incoming res 1
Sedan i ISR-delen där det är konstaterat att det har kommit en byte i RCREG:
movf RCREG,w ; Get incoming byte
movwf Incoming ; Save for later use
sublw ESC ; Compare with ESC
btfsc STATUS,Z ; Test if equal
goto ESC_Found ; Jump if it was an ESC
; Was not ESC, put it in buffer
movf Rx_Counter,f ; Get status
btfsc STATUS,Z ; Test if Zero-flag is set
goto Exit_ISR ; Leave, no more room in buffer
movf Rx_Counter,w ; Get the index
addlw Rx_Buffer,w ; Add address offset
movwf FSR ; Save result in FSR to index
movf Incoming,w ; Get the input
movwf INDF ; Save it in buffer
incf Rx_Counter,f ; Point on next location
movf Rx_Counter,f ; Check value of counter
btfss STATUS,Z ; Is Rx_Counter = 0?
goto Exit_ISR ; Jump if not...
...
här har 5 bytes blivit tagit emot, kolla om det är rätt data och flytt dom på plats om det är.
...
goto Exit_ISR ; Jump if not...
ESC_Found
movlw BufLen ; Reset count
movwf Rx_Counter ; Save it in correct location
Exit_ISR
Edit: skrivit med en flasksugande 2½ månaders tjej på ena armen, garanti för rätt funktion ges inte!
OK, vi tar enbart själva FSR/INDF hanteringen. (Tillkommer resten
i ISR'en som kollar efter <ESC> o.s.v. men det hade ganska bra
koll på, tror jag...
).
Först någonstans i början koden har du en RES som allokerar minne till bufferten :
(4'an kan lika vara en definierat konstant som i Icecap's exempel, det
är att föradra, speciellt om man vill använda "längden" senare i koden,
då är det bara ett ställe att ändra på om länden ska ändras...)
Detta allokerar (reserverer) 4 bytes i sekvens någonstans i minnet (GPR)
och ger symbolen RX_BUFFER ett värde som motsvarar adressen till *första*
positionen i RX_BUFFER.
(PS: Jag rekomenderar varm att du har MAP filen påslagen (MPLINK i
Project Setup-någonstans) så att du även kan se hur olika variabler är
allokerade i minnet. Inte för att man behöver veta adresserna, men det
ger lite mer förståelse för vad RES (tillsammans med MPLINK) gör).
Sen så ska vi låta registret FSR "peka" på första positionen i RX_BUFFER :
Notera, move *literal* to W, d.v.s själva värdet av *symbolen* "RX_BUFFER" !
*Inte* det som RX_BUFFER eventuellt innehåller !
Detta görs alltså någonstans då vi ska börja på ett nytt datablock efter en <ESC>...
Så där, nu "pekar" FSR mot första positionen av RX_BUFFER.
Nu, för varje tecken som du mottar (efter en <ESC>) så gör du i princip :
Notera alltså att då man skriver/läser INDF, så är det igentligen adressen
i FSR som man skriver/läser !
Nu är FSR ökad med ett och förberätt för nästa tecken som kommer in
til USART'en. På så sätt kommer varje tecken att hamna i "nästa"
position i RX_BUFFER.
Icecap har en lite annorlunda hantering där FSR värdet beräknas varje
gång. Det fungerar det också, men i detta fall räcker det med att
bara räkna upp det med 1 vid varje varv genom ISR'en. (Icecap's
metod är dock lite mer generell. Ofta har man antingen flera buffrar eller
har behov att t.ex skriva och läsa från olika positioner i samma buffert,
och då måste man spara undan FSR värdet mellan de olika accesserna...)
Tillkommer lite check av om/när 4 tecken är mottaget, o.s.v.
Men det har diskuterats i tidigare inlägg.
i ISR'en som kollar efter <ESC> o.s.v. men det hade ganska bra
koll på, tror jag...

Först någonstans i början koden har du en RES som allokerar minne till bufferten :
Kod: Markera allt
RX_BUFFER RES 4
är att föradra, speciellt om man vill använda "längden" senare i koden,
då är det bara ett ställe att ändra på om länden ska ändras...)
Detta allokerar (reserverer) 4 bytes i sekvens någonstans i minnet (GPR)
och ger symbolen RX_BUFFER ett värde som motsvarar adressen till *första*
positionen i RX_BUFFER.
(PS: Jag rekomenderar varm att du har MAP filen påslagen (MPLINK i
Project Setup-någonstans) så att du även kan se hur olika variabler är
allokerade i minnet. Inte för att man behöver veta adresserna, men det
ger lite mer förståelse för vad RES (tillsammans med MPLINK) gör).
Sen så ska vi låta registret FSR "peka" på första positionen i RX_BUFFER :
Kod: Markera allt
movlw RX_BUFFER
movwf FSR
*Inte* det som RX_BUFFER eventuellt innehåller !
Detta görs alltså någonstans då vi ska börja på ett nytt datablock efter en <ESC>...
Så där, nu "pekar" FSR mot första positionen av RX_BUFFER.
Nu, för varje tecken som du mottar (efter en <ESC>) så gör du i princip :
Kod: Markera allt
movf RCREG, w ; Hämta tecknet från USART'en till WREG
movwf INDF ; Skriv tecknet till aktuell position i RX_BUFFER.
incf FSR ; Öka "pekaren" med ett för nästa tecken...
i FSR som man skriver/läser !
Nu är FSR ökad med ett och förberätt för nästa tecken som kommer in
til USART'en. På så sätt kommer varje tecken att hamna i "nästa"
position i RX_BUFFER.
Icecap har en lite annorlunda hantering där FSR värdet beräknas varje
gång. Det fungerar det också, men i detta fall räcker det med att
bara räkna upp det med 1 vid varje varv genom ISR'en. (Icecap's
metod är dock lite mer generell. Ofta har man antingen flera buffrar eller
har behov att t.ex skriva och läsa från olika positioner i samma buffert,
och då måste man spara undan FSR värdet mellan de olika accesserna...)
Tillkommer lite check av om/när 4 tecken är mottaget, o.s.v.
Men det har diskuterats i tidigare inlägg.