Skrivning av första assembler kod! kört fast
Skrivning av första assembler kod! kört fast
Håller på att försöka knåpa ihop min egna första kod. Har tidigare bara labbat med lite exempelkoder, klipt o klistrat lite och fått ett hum hur de fungerar. Processorn är en 16F876A
Har förtillfället en tempsignal med lite simpel elektronik för att kunna kalibrera nolla samt spann. 0-100C och nu kalibrarad för 0-4volt in på processorn. Ut från processorn sitter ICM7211 som i sin tur ska skriva ut värdet.
Håller på o läser för fult men jag har kört fast vet inte alls hur jag ska börja skriva, nån som har lite tips o info för att överhuvudtaget komma igång?
Har kommit fram till följande inom själva A/D delen iaf:
ADCON0 **000101 ; Channel0 AN0, AD igång samt körning.
ADCON1 ***01110 ; AN0 analog, resterande I/O
Har förtillfället en tempsignal med lite simpel elektronik för att kunna kalibrera nolla samt spann. 0-100C och nu kalibrarad för 0-4volt in på processorn. Ut från processorn sitter ICM7211 som i sin tur ska skriva ut värdet.
Håller på o läser för fult men jag har kört fast vet inte alls hur jag ska börja skriva, nån som har lite tips o info för att överhuvudtaget komma igång?
Har kommit fram till följande inom själva A/D delen iaf:
ADCON0 **000101 ; Channel0 AN0, AD igång samt körning.
ADCON1 ***01110 ; AN0 analog, resterande I/O
För att ladda in värdet i registerna:
Kod: Markera allt
movlw b'00000101' ;mov(e) l(iteral into)W = "ladda in ett fast värde i W"
movwf ADCON0; mov(e) W (to) f(ile) = "spara W i en minnesposition"
movlw b'00001110' ;mov(e) l(iteral into)W = "ladda in ett fast värde i W"
movwf ADCON1; mov(e) W (to) f(ile) = "spara W i en minnesposition"
Ahha, tackar.. där löste du några grynner jag ståt och funderat på ett tag.Icecap skrev:För att ladda in värdet i registerna:Kod: Markera allt
movlw b'00000101' ;mov(e) l(iteral into)W = "ladda in ett fast värde i W" movwf ADCON0; mov(e) W (to) f(ile) = "spara W i en minnesposition" movlw b'00001110' ;mov(e) l(iteral into)W = "ladda in ett fast värde i W" movwf ADCON1; mov(e) W (to) f(ile) = "spara W i en minnesposition"
med kommandot "movlw" för jag in det i ett typ av virtuellt värde. Det värdet tar jag sedan och för in i registret?
Finns det nån länk eller likande där man kan se nån funktion för kommandona? Hittar inget i databladet för prollen.
> med kommandot "movlw" för jag in det i ett typ av virtuellt värde.
Absolut ingenting "virtuellt" här !
Kommandot MOVLW laddar värdet i kommandot till W registret. Inget annat.
> Finns det nån länk eller likande där man kan se nån funktion för kommandona?
I databladet.
> Hittar inget i databladet för prollen.
Konstigt, vad innehåller kapitel "15.0 INSTRUCTION SET SUMMARY"
i *din* kopia av databladet ?
Jag skulle även rekomendera " Instruction Set - PICmicro Mid-Range MCU Family".
Lite utförligare beskrivningar av instruktionerna med fler exempel än i databladen.
Klicka på "Reference Manuals" på produktsidan för processorn.
Kolla nästan i botten av listan !
Eller : http://ww1.microchip.com/downloads/en/D ... 31029a.pdf
Absolut ingenting "virtuellt" här !
Kommandot MOVLW laddar värdet i kommandot till W registret. Inget annat.
> Finns det nån länk eller likande där man kan se nån funktion för kommandona?
I databladet.
> Hittar inget i databladet för prollen.
Konstigt, vad innehåller kapitel "15.0 INSTRUCTION SET SUMMARY"
i *din* kopia av databladet ?
Jag skulle även rekomendera " Instruction Set - PICmicro Mid-Range MCU Family".
Lite utförligare beskrivningar av instruktionerna med fler exempel än i databladen.
Klicka på "Reference Manuals" på produktsidan för processorn.
Kolla nästan i botten av listan !
Eller : http://ww1.microchip.com/downloads/en/D ... 31029a.pdf
Läs också om avsnittet om AD'n, man kan inte aktivera och starta omvandling samtidigt. Du måste läsa datablad hur motbjudande det än kan kännas och hur ivrig Du än är att komma igång snabbt. Inte förän Du vet vad Du gör och varför Du gör det går det attfå till ett fungerande program. Tiden det tar att läsa sparar Du in mångdubbelt och dessutom finns chansen att resultatet kan bli bra.
Kanske bör flyttas till projekttråden?
Hur som, tack så mycket för hjälpen... kan behövas bara en liten knuff när man kör fast, även om de nu stod i databladet
Har försökt nu så gott de går, några rader blev de... sen om de e rätt eller ej!
Om nån tycker det är kul att hjälpa en nybörjare så kommentera gärna/ge förslag...
Hur som, tack så mycket för hjälpen... kan behövas bara en liten knuff när man kör fast, även om de nu stod i databladet

Har försökt nu så gott de går, några rader blev de... sen om de e rätt eller ej!
Kod: Markera allt
Start
org 0x000 ;Vet inte vad nån av dessa tre rader gör!
goto Start ;
org 0x004 ;
bcf STATUS,RP0 ;bank 1
bcf STATUS,RP1
clrf PORTA
bsf STATUS, RP0
movlw h'B5'
movwf ADCON1 ;sätter RA0 till analog in
movlw h'01'
movwf TRISA ;sätter RA1-5 till digitala ut
movlw b'0100001' ;Fosc/8, A/Dchannel0, A/D=On
movwf ADCON0
org 0x000 anger "Originate" på adress 000 (0x först betyder hexadecimal notering), alltså startadress.
0x004 anger interrupt-rutinens adress och använder du inte den kan du skippa 'goto' och org 0x004. Observera också att 'goto Start' medför att programmet konstant vill starta om programmet, kommandot betyder ju 'gå till punkten som heter "Start"'
Sedan bör du använda 'banksel' istället för att fibbla med RP0 & RP1.
Exempel:
banksel PORTA
clrf PORTA
banksel ADCON1
movlw h'B5'
.... osv.
Sodjan kommer nog att berätta en del om relativt adresserings mode men det är iaf en start här.
0x004 anger interrupt-rutinens adress och använder du inte den kan du skippa 'goto' och org 0x004. Observera också att 'goto Start' medför att programmet konstant vill starta om programmet, kommandot betyder ju 'gå till punkten som heter "Start"'
Sedan bör du använda 'banksel' istället för att fibbla med RP0 & RP1.
Exempel:
banksel PORTA
clrf PORTA
banksel ADCON1
movlw h'B5'
.... osv.
Sodjan kommer nog att berätta en del om relativt adresserings mode men det är iaf en start här.
> org 0x000 ;Vet inte vad nån av dessa tre rader gör!
> goto Start ;
> org 0x004 ;
ORG är ett "assembler directive". Om du inte redan har gjort det, så bör du
ladda ner "MPASM/MPLINK User's Guide" (från samma sida där du laddade
ner MPLAB). I kapitel 4.50 på sidan 100 i manueln.
GOTO är en "vanlig" assembler instruktion och beskrivs i (t.ex) databladet.
I detta fall hoppar GOTO till en label "Start". Och eftersom labeln "Start" ligger
direkt innan så kommer programmet aldrig längre än så här...
Som Icecap noterade, används BANKSEL.
Se MPASM manualen kapitel 4.5 på sidan 50.
Sedan,
> movlw h'B5'
> movwf ADCON1 ;sätter RA0 till analog in
Ovanstående är inte *fel*, och det fungerar antagligen, men...
Eftersom ADCON1 består av olika bitar med lite olika funktion så är det
i allmänhet mer tydligt om man gör så här :
> movlw b'10110101'
> movwf ADCON1 ;sätter RA0 till analog in
Det gör det lättare att stämma av mot databladet att rätt bitar är satta.
Detta gäller generellt alla register som består olika bitar med lite olika funktion.
Däremot register som t.ex TMR1 (d.v.s registret som innehåller "räknaren"
för Timer 1) så är det mer logiskt att köra med hex (eller decimala) värden.
> movlw b'0100001' ;Fosc/8, A/Dchannel0, A/D=On
Det är bara 7 bitar i det binära värdet. Det är möjligt att det är rätt ändå,
men för att läsaren ska slippa fundera över vilken ända som fylls på med
en extra "0" så är det bäst att ange alla 8 bitarna direkt.
> Om nån tycker det är kul att hjälpa en nybörjare så kommentera gärna/ge förslag...
Finns det något roligare ??
> goto Start ;
> org 0x004 ;
ORG är ett "assembler directive". Om du inte redan har gjort det, så bör du
ladda ner "MPASM/MPLINK User's Guide" (från samma sida där du laddade
ner MPLAB). I kapitel 4.50 på sidan 100 i manueln.
GOTO är en "vanlig" assembler instruktion och beskrivs i (t.ex) databladet.
I detta fall hoppar GOTO till en label "Start". Och eftersom labeln "Start" ligger
direkt innan så kommer programmet aldrig längre än så här...
Som Icecap noterade, används BANKSEL.
Se MPASM manualen kapitel 4.5 på sidan 50.
Sedan,
> movlw h'B5'
> movwf ADCON1 ;sätter RA0 till analog in
Ovanstående är inte *fel*, och det fungerar antagligen, men...
Eftersom ADCON1 består av olika bitar med lite olika funktion så är det
i allmänhet mer tydligt om man gör så här :
> movlw b'10110101'
> movwf ADCON1 ;sätter RA0 till analog in
Det gör det lättare att stämma av mot databladet att rätt bitar är satta.
Detta gäller generellt alla register som består olika bitar med lite olika funktion.
Däremot register som t.ex TMR1 (d.v.s registret som innehåller "räknaren"
för Timer 1) så är det mer logiskt att köra med hex (eller decimala) värden.
> movlw b'0100001' ;Fosc/8, A/Dchannel0, A/D=On
Det är bara 7 bitar i det binära värdet. Det är möjligt att det är rätt ändå,
men för att läsaren ska slippa fundera över vilken ända som fylls på med
en extra "0" så är det bäst att ange alla 8 bitarna direkt.
> Om nån tycker det är kul att hjälpa en nybörjare så kommentera gärna/ge förslag...
Finns det något roligare ??

Tackar tackar, nu faller fler och fler bitar på plats. Sista timmen igår förtörde jag nog mer än gjorde nytta. Har fixat till HEX till decimalt samt ändrat lite, knåpat om till banksel m.m Kanske tillomed blev rätt?
Nu borde jag ha själva värdet i binärt i "Result", dessvärre så ligger de väll två bitar kvar i "ADRESL" som jag inte vet vad ja ska göra med. Nöjer mig mer 8-bitars upplösning. Värdet i result borde nu va 0-255 och bör därmed delas med 2 för skalan 0-128 för att sedan kodas om till BCD.
Ja klurar vidare...
Tack och bock!
Kod: Markera allt
;Information Data
;PIC16F876A
;------inkludera definitioner----
#include <p16f876a.inc>
;-------Start--------------------
org 0x000
Result equ 0x20
Start
banksel PORTA ;Väljer rätt bank
clrf PORTA
banksel ADCON1 ;väljer rätt bank
movlw b'11001110'
movwf ADCON1 ;sätter RA0 till analog in
movlw b'00000001'
movwf TRISA ;sätter RA1-5 till digitala ut
movlw b'11000001' ;Frc A/Dchannel0 A/D=On
movwf ADCON0
bsf ADCON0,GO ;Kör A/DChannel0
Wait
btfsc ADCON0,GO ;Väntar på resultat
goto Wait
movf ADRESH,W ;Lagrar värdet i W till Result
movwf Result
clrf ADRESH
Ja klurar vidare...
Tack och bock!
> Har fixat till HEX till decimalt....
HEX till *binärt*, eller hur ?
Jag ser ingen uppenbart fel (har inte kollat alla inställningar mot
databladet).
En lite kosmetisk sak bara...
> org 0x000
> Result equ 0x20
Lägg gärna alla definitioner av variabler *innan* koden börjar.
Bitarna (de två lägsta) i ADRESL kan du strunta i *om* du inte behöver dom.
Förresten, kolla ADFM biten i ADCON1. Jag tror att du har den satt fel...
Sen har koden inget "slut", utan den kommer att starta om hela tiden.
HEX till *binärt*, eller hur ?
Jag ser ingen uppenbart fel (har inte kollat alla inställningar mot
databladet).
En lite kosmetisk sak bara...

> org 0x000
> Result equ 0x20
Lägg gärna alla definitioner av variabler *innan* koden börjar.
Bitarna (de två lägsta) i ADRESL kan du strunta i *om* du inte behöver dom.
Förresten, kolla ADFM biten i ADCON1. Jag tror att du har den satt fel...
Sen har koden inget "slut", utan den kommer att starta om hela tiden.
HEX till *binärt*, eller hur ?
Har du rätt i binärt ska de va... mycket ord o hålla i tungan.
Förresten, kolla ADFM biten i ADCON1. Jag tror att du har den satt fel...
En nybörjarmiss kanske, hehhe.. fixat!
Börjar bli lite fundersam på att dela värdet med två, verkar krångligare än ja trodde. Känns lite tarvligt o ändra skalan till 0-255 för att man inte lyckas dividera! Nåt sätt går de väll,
Projektet fortlöper... Känns som man har lämat start plattan och är en liten bit på väg iallfall.
Har du rätt i binärt ska de va... mycket ord o hålla i tungan.
Förresten, kolla ADFM biten i ADCON1. Jag tror att du har den satt fel...
En nybörjarmiss kanske, hehhe.. fixat!
Börjar bli lite fundersam på att dela värdet med två, verkar krångligare än ja trodde. Känns lite tarvligt o ändra skalan till 0-255 för att man inte lyckas dividera! Nåt sätt går de väll,
Projektet fortlöper... Känns som man har lämat start plattan och är en liten bit på väg iallfall.
Att dela med 2 är väldigt enkelt.
Ändra bara :till:
"clrf ADRESH" är onödigt och kan plockas bort...
Ändra bara :
Kod: Markera allt
movf ADRESH,W ;Lagrar värdet i W till Result
movwf Result
Kod: Markera allt
bcf STATUS, C
rrl ADRESH,W ;Lagrar värdet i W till Result
movwf Result
Har gjort lite små förändringar hårtvarumässigt. Hoppar över att använda mig av displaydrivaren
och kör ren BCD ut till de 3st 7segmentarna via PortB samt PortC. Skalan är graderad att visa 0-128C,
tror inte de är så stor ide att försöka öka upplösning pg.a den analoga signalen.
Inga större ändringar i koden. En divition med två är inlagd (Tack sodjan, här får man allt på ett silverfat).
Dessvärre har jag kört fast totalt i omvandlingen av det "binära" värdet i result till BCD
(ska ut på portB och portC är det tänkt). Kan man skriva nån typ av lista för alla möjliga värden ska sätta utgångarna Höga/Låga. Är ju bara 8-bit så de blir ju inte så många rader,
kanske inte effektivast dock.
Annars hitttade jag denna formel 8-bit binary to BCD Har försökt förstå vad som händer på 5år nivå utan resultat.
Fattar inte vart värdet hämtas och vart de skrivs ex.
och kör ren BCD ut till de 3st 7segmentarna via PortB samt PortC. Skalan är graderad att visa 0-128C,
tror inte de är så stor ide att försöka öka upplösning pg.a den analoga signalen.
Kod: Markera allt
;Information Data
;PIC16F876A
;------inkludera definitioner----
#include <p16f876a.inc>
;-------Start--------------------
org 0x000
Result equ 0x20
Start
banksel PORTA ;Väljer rätt bank
clrf PORTA
banksel ADCON1 ;väljer rätt bank
movlw b'11001110'
movwf ADCON1 ;sätter RA0 till analog in
movlw b'00000001'
movwf TRISA ;sätter RA1-5 till digitala ut
movlw b'11000001' ;Frc A/Dchannel0 A/D=On
movwf ADCON0
Kor ;---- Kör A/D omvanling---------
bsf ADCON0,GO ;Kör A/DChannel0
Wait
btfsc ADCON0,GO ;Väntar på resultat
goto Wait
bcf STATUS, C
rrl ADRESH,W ;Värdet divideras med 2, på nåt sätt :)
movwf Result
goto Kor
Dessvärre har jag kört fast totalt i omvandlingen av det "binära" värdet i result till BCD
(ska ut på portB och portC är det tänkt). Kan man skriva nån typ av lista för alla möjliga värden ska sätta utgångarna Höga/Låga. Är ju bara 8-bit så de blir ju inte så många rader,
kanske inte effektivast dock.
Annars hitttade jag denna formel 8-bit binary to BCD Har försökt förstå vad som händer på 5år nivå utan resultat.
Fattar inte vart värdet hämtas och vart de skrivs ex.
> Värdet divideras med 2, på nåt sätt 
På något sätt ??
Du bör nog försöka förstå denna operation, den är väldigt "basic".
Antag att ADRESH är '10000000' (d.v.s 128 decimalt).
Efter "rrl ADRESH,W " kommer W att innehålla '01000000' (d.v.s 64)
Något problem med det ?
Kodexemplen från PIClist.com är ofta "smarta" till gränsen till oläsliga.
Men för den som är intresserad så är det ofta väldigt intressant läsning.
Scott Dattalo (som skrev det du länkade till) är en av de 5-10 vassaste
PIC programmerarna och hans lösningar är alltid väldigt snygga och
matematiskt smarta.
Det snygga i just det exemplet är t.ex att det är "rak" kod utan loopar
och tar alltså alltid *samma tid* att köra igenom oavsett vilket värde
som konverteras. Ibland är det väldigt viktigt !
Ett enklare sätt är att först minska värdet med 100 så många gånger det
går (utan att det går under 0) för att få 100-tals siffran. Sedan minskas
resten med 10 så långt deet går på samma sätt för att få 10-tals
siffran. Resten efter det är entals-siffran. Tar lite längre tid med kan
vara lite enklare att förstå vad som händer...
Sedan behöver du en enkel tabell med 10 värden för att mappa 0-9
till motsvarande 7-seg koder.

På något sätt ??
Du bör nog försöka förstå denna operation, den är väldigt "basic".
Antag att ADRESH är '10000000' (d.v.s 128 decimalt).
Efter "rrl ADRESH,W " kommer W att innehålla '01000000' (d.v.s 64)
Något problem med det ?
Kodexemplen från PIClist.com är ofta "smarta" till gränsen till oläsliga.
Men för den som är intresserad så är det ofta väldigt intressant läsning.
Scott Dattalo (som skrev det du länkade till) är en av de 5-10 vassaste
PIC programmerarna och hans lösningar är alltid väldigt snygga och
matematiskt smarta.
Det snygga i just det exemplet är t.ex att det är "rak" kod utan loopar
och tar alltså alltid *samma tid* att köra igenom oavsett vilket värde
som konverteras. Ibland är det väldigt viktigt !
Ett enklare sätt är att först minska värdet med 100 så många gånger det
går (utan att det går under 0) för att få 100-tals siffran. Sedan minskas
resten med 10 så långt deet går på samma sätt för att få 10-tals
siffran. Resten efter det är entals-siffran. Tar lite längre tid med kan
vara lite enklare att förstå vad som händer...
Sedan behöver du en enkel tabell med 10 värden för att mappa 0-9
till motsvarande 7-seg koder.
Söndag och labrationen fortsätter. Har suttit länge på google utan att hitta en kod (binary to BCD) som jag förstår mig på hur den fungerar. Tänkte därför ge de ett försök att skapa en på helt egen hand. Har kommit en liten bit på vägen men postar upp iaf... Kanske kan ha turen att nån ryter till så sitter man sitta i skriva fel i timmar.
Gärna kommentarer vad det än gäller.. knackar vidare så länge! De går ju inte fort kan ja lova.
Kod: Markera allt
Omvandla1 ;100tal
movf Result, W ;flyttar värdet till W.
sublw 100 ;Drar av 100.
btfss W ;Är värdet possetivt. NEJ=hoppa över en instruktion
goto Positiv ;gå till positiv
addlw 100 ;lägg till 100, för att återfå samma värde
addwf Result ;tillbaka med ursprungligt värde i Result
goto Omvandla2
Positiv
movwf Result ;flyttar ursprungligt värde -100 till Result
movlw b'00010000' ;lägger till 1
movwf 0x30 ;i registret. Som då är i BCD för display 1.
Omvandla2 ;10tal
clrw ;töm W
Läs endast av värdet till W ;Låt det alltså ligga kvar i Result
dividdera med 10 ;har inte kommit på hur man gör.
movwf 0x30 ;läs värdet till PortC
;nu borde jag har BCDför 100 och 10 tal i 0x30
Omvandla3 ;Ental
movf Result, W ;Läs värdet till W
sublw 10 ;Dra av 10.
btfss W ;är värdet negativt? Ja=hoppa en instruktion
goto Omvandla3 ;upprepa OMvandla3
addlw 10 ;Gör värdet positivt
movwf 0x40 ;lägger värdet i registret