Pic från början

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

OK, *den* funktionen... :-)

Det ät inte bara MAX232 kretsen som används, utan även en del av programvaran i den 16F629A som sitter på Wisp628 samt en funktion i den programvara som används på PCn. Notera dock att just *denna* funktion inte blev portad från XWisp -> XWisp2, den ansågs inte som speciellt intressant.

Jag tror att Rob Hamerling (www.robh.nl) som skrev XWisp2 (eller, för att vara exakt, jag skrev den första porten till Windows...), skriver något om detta i readme filen till XWisp2...

Jag har själv aldrig använt den och inte funderat mer på det.
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Trött på pic:n

Inlägg av frejo »

Nu börjar jag allvarligt bli lite trött på pic:n, om det nu inte är jag som gör fel men kan inte se något fel i detta:

Håller på och försöker styra en hitachi lcd från pic:n, port a används till att styra kontrollbitarna.
Innan jag skriver ett tecken till displayen vill jag sätta den i datamode och sen sätta E hög så att den tar emot datan, har skrivit det så här:
bsf PORTA, RA0 ; data mode
bsf PORTA, RA2 ; LCD E-line high

Det vägrade dock dungera. Nu efter 6 timmars debuggande kan jag konstatera att efter den första instruktionen är PORTA 00000001, efter den andra blir den 00000100, dvs den andra bsf instruktionen clearar bit 0, det måste väl ändå vara en bugg? kan inte hitta nånstans att en bitset ska cleara bitar...

När jag istället kör
movlw 'b00000101'
movwf PORTA

Fungerar det alldeles ypperligt...

edit:
märkte just att
bsf LATA, RA0 ; data mode
bsf LATA, RA2 ; LCD E-line high

fungerar...
Hur kommer det sig att en bsf på PORTA clearar vissa bitar och inte en bsf på LATA?

edit2:
ett nytt problem uppstod när jag började använda LATA, det går bra att köra bsf på LATA, men bcf fungerar inte alls.
Vad är detta? ska man vara tvungen att använda ett register för att sätta bitar och ett annat för att cleara bitar?
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

:-)

Det hela ser ut som det vanliga read-modify-write problemet.

Notera att en BSF/BCF operation innebär tre faser. Först läses *hela* porten, sedan ändras den bit man har pekat ut, sist skrivs alla 8 bitarna tillbaka till porten. Det du gör är att först sätta en bit, sedan direkt en annan. Om det nu är så att den första biten är beslastad (med t.ex en viss kapacitans), så kanske den inte har hinnit bli hög innan porten läses igen i det andra BSF kommandot.

Det finns flera sätt att komma runt detta problem :
- Sätt in ett par NOP mellan de två varje BSF/BCF.
- Använd ett "shadow" register.
- Använd LATx registret.

Generellt sätt, bör man inte göra två eller flera BSF/BCF operationer mot *samma* port direkt efter varandra. Det är upplagt för problem, kanske inte märks direkt, men senare när t.ex produkten har hamnat på ett mönsterkort med andra elektriska egenskaper. Om man vill vara riktigt säker skall man *aldrig* gör BSF/BCF direkt mot PORTx registren.

Tyvärr är inte databladet helt tydligt på denna punkt, men det är *inte* en bugg...

> När jag istället kör
> movlw 'b00000101'
> movwf PORTA

Som förväntat.

Prova gärna också med 2-3 NOP's mellan de två BSF.

> märkte just att
> bsf LATA, RA0 ; data mode
> bsf LATA, RA2 ; LCD E-line high

Japp, och orsaken till det framgår av databladet.
LATx är "output latchen", medan PORTx läser från *pinnarna*.

> ett nytt problem uppstod när jag började använda LATA, det går bra
> att köra bsf på LATA, men bcf fungerar inte alls.

Kod exempel !
Vad betyder "fungerar inte alls" ???
Användarvisningsbild
Logan
Inlägg: 630
Blev medlem: 5 januari 2005, 21:31:53
Ort: Jönköping
Kontakt:

Inlägg av Logan »

ojoj, redig bra tråd, denna hamlar på Mina favoriter :D
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

En liten kod-kommentar för att underlätta läsbarheten och framtida underhåll...

Detta :

Kod: Markera allt

bsf LATA, RA0 ; data mode
bsf LATA, RA2 ; LCD E-line high
kan gärna skrivas så här. Först några definitioner först i koden:

Kod: Markera allt

#define LCD_S    LATA, 0
#define LCD_E    LATA, 1
Sedan:

Kod: Markera allt

bsf LCD_S
bsf LCD_E
behövs inte några line-comments på dessa rader, de talar ju för sig själva... :-)

Fördelen är att man kan ha flera ställen i koden där man hanterar LCD_S och LCD_E, om man flyttar dessa till andra pinnar så är det bara ett ställe att ändra på. Genm att samla alla sina pin-definitioner på ett ställe (t.ex i en #include fil), så får man även direkt en dokumentation av hur pinnarna används...
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Jo så hade jag faktiskt gjort, men skrev om det innan jag postade i tron att det skulle bli lättare att tolka:

#define LCD_DATA PORTD
#define LCD_DATA_TRIS TRISD
#define LCD_CTRL PORTA
#define LCD_CTRL_TRIS TRISA
#define LCD_RS 0
#define LCD_RW 1
#define LCD_E 2

angående bcf så var det detta som inte fungerade:

Kod: Markera allt

LcdPutChar
	movwf	LCD_TEMP			; gets the character to send
	call	LcdBusy				; make sure lcd is ready
	movf	LCD_TEMP,W	
	movwf	LCD_DATA			; Send data to lcd
	movlw	b'00000101'			; E=1,RW=0,RS=1
	movwf	LCD_CTRL
	nop
	bcf	LCD_CTRL,LCD_E			; set the E-line low once again
	return
dvs bit:n som motsvarades av LCD_E blev inte låg... men jag är inte säker på att jag kollade på rätt bit när jag mätte... var lite less efter 6 timmars felsökande av min kod i tron att den var felaktig... tycker fortfarande det är en "bugg" med bsf då det inte uttryckligen står att man inte får ha två bsf efter varandra i koden.

Ska man alltid jobba mot LATA istället? finns det nån situation när man vill jobba mot PORTA?
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

R-M-W problemt är ingen "bug", och det är dokumenterat (om än indirekt). Det står (i kapitlet om PORTA) bl.a :

"The data latch (LAT register) is useful for read-modify-write operations on the value that the I/O pins are driving.".

Inte solklart kanske, men i alla fall... :-)

Det har inte specifikt med BSF/BCF att göra, men det brukar vara med
dessa instruktioner som man "ser" problemet.

Fick du igång PLL'en ? Kör du i 40 Mhz ? Då är det inte mycket tid (ca 25-50 ns) från det att en BSF har skrivit till porten tills att nästa BSF läser från den igen. Beroende på hur "lasten" på porten ser ur, är det inte säkert att den har hunnit växla läge så om man läser från PORTx kommer man att se den gamla nivån.

Man kan visst ha flera BSF efter varandra i koden ! Så länge det är något annat än ett PORTx register som hanteras är det inga problem.

Notera att en stor anledning till att man i PIC18 valde att göra latcharna tillgängliga för programmeraren (på de mindre PICarna finns inga LATx register), är just för att enkelt kunna undvika R-M-W problemet.

Ingen, det är ingen bugg, det är bara så som det fungerar...

För övrigt borde din BCF fungera även mot LATx (i koden du postade kör du dock mot PORTx).
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Jo jag ändrade define till porta efter att det strula... men men orkar inte gräva i det mer.

Men om man väljer att alltid köra mot LATx, innebär det nå problem? om det inte gör det så känns ju det säkrast.

Aja, dags för lite ny kod att kommentera på ;)
Lab 2 i kursen jag går just nu.
http://www.student.itn.liu.se/kursmater ... r/LAB2.pdf
Kortfattat gick den ut på att läsa av en 4*3 knappsats och skriva detta till en hex-siffra med inbyggd ttl-logik.

Kod: Markera allt

;=========================================================
; TNE019  Lab 2 ht 2005		Uppg 5.2
; Fredrik Johansson
; Program for decoding a numeric keyboard and displaying
; it on a hex-led-display
;=========================================================
	list p=18f452
	include "p18f452.inc"
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;    Variables. We put them in the access bank...
vars		UDATA_ACS
scanOut		RES   1		; value to send to keyboard
scanIn		RES   1		; value to read from keyboard
readFlag	RES	  1		; flag to indicate its time to read
offset		RES	  1		; offset used to decode keys
dont_jump_to_far	RES		1
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	
Boot	CODE	h'0000'
 	goto	start
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Int	CODE    h'0008'         ;This is where our interrupt routine will start 
	btfsc	INTCON, TMR0IF	; tmr0 overflow interrupt
	goto	tmr0of
	goto	end_of_isr

tmr0of

	bsf		readFlag,0		; set the "its-time-to-read"-flag

end_of_isr
	bcf	    INTCON, TMR0IF 	; clear interrupt flag.
	retfie                      

;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Main   CODE

start
	bsf     INTCON,GIE
	bsf     INTCON,TMR0IE
	movlw	d'26'
	movwf	dont_jump_to_far

	movlw	0xFF			; configure PORTA as
	movwf	ADCON1			; digital I/O

	movlw	0x00
	movwf	TRISC		  	; PORTC as output
	movwf	TRISA			; PORTA as output
	movwf	TRISE			; PORTE as output
	
	movlw	b'00000111'		; PD2-PD0 as inputs, PD7-PD3 outputs
	movwf	TRISD
	movlw	0xFF
	movwf	PORTD			; set whole PORTD to "ones"
	bcf		PORTE,0
	movlw   b'10001111'		; enable timer0,16-bit, prescale = 256 
	movwf	T0CON

	call	resetScan
run
	btfsc	readFlag,0
	call	Readkb
	goto 	run
	
Readkb
	movff	scanOut, LATC
	movff	PORTD, scanIn 	; move the value in PORTD into scanIn, we're after bit 2-0
	infsnz	scanIn,W 		; skips next instruction if PORTD+1!=0
	goto 	nokey_pressed	; no key pressed
	call	Decode_key		; key pressed, lets decode it!
	btfsc	WREG,7			; if w is set to 0xFF
	bsf		PORTE,0
	btfss	WREG,7			; if w is set to 0xFF
	bcf		PORTE,0
	movwf	LATA			; w is loaded with keycode on return from Decode_key
	; set strobe low ie light up the display
	call	resetScan		; reset after decoding
	
endof_readkb
	rlncf	scanOut		; rotate the zero one step to the right
	btfss	scanOut,4	; as long as '0' is at bit 0-3 we're good
	call	resetScan	; oops, no carry, time to reset the scan value
	clrf	readFlag	; clear the "its time to read keyboard"-flag
	return
nokey_pressed
	bsf		PORTE,0	; blank the display
	goto 	endof_readkb

Decode_key
	movlw	b'00000010'
	movwf	offset			; offset counter for decoding
decode_column
	rlncf	offset
	rlncf	scanIn			; rotate the zero one step to the left
	btfsc	scanIn,3		; skip next if we have found the '0'
	goto 	decode_column	; continue until the 0 "falls out"
	; offset should be 0,8 or 16, so if it's 2 or 4 we clear it
	bcf		offset,1
	bcf		offset,2
	; ok, now offset is 0,8 or 16 depending on selected column
decode_row
	incf	offset
	incf	offset
	rlncf	scanOut		; rotate the zero one step to the right
	btfsc	scanOut,4	; skip next if we have found the '0'
	goto 	decode_row	
	; finally, we're done decoding, should have a proper offset
        ; of [0,8,16] + 2,4,6 or 8
	movf	offset,W	; place the offset into W
	cpfslt	dont_jump_to_far
	addwf	PCL,F	
	return
	retlw	d'255'	; offset 2, #
	retlw	d'9'
	retlw	d'6'
	retlw	d'3'
	retlw	d'0'	; offset 10
	retlw	d'8'
	retlw	d'5'
	retlw	d'2'
	retlw	d'255'	; offset 18, *
	retlw	d'7'
	retlw	d'4'
	retlw	d'1'
	return
resetScan
	movlw	b'11111110'
	movwf	scanOut
	return
	end

ev. ligger min offset fel, trixade på laben och fick det iaf att fungera, osäkert om det var just denna kod.
Beror ju på om programräknaren redan är framräknad när jag plussar med 2*x? dvs att den hoppar en rad om jag ökar med 0 , två rader när ja ökar med 2, 3 rader när jag ökar med 4 osv.

Och i just detta fall är det inte direkt nödvändigt att scanna i 300Hz eller va det nu blev, men det kändes bra för en ev. situation där man vill undvika kontaktstuds.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Men om man väljer att alltid köra mot LATx, innebär det nå problem?

Nej, normalt sett inte.

Koden är väll inte så mycket att säga om, ett par småsaker bara... :-)

Om du lägger "nokey_pressed" före "endof_readkb", så försvinner ett "GOTO". Det är också lite "snyggare" om RETURN är den sista instruktionen i sub'en. För att hitta slutet letar man ofta efter RETURN, men i ditt fall finns det ett par rader till som hör till samma sub.

"Decode_key" har flera RETURN, kan vara lite förvillande. Bättre att ha ett GOTO i första läget till en label före den andra RETURN'en.

"Reset_scan" gör inte speciellt mycket. Det kanske finns någon anledning till att det är gjort till en sub, men annars skulle ett macro även fungera bra i detta fall.

Slutligen, prova gärna att lägga in flera CODE directive, t.ex genom att göra "Readkb" och "Decode_key" till egna "code sections". Observera hur du då automatiskt för storlekarna på de olika rutinerna uträknade i MAP filen !
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Ja den var en subrutin för att i det här fallet släcks displayen om man tryckt * eller #, flyttar jag på nokey_pressed så släcks displayen direkt efter en knapptryckning oavsett vad jag tryckt om jag inte lägger in en goto hoppar över den.

Mmm, har provat lite med code och kollat i map-filen på lab3 som jag sitter med nu.
Men vad jag förstått måste det vara nån slags "global" deklarering på subrutiner som ligger i olika code-blocks när de vill anropa varandra?
fast det har jag inte märkt något av, har slängt in code lite här och var och det verkar inte ha ställt till något hittills.

edit:
reflekterade just över hur dålig jag känner mig som börjat spaghettikoda igen... trodde goto var något jag lämnade bakom innan jag blev tonåring och dumpade basic:n i favör för C ;)
Fast det kanske inte är riktigt lika illa som basic ändå, men man har ju ändå växt upp med att goto är något hemskt som man aldrig mer igen ska använda sig av :lol:
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

OK, det är rätt, men det är i alla fall bättre, så att RETURN kommer sist...

> Men vad jag förstått måste det vara nån slags "global" deklarering på subrutiner som ligger i olika code-blocks

Bara om dessa "code sections" ligger i olika "code modules", d.v.s olika källkodsfiler (ASM filer). Då får man använda GLOBAL och EXTERN. Se beskrivning av dessa...

Fördelen med olika källkodsfiler (modules), är att man kan köra med samma variabler (som t.ex "temp", "count" eller liknande) så länge som man inte gör dom GLOBAL. MPLINK håller isär alltsammans. Även labels för programhopp kan vara samma, som t.ex "loop" eller liknande. Det gör det enklare att utveckla generella rutiner som man "länkar" in i olika applikationer. Här syns även den stora fördelen med RES (jämfört med att hårdkoda adresserna till variablerna), MPLINK kommer att tilldela adresser dynamiskt och ta hänsyn till vilka moduler som man har tagit med i varje individuell applikation.
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

ah, det verkar riktigt smidigt.

Ska nog ta och försöka lägga ut mina lcd-rutiner som jag gjort inför nästa lab i separata filer. Kan ju va bra att ha, hitachi-kontrollern är ju rätt vanlig ändå.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Precis !

Om du vill göra deet riktigt "snyggt" (jag vet inte om du får extrapoäng på kursen, men endå :-) ), så kan du göra så här :

- Lägg din kod för HD44780 med olika subar i en en fil. Se till att göra de labels och variabler som behövs GLOBAL. t.ex HD44780.ASM

- Lägg de EXTERN som behövs i andra moduler (d.v.s motsvarande de GLOBAL som ligger i huvudfilen) i en annan ASM fil, t.ex HD44780_INC.ASM. Sen gör du "#INCLUDE HD44780_INC.ASM" i de andra moduler där du vill kunna anropa HD44780 koden. Då behöver du inte lägga in flera EXTERN i varje fil, och om du ändrar HD44780 koden (och t.ex lägger till en sub) så är det bara att ändra HD44780_INC.ASM, lägga till anrop till de nya sub'arna och bygga om applikationen.

Så om du har en befintlig applikation där man vill lägga till LCD funktioner så lägger man till HD44780.ASM till "Source Files" i projekt fönstret, lägger till en INCLUDE i de filer där man vill använda LCD funktioner, samt lägger till anrop till de funktioner man vill använda.

Notera också att man kan göra mycket med "conditional assembly" där man "styr" vilken kod som skall genereras med hjälp av de olika inbyggda funktionerna i MPASM. Eller "assembly time calculations", som det också kallas. Det går då att skriva flexibla moduler där man genom att göra vissa DEFINES i huvud modulen styr det hela.

En sak som man kan vilja påverka i en generell HD44780 modul, är ju t.ex vilka portar/pinnar som LCD'n är kopplad till ! Genom att sätta upp detta i DEFINES i huvudkoden, så behöver man inte ändra i HD44780.ASM varje gång. (Antagligen behöver man göra EXTERN på define-symboerna i HD44780.ASM också för att LCD modulen skall "se" symbolerna... Och GLOBAL från main modulen).
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Har börjat möblera om koden precis på det sättet nu men fick lite problem med mappningen av LCD_DATA osv till de olika portarna mha #define, den vill inte gå med på min global/extern deklarering:

Error[113]/MYLIB/HD44780_INC.ASM 6 : Symbol not previously defined (LCD_DATA)
Error[113]/MYLIB/HD44780_INC.ASM 6 : Symbol not previously defined (LCD_DATA_TRIS)
Error[113]/MYLIB/HD44780_INC.ASM 6 : Symbol not previously defined (LCD_CTRL)
Error[113]/MYLIB/HD44780_INC.ASM 6 : Symbol not previously defined (LCD_CTRL_TRIS)

filerna börjar på följande sätt:
[LAB3.ASM]
Include "../myLib/hd44780_inc.asm"

#define LCD_DATA PORTD
#define LCD_DATA_TRIS TRISD
#define LCD_CTRL PORTA
#define LCD_CTRL_TRIS TRISA


[HD44780_INC.ASM]
global LCD_DATA,LCD_DATA_TRIS,LCD_CTRL,LCD_CTRL_TRIS
extern lcdBusy,lcdSetAdr,lcdHome,lcdClear,lcdPutChar,lcdPutCmd,lcdInit

[HD44780.ASM]
include delays10mhz_inc.asm
global LCD_TEMP
global lcdBusy,lcdSetAdr,lcdHome,lcdClear,lcdPutChar,lcdPutCmd,lcdInit
extern LCD_DATA,LCD_DATA_TRIS,LCD_CTRL,LCD_CTRL_TRIS

vars UDATA_ACS
LCD_TEMP RES 1 ;


[DELAYS10MHZ_INC.ASM]
extern delay100,delay_W_100

[DELAYS10MHZ.ASM]
global delay100,delay_W_100
vars UDATA_ACS
DELAY RES 1 ; delay var
DELAY_W RES 1 ; used in delay*X routine


Tycker det verkar rätt, hd44780_inc.asm är ju inkluderad innan deklareringen av LCD_DATA osv så de ska ju bli global då.
Sen säger ju att hd44780.asm att den vill ha tillgång till samma symboler externt.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Du har väll inte lagt till _INC filen som en "Source file" ?
I så fall bör du få detta fel.

(Du kan lägga till den som "other files", om du ändå vil kunna öppna den enkelt, o.s.v...)

Annars ser jag inget uppenbart så här lite snabbt, utan att testköra själv...
Skriv svar