Skrivning av första assembler kod! kört fast

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
mr_fatise
Inlägg: 93
Blev medlem: 22 september 2004, 03:24:49

Skrivning av första assembler kod! kört fast

Inlägg av mr_fatise »

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
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

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"
mr_fatise
Inlägg: 93
Blev medlem: 22 september 2004, 03:24:49

Inlägg av mr_fatise »

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"
Ahha, tackar.. där löste du några grynner jag ståt och funderat på ett tag.
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.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> 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
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

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.
mr_fatise
Inlägg: 93
Blev medlem: 22 september 2004, 03:24:49

Inlägg av mr_fatise »

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 :shock:

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
Om nån tycker det är kul att hjälpa en nybörjare så kommentera gärna/ge förslag...
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

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.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> 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 ?? :-)
mr_fatise
Inlägg: 93
Blev medlem: 22 september 2004, 03:24:49

Inlägg av mr_fatise »

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?

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
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!
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> 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.
mr_fatise
Inlägg: 93
Blev medlem: 22 september 2004, 03:24:49

Inlägg av mr_fatise »

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.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Att dela med 2 är väldigt enkelt.

Ändra bara :

Kod: Markera allt

   movf    ADRESH,W      ;Lagrar värdet i W till Result
   movwf   Result
till:

Kod: Markera allt

   bcf    STATUS, C
   rrl    ADRESH,W      ;Lagrar värdet i W till Result
   movwf   Result
"clrf ADRESH" är onödigt och kan plockas bort...
mr_fatise
Inlägg: 93
Blev medlem: 22 september 2004, 03:24:49

Inlägg av mr_fatise »

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.

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
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.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> 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.
mr_fatise
Inlägg: 93
Blev medlem: 22 september 2004, 03:24:49

Inlägg av mr_fatise »

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.

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
Gärna kommentarer vad det än gäller.. knackar vidare så länge! De går ju inte fort kan ja lova.
Skriv svar