Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfråga!

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Glattnos
Inlägg: 3106
Blev medlem: 29 oktober 2009, 20:01:18

Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfråga!

Inlägg av Glattnos »

Jag har gjort ett projekt med en Atmega48 och en LCD-display(hd44780).
Har kopplat LCD:ns 8-bits data-buss till PORTB på AVR:en.

Problemet är att nu när jag kom på att jag ska driva AVR:en med kristall så ska kristallen kopplas in på PB6 och PB7. Då går det ju inte att använda PORTB som data-buss för LCD:n.

Jag är ju nybörjare och är inte helt klar på hur jag ska lösa detta:
Kan man på något sätt byta de två högsta bitarna i PORTB mot två andra bitar(pinnar), tex PC4 och PC5? Ja, jag antar ju att det går men jag kommer bara på riktigt krångliga sätt att lösa det på rent program-mässigt.
Kan jag kanske köra 4-wire? Detta har jag aldrig gjort förr och hela programmet som jag har nu är skrivet för 8-ledningsbuss. Därför känns även detta ganska krångligt att få till.

Har någon ett förslag?

Såhär ser mina sändningsrutiner ut nu, lite otydligt kanske, men det fungerar ju nu:

Kod: Markera allt

.MACRO PRINT_TEXT
	ldi	ZL, LOW(@0*2)
	ldi	ZH, HIGH(@0*2)
	rcall Print_data
.ENDMACRO

.MACRO PRINT_LCD
	ldi	ZL, LOW(@0*2)
	ldi	ZH, HIGH(@0*2)
	rcall Print_init
.ENDMACRO

.MACRO PRINT_SRAM
	ldi	ZL, LOW(@0)
	ldi	ZH, HIGH(@0)
	ldi	Sram_antal, @1
	rcall Print_data_SRAM
.ENDMACRO

;===============================================================================================
;	Subrutin Print_data
;===============================================================================================
Print_Data:
	ldi		temp, WRITE_DATA		;Sätt 3-ledningsbussen för sändning
	out		LCD_set, temp			;
Print_Next:
	lpm								;Hämta tecken från PM (r0 <- @Z)
	mov		temp, LPMdata
	out		LCD_data,temp
	cpi		temp, EOL				;Om detta tecken är lika med EOL...
	breq	Print_Done				;...hoppa till "Print_Done...
	rcall	SEND					;...annars, sänd LCD_data till Displayen
	adiw	ZL, 1					;Addera registerpar med direktdata (flyttar Z-pekare)
	rjmp	Print_Next				;Skicka nästa tecken
Print_Done:
	ret								;EOL(End Off Line), Returnera

;===============================================================================================
;	Subrutin Print_data_SRAM	-	Skriver ut från SRAM till LCD
;===============================================================================================
Print_data_SRAM:
	ldi		WriteCount, 0
	ldi		temp, WRITE_DATA		;Sätt 3-ledningsbussen för sändning
	out		LCD_set, temp			;
Print_Next_SRAM:
	ld		temp, Z+				;Ladda temp och flytta pekare
	ldi		temp2, 48
	add		temp, temp2
	out		LCD_data,temp
	cp		WriteCount, Sram_antal
	brsh	Print_Done_SRAM			;...hoppa till "Print_Done...
	rcall	SEND					;...annars, sänd LCD_data till Displayen
	inc		WriteCount
	rjmp	Print_Next_SRAM				;Skicka nästa tecken
Print_Done_SRAM:
	ret								;EOL(End Off Line), Returnera

;===============================================================================================
;	Subrutin Print_init	-	Skriver ut konstanter till LCD
;===============================================================================================
Print_init:
 	lpm		temp, Z+				;GET WRITE INTR OR VOID
 	cpi		temp,VOID				;VOID?
 	breq	Print_init_done			;YES DONE
 	out		LCD_SET, temp			;ELSE SETUP LCD_SET
 	lpm		TEMP, Z+				;GET DATA
 	out		LCD_DATA, temp			;SETUP DATA
 	rcall	SEND					;SEND IT
 	rjmp	Print_init				;AGAIN
Print_init_done:
 	ret								;OK DONE

;--------------------------------------------------------
SEND:
	sbi		LCD_set, LCD_E
	rcall	Delay_Long
	cbi		LCD_set, LCD_E
	ret
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av Swech »

Kod: Markera allt

out      LCD_data,temp

andi     temp,0b11000000    ;maska ut bit 6,7
lsr       temp                     ;flytta ned till bit 5,6
lsr       temp                     ;flytta ned till bit 4,5   nu är de på rätt ställe för portc
out      portc,temp             ;skriv till portc
Swech
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av jesse »

hela programmet som jag har nu är skrivet för 8-ledningsbuss.
Där är nog ett tankefel. Man skriver inte ett helt program baserat på hur en utgång ser ut.
Man ordnar en subrutin som skickar data och/eller instruktioner till LCD. Sedan gör man andra subrutiner som anropar denna för att skicka ut olika sorts data (som t.ex. från SRAM eller initieringskoder).

Då blir inte längre "hela programmet" gjort för ett visst sätt att skicka datan. Om du vill skicka data på något annat sätt ändrar du bara i den enda subrutinen. Jag brukar köra med 4-bitars överföring och det är inte mycket krångligare. Det går också ganska enkelt att lägga ut de översta bitarna på PC4 och PC5 om man vill det.

4-bitars sändning:
Saxat från elektronikwikin: "För att skicka text och kommandon gör man som i 8-bitars läge med den skillnaden att man delar upp data i två delar. Först lägger man ut den första halvan av databyten på port D7-D4 och skickar en puls på E porten, sedan tar man de sista 4 bitarna och lägger ut på D7-D4, också detta följt av en puls på E porten. Det är bitarna 7-4 som skickas först, följt av 3-0. "

ungefär så här:

Kod: Markera allt

; du har 8-bitar data i tmp.
call FourBitSend ; skicka höga åtta bitarna
swap tmp ; (byter de 4 höga mot de 4 låga bitarna i en instruktion)
FourBitSend: kod: skicka ut fyra bitar på porten ( och toggla klockan).
ret
Att lägga ut de höga bitarna på portC är också lätt. Eftersom PB6 och PB7 används till annat så spelar det ingen roll att du skriver till dem. Du behöver alltså inte maska bort de bitarna. Så du skickar ut databyten till portB som vanligt.
Sedan ska bit6 och 7 läggas ut på portC PC4 och PC5:
ungefär så här:

Kod: Markera allt

;tmp innehåller byte, tmp2 = ledigt register
out PORTB, tmp
rol ; rotate right 1 bit
rol ; rotate right 1 bit
and  tmp,0b00110000
in tmp2, PORTC
and tmp2,0b11001111
or tmp, tmp2
Mina kodexempel är ungefärliga eftersom det var längesen jag skrev i assembler och har inte syntaxen helt i huvudet.
(Swech hann före med ett exempel)
Glattnos
Inlägg: 3106
Blev medlem: 29 oktober 2009, 20:01:18

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av Glattnos »

Tack Swech och jesse! Nu kan jag lura vidare lite. Ska nog försöka få till sändning via 4-ledningar.

Jag provade att göra ett program som sänder via 4 ledningar.
Ska det vara 40 us mellan alla 4-bitars tal?
Hur vet LCD:n om det är det första eller sista 4 bitarna? Räknar den helt enkelt: MSB/LSB, MSB/LSB, MSB/LSB o.s.v.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av sodjan »

Generellt finns det sällan någon anledning att *inte* köra 4-bit HD44780.
Vad kommer de där "40 us" som du talar om ?

Efter att man har skickat kommandot för att byta från 8-bit
(vilket det alltid är efter reset eller power-on) till 4-bit så
skickar man allt som 2 x 4-bit. Men du menar kanske ifall
man kommer "ur takt", så att säga ? Har aldrig tänkt på det.
Jag gissar att om man läser HD44780 specen noga så har de
tänkt på det på någor sätt... :-)
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av jesse »

>"Räknar den helt enkelt: MSB/LSB, MSB/LSB, MSB/LSB o.s.v."
Ja. Man kan komma "ur takt" om man t.ex bara skickar en "halv" byte... då blir allt man skriver senare bara skräp. Man kan råka ut för det också om det skulle bli någon störning på Enable-tråden. Man kan återgå till ordningen genom att köra initieringen igen. Eller kanske ännu enklare med vissa instruktioner?
Glattnos
Inlägg: 3106
Blev medlem: 29 oktober 2009, 20:01:18

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av Glattnos »

sodjan skrev:Vad kommer de där "40 us" som du talar om ?
De står i databladet att man ska vänta 39us mellan instruktionerna.

Ska man köra enable-ledningen hög i 39 us mellan varje "halv byte"? I databladet ser det ut som att man INTE ska göra det utan bara mellan 2 till 3 "halv byte"!
Jag får det inte att fungera och är inte helt klar på hur det ska vara eftersom jag har hittat två datablad som säger olika när det gäller 4-bit interface. Hur kan jag ta reda på vilket som är rätt? På ELFA där jag köpte displayen finns det inget datablad.
http://www.soselectronic.hu/a_info/reso ... syh-ly.pdf
http://www.display-elektronik.de/DEM16216SYH-LY.PDF

Jag blir förvirrad?? :humm:
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av sodjan »

Du kan kolla mitt HD44780 exempel. För PIC förvisso, men ska
fungera i alla fall. Kolla subrutinerna där själva LCD kommandona
skickas. http://www.jescab.se/HD44780.html

> Jag får det inte att fungera...

Lite ointressant eftersom du varken visar eller beskriver vad du gör.
Glattnos
Inlägg: 3106
Blev medlem: 29 oktober 2009, 20:01:18

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av Glattnos »

sodjan skrev:> Jag får det inte att fungera...

Lite ointressant eftersom du varken visar eller beskriver vad du gör.
Jag tänkte när jag skrev det: Det här kommer man få höra sen! :P Men min största förbryllan var databladen i detta fall, två olika :shock:

sodjan: Om jag tolkar din kod rätt så håller du "enable-ledningen" hög i bara en "nop" när du skickar kommandon eller data och sedan väntar en tid för att LCD:n ska få bearbeta.
Jag trodde att "enable-ledningen" ska vara "hög" hela väntetiden, så har jag gjort förr när jag kört med 8-ledningar till LCD:n. Kan det vara därför det inte fungerar?
Om jag stegar igenom min kod i AVR-Studio så verkar alla kommandon och all data som sänds komma rätt på de fyra ledningarna, men tiderna har jag samma som när jag hade 8-ledninga.

En liten förvirring:
Men hur kan LCD:n "hinna" med att reagera på en "enable" på bara en "nop"? Det är väll bara en clock-cykel, eller är det annorlunda på PIC? Är "enable-ledningen" kanske en ext-interrupt? Men den borde väll kunna missa det med om den är riktigt snabb, eller?

EDIT: Läste i data-bladet att enable-signalen kan vara så kort som 500ns, en clock-cykel borde ju vara 1 000ns vid 1 Mhz men sodjans exempel är 4 Mhz, hur går det till då? Kör man på 8 Mhz borde väll LCD:n kunna missa enable eftersom det bara blir 125 ns? Eller är jag helt borta?
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av jesse »

Här står det exakt hur du gör - och det stämmer.

Angående "Enable": den fungerar som en "klockpuls" som klockar in data. Om det är 4 bitar åt gången måste du klocka in var och en för sig. Alltså:

1) sätt fyra bitar (de höga)
2) sätt enable hög.
3) sätt enable låg.
4) sätt fyra bitar (de låga).
5) sätt enable hög.
6) sätt enable låg.
7) vänta 40 uS

Jag tror att tiden mellan punkterna 1-6 kan vara ganska snabb. Det handlar nog om nanosekunder. Så om du kör <= 1MHz så behöver du inte lägga till någon fördröjning nånstans däremellan.

Tänk bara på att de fyra bitar som ska ut ska hamna på D4-D7 på displayen. D0-D3 ska alltid vara nolla (GND).

Om det inte funkar, kan det bero på miljoner saker. Har du rätt spänningar till displayen (även V0)?
Ordentlig kontakt till alla data och kontrollsignaler? Använder du rätt port, rätt bitar? Händer det något på utgångarna? Kommer programmet nånsin fram till stället där den försöker skriva ut ett tecken, etc etc...

Att "enable" räcker under en "nop" beror på att den bara lastar in data eller en instruktion i ett 8-bitars register. Sedan, när det är klart, börjar HD44780 att jobba. Se timingdiagrammet "Figure 7.0 Example of 4-bit bus mode timing diagram" på sidan 11 i databladet som har små bokstäver i filnamnet.
Där ser man (även om det är lite otydlig) att data skiftas in när enable går från etta till nolla. På sidan 16 finns tiderna: Enable cykleln (från att den blir etta - sedan nolla och etta igen) måste det gå minst 500 nS. Pulsen (etta) måste vara minst 220 ns lång. Det innebär 2 klockcykler för en processor med 8 MHz klocka.
Glattnos
Inlägg: 3106
Blev medlem: 29 oktober 2009, 20:01:18

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av Glattnos »

jesse: Tackar! Fick det dock att fungera precis innan jag läste ditt inlägg. Jag ändrade tiderna så det blev som sodjans exempel och POFF så fungerade det. Problemet var att jag förut fattat fel va gäller "enable-ledningen" och haft den "hög" under hela väntetiden, blir logiskt att det inte fungerar, eftersom data shiftas in när ledningen går "från 1 till 0", då blir ju min väntetid värdelös.

Dock vill jag försvara mig lite eftersom jag alltid kört med enable hög hela väntetiden förr när jag kört med 8 ledningar till LCD och det har fungerat jättebra. Inte konstigt att man blir snurrig :shock:
EDIT: Plus att jag hade två datablad som sa olika om "4-lednings initiering" för samma display och Wiki:n är faktiskt en tredje variant. Det är just utseendet på initieringen för 4-wire som är lite olika, det kanske fungerar med vilket som, nu när tiderna är rätt.

Tack för all hjälp!
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Byta ut två bitar i en port PORTB, AVR Assem? Nybörjarfr

Inlägg av jesse »

Dock vill jag försvara mig lite ...
hehe, det är väl lugnt, vi har alla gjort en massa såna fel när något är nytt.. :D
Skriv svar