Prevod dvou registru na cislo int.

No ja programy zkusebne zacinam psat v jazyku C a prostredi se jmenuje mikroC. Ten muj prvni zpusob bude ale podle toho kompilatoru pomalejsi, protoze kod v ROM zabira o 94 bitu vice, nez kdyz to provedu bez primeho prirazeni. Divne, ze?

Tj.
DB7 = znak.F7;
DB6 = znak.F6;
DB5 = znak.F5;
DB4 = znak.F4;

DB7 = znak.F3;
DB6 = znak.F2;
DB5 = znak.F1;
DB4 = znak.F0;

je pomalejsi, nez

PORTD = (znak & 0xf0) | (PORTD & 0x0f);

PORTD = (znak<<4) | (PORTD & 0x0f);

Jeste neco pro pobaveni:

char znak = ‘R’;

PORTD = (‘R’<<4) | (PORTD & 0x0f); // Funguje

PORTD = (znak<<4) | (PORTD & 0x0f); // NEFunguje !!!

Jsem z toho jelen :cry:

Hoď sem soubor s asemblerem, popřípadě se doněj podívej a stoho bude jasný co se tam děje. Osobně si myslim že to bude nějakej problém s překladačem kterej přesně nechápe jak ten příkaz mysllíš. Skompiluj jenom tudle procedůru a hoď sem výsleden ASM soubor.

Už asi vidim včem je problém. Když máš ten první příkaz kterej funguje, tak kompilátor dojde ke kódu kterej bude vypadat nějak takhle: PORTD= K | (PORTD & 0x0f). kde K je přímo konstanta uložená v procesoru jako bitovej posun písmena R
ale zatimco u druhýho příkazu se to rozdělí do dvou fází
PORTD=znak<<4 a až teprve potom se provede
PORTD=PORTD | (PORTD & 0x0f)
Jinak ber to spíš jako doměnku, protože v programovánim MCU v C moc skušeností nemam, ale asi by to tak mohlo bejt, popřípadě něco na tendle spůsob. Jinak když hodíš ASM tak to bude jasný.

Tak to je to co vyplivne prekladac. Snad se v tom zorientujes.

; ;my_lcd.c,97 :: char tmp = 'B',tmp0; $01BE $0E42 MOVLW 66 $01C0 $6E2B MOVWF put_char_on_lcd_tmp_L0, 0 ;my_lcd.c,101 :: RS = 1; $01C2 $8483 BSF PORTD, 2, 0 ;my_lcd.c,103 :: E = 1; $01C4 $8683 BSF PORTD, 3, 0 ;my_lcd.c,111 :: PORTD = (tmp & 0xf0) | (PORTD & 0x0f); // OK $01C6 $0E0F MOVLW 15 $01C8 $1483 ANDWF PORTD, 0, 0 $01CA $6E00 MOVWF STACK_0, 0 $01CC $0E40 MOVLW 64 $01CE $1000 IORWF STACK_0, 0, 0 $01D0 $6E83 MOVWF PORTD, 0 ;my_lcd.c,113 :: E = 0; $01D2 $9683 BCF PORTD, 3, 0 ;my_lcd.c,115 :: E = 1; $01D4 $8683 BSF PORTD, 3, 0 ;my_lcd.c,124 :: PORTD = (tmp<<4) | (PORTD & 0x0f); $01D6 $C02B F001 MOVFF put_char_on_lcd_tmp_L0, STACK_1 $01DA $3601 RLCF STACK_1, 1, 0 $01DC $9001 BCF STACK_1, 0, 0 $01DE $3601 RLCF STACK_1, 1, 0 $01E0 $9001 BCF STACK_1, 0, 0 $01E2 $3601 RLCF STACK_1, 1, 0 $01E4 $9001 BCF STACK_1, 0, 0 $01E6 $3601 RLCF STACK_1, 1, 0 $01E8 $9001 BCF STACK_1, 0, 0 $01EA $0E0F MOVLW 15 $01EC $1483 ANDWF PORTD, 0, 0 $01EE $6E00 MOVWF STACK_0, 0 $01F0 $5000 MOVF STACK_0, 0, 0 $01F2 $1001 IORWF STACK_1, 0, 0 $01F4 $6E83 MOVWF PORTD, 0 ;my_lcd.c,130 :: E = 0; ///////////////////////

Tady vtáý procedůře to proběhne takhle: veme se znak a uloží se do pomocný proměný (označme ji A), vtýdle proměný proběhne rotace o 4 bity. Potom se veme a udělá se PORTD=PORTD & 0x0F . Potom se veme ta pomocná proměná a udělá se PORTD=PORTD | A . Nevim jestli to je takjak zamejślíš, skus sem kdyžtak hodit i tu druhou která funguje, takhle nemam sčim porovnávat. Jinak taky by nebylo špatný vedět v jakým stavu se nachází portD, natom je ten výsledek docela taky závislej.

;my_lcd.c,101 :: RS = 1; $01BE $8483 BSF PORTD, 2, 0 ;my_lcd.c,103 :: E = 1; $01C0 $8683 BSF PORTD, 3, 0 ;my_lcd.c,111 :: PORTD = (tmp & 0xf0) | (PORTD & 0x0f); // OK $01C2 $0E0F MOVLW 15 $01C4 $1483 ANDWF PORTD, 0, 0 $01C6 $6E00 MOVWF STACK_0, 0 $01C8 $0E40 MOVLW 64 $01CA $1000 IORWF STACK_0, 0, 0 $01CC $6E83 MOVWF PORTD, 0 ;my_lcd.c,113 :: E = 0; $01CE $9683 BCF PORTD, 3, 0 ;my_lcd.c,115 :: E = 1; $01D0 $8683 BSF PORTD, 3, 0 ;my_lcd.c,123 :: PORTD = ('B'<<4) | (PORTD & 0x0f); $01D2 $0E0F MOVLW 15 $01D4 $1483 ANDWF PORTD, 0, 0 $01D6 $6E00 MOVWF STACK_0, 0 $01D8 $0E20 MOVLW 32 $01DA $1000 IORWF STACK_0, 0, 0 $01DC $6E83 MOVWF PORTD, 0 ;my_lcd.c,130 :: E = 0; ///////////////////////

to je ta cast ktera funguje

No jabych řek že je to jasný a nejspíš jsem měl pravdu :slight_smile:. Tadle ta procedůra to dělá trošku jinak. udělá: STACK=PORTD & 0X0F (neukládá výsledek na PORTD ale do proměný STACK) pak vezme a udělá PORTD=STACK & 0X20
Takžese na portd uloží data jenom jednou naproti tomu to předchozí kde probíhá jeden výpočet prostřednictvím portud. Jinak to 0X20 je konstanta která vznikne posunem písmena B o 4 bajty.
Todle je názorná ukázka toho proč používat ASM :smiley:

Ani nie … skor nazorna ukazka toho ze ked niekto vie ASM lahko si pomoze… najst chybu :slight_smile:

A presne to mi na Cku vadi (okrem startu rychlosti a priestoru v uP)
V asm je chyba medzi stolickou a klavesnicou kdez to v cecku moze byt este aj v prekladaci… grrr

No ja zacinam s programovanim Cecka pro mikrocipy. Samozrejme Cecko znam z PC a tak bych cekal ze dodrzuji jakousi ANSI normu. Asembler umim tak nejak stredne. Kdyz si to ale projdu cely program at uz ten prvni ci druhy. Fakt nevidim tu chybu. Muzes mi ji napsat na jakem radku to je?

:arrow_right: administrator: příspěvek byl upraven

Pokud si totiz vezmu v asembleru instrukci po instrukci, dojdu k stejnemu vysledku jak v prvnim tak druhem pripadu programu.

Ano, výsledek je stejnej, jinak by byla chyba v překladači. Ale jde oto že když měníš bity na portu jako mezikrok, může to ovlivnit nějaký obvody co jsou na ten port připojený. Z hlediska programu je všechno dobře a nakonci algorutmu bude na portuD to samí číslo, ale nesmíš zapomenout na další elektrická specifika toho zapojení.

Ted jsem ty moje dva programy projel debugerem v mikroC. Sledoval jsem jednotlive promenne. V obou pripadech to dava stejny vysledek na portu D :cry: ale v PICu to nefunguje.

No to mas pravdu, ale nikde se na port prece nepise, leda az se vyhodnoti promene vpravo, pak se hodnota vysledku prideli portu D. Nebo ne? Mimochodem, pri projeti debugeru to taky nemeni stav portu, ale jeste zkusim ty jednotlive operace rozepsat na kratsi.

Můžeš sem hodit schéma toho zapojení? co je napojený na portD? Ja bych tipnul LCD display kterej komunikuje po 4 bitech ?

No vtý jedný variantě se právě během provádění toho příkazu uloží mezyvýsledek na portD a teprve pak další operací se tam udělá finální výsledek, takže po dobu 1-2 instrukcí jsou tam “náhodný” data

:arrow_right: administrator: příspěvek byl upraven

Mas naprostou pravdu. Je to LCD na 4 bitech. Je to zapojeno

DB7 je na PORTD7
DB6 … PORTD6
DB5 … PORTD5
DB4 … PORTD4

ENABLE … PORTD3
RS … PORTD2

RW je na log. 0 tedy ve stavu psani do LCD

Aha, to mi uniklo. No v kterem radku to prosim vidis? Jestli by totiz doslo k zhozeni v tech “nahodnych datech” bitu ENABLE, tak by se ten vysledek co je momentalne na DB7-DB4 poslal na LCD a to by delalo neplechu.

:arrow_right: administrator: příspěvek byl upraven

$01EA $0E0F MOVLW 15 $01EC $1483 ANDWF PORTD, 0, 0 $01EE $6E00 MOVWF STACK_0, 0 $01F0 $5000 MOVF STACK_0, 0, 0 $01F2 $1001 IORWF STACK_1, 0, 0 $01F4 $6E83 MOVWF PORTD, 0

Jsou to tydle řádky, je tam vidět že napřed se uloží mezikrok na portd a pak nakonci je zase operace s portemd která ho nastaví na konečnou hodnotu. Jinak skus vyjít ztěch popisu toho algoritmu co jsem ti poslal a tam je to vydět co a jak se děje.

Aha tak to asi neco spatne chapu, promin. Moje interpretace:

[code] MOVLW 15 // nastavi do W = 0b0000 1111

ANDWF PORTD, 0, 0 // logicky soucin PORTD a W => ulozi se do W

MOVWF STACK_0, 0 // W se ulozi do promenne STACK_0

MOVF STACK_0, 0, 0 // ze STACK_0 se naplni W registr

IORWF STACK_1, 0, 0 // provede se logicky soucet W a STACK_1 ulozi se opet do W

MOVWF PORTD, 0 // az tady se z W ulozi vysledek do PORTD[/code]

tak to vidim ja, ale nejsem zadny ASEMBLER guru
:frowning:

:arrow_right: administrator: příspěvek byl upraven