mega8 nemužu rozchodit vstupní porty

Dobrý den.

Začínám s AVR assemblerem (asi jsem masochista).
Se vším se mi dařilo nějak se vypořádat ale zaboha nemužu přijít na to proč mi nefunguje jedoduchhý program, který nedělá nic jiného než že načítá to co je na portuC a posílá to na portB

[code] .include “m8def.inc”
.def w=r16
rjmp main

main: LDI W,0x00 ;smer portC - vstup
out DDRc,w

LDI w,0xFF	;smer portB - vystupni
out ddrb,w

smycka: in w,portc
out portb,w
jmp smycka[/code]
je to pro megu 8 W je všeobecný registr

Ať propojím PC0 s VCC nebo GND LEDka na PB0 nesvítí.

V AVR jsem taky začátečník, ale děláš tam úplně tupou chybu z nepozornosti. KDyž čteš port, tak takhle:
in R16, PINx
kde x je písmeno portu. Při čtení se používá registr PINx, pro zápis PORTx
Nesmíš taky zapomenout porty nastavit jako vstupy přes registr DDRx.

Jinak proc to nesmyslne (pro me) označení registru R16 “w” ??

Je dobře že jsi se pustil do asm. Je to ve většině případů výhodnější než Cčko.

Jinak pokud správně chápu, tak účelem tohoto programu je to, aby přenášel stav pouze pinu PC0 na PB0 - tenhle program ale přenáší stav celého portu! DOufám že seš si toho vědom. Celkem jednoduše to lze vyřešit i přenos pouze jednoho bitu. Jestli budeš chtít, tak ti napíšu i krátký program s popisem.

PS: doma jsem pouze zítra, pak jsem 3 týdny pryč!!! (Mat-Fyz tábor a tejden v Krkonoších. Pak už budu doma.

On vi, ze to pracuje s celym portem, ma to v popisu :wink:
“w” - co treba “working register” :wink: muze si ho pojmenovat treba “babicka”, to je jeho vec :slight_smile:
Je to skutecne tim, ze to, co se deje vne procesoru je videt v registru “PINx”… Stejne “uplne tupou chybu” jsem mel v jednom projektu, 3 dny jsem zkoumal, proc to nefunguje… (mimochodem tu chybu nasel nekdo jinej… :blush: )
Ovsem pouziva se i cteni z “PORTx”, ale to pouze v pripade, ze te nezajima skutecny stav na portu, ale jen to, co jsi tam naposledy zapsal.

No ja to psal dost na forfr, tak jsem jen napsal co mně napadlo… popis sem nijak moc nečet…

Díky.
Před atmelama jsem teoretizoval na PIC-ech tam bylo tuším W jako pracovní registr. a vůbec celý ten PICácký asssembler mně přišel o něco lidštější. Jeden nemusel přemýšlet nad tím jestli přesouvá do portu nebo do registru…
no konečně mně funguje te “externě řízený” blikač. eště ho zkusím postavit na čekání timerem.

[code] .include “m8def.inc”
.def w=r16
.def vzorek=r17
.def cykly=r25

rjmp main

main: LDI W,$00
out DDRD,w ;a portD vstupním

LDI w,$FF 
out DDRB,w 	;učinit celý portB výstupním

out portD,W	;pullUPy

LDI W,LOW(ramend) ;natáhnout konec ram
out SPL,W	;vložit adresu do stackpointeru
LDI W,HIGH(ramend)
out SPH,W


ldi r18,1	;natáhnout jedničku do r18 (tím se inkrementuje)

ldi cykly,$01	;nastavíme uvodní počet cyklů na 1 aby se načetl rovnou vzorek

sbi ddrd,portd0

;========

start: dec cykly ;snížime o jednu proměnnou cykly
BRNE hopLD ;pokud jsem se nedostali na nulu tak přeskočíme načítání vzorku
in vzorek,pinD ;natáhneme vzorek z portu D
ldi cykly,$04 ;znovu naplníme počet cyklů
hopLD: bst vzorek,0 ;načíst hodnotu nultého bitu ze vzorku
BRTS hopS ;přeskočí příkaz pokud je T 1
cbi portb,0 ;vynuluje bit PB0
hopS: BRTC hopC ;přeskočí následující jednu instrukci pokud je T0
sbi portb,0 ;nastaví bit PB0
;--------
hopC: LSR vzorek ;posuň vzorek

rcall cekej	;počkat

rjmp start	;vrátit se na start

;========
cekej: CLR r20
CLR r21 ;nastavit na nulu
wait: add r21,r18 ;přičteme 1

nop
brcc wait	;skočí je li carry v nule


add r20,r18	;jedničku k béčku
brcc wait
ret		;návrat z podprogramu

;========[/code]

Drobná připomínka: Pokud chceš nějaký registr zvětšit, tak na to se používá instrukce inc, a ne ldi a add to je blbost, akorát je to daleko pomalejší, a zbytečně.

Jinak na procesorem řízený blikač LED neni potřeba časovač, na to stačí zpožďovací smyčka.
(Můj První program):

		.NOLIST
		.INCLUDE "m8def.inc"
		.LIST


;**************************************************************************
;       MUJ PRVNI PROGRAM - BLIKANI LED
;		Neguje stav PB0 po 500ms
;
;		Xtal 4MHz
;
; by Jan16 (c) 15.6.2008
;**************************************************************************


			ldi R16, HIGH(RAMEND)	;nastavime zasobnik na konec SRAM
			out SPH, R16
			ldi R16, LOW(RAMEND)
			out SPL, R16


			ldi R16, 0b00000001		;1 -> R16
			out DDRB, R16			;pin PB0 jako výstupní
			sbi PORTB, 0			;nastavíme PB0 do log. 1

zacatek:	rcall zpozdi			;zavolame rutinu ZPOZDI

			in R16, PORTB			;načteme stav portu B do R16
			ldi R17, 0b00000001		;Budeme negovat bit 0 portu B
			eor R16, R17			;R16 XOR R17 -> R16
			out PORTB, R16			;výsledek po negaci XORem pošleme z5 na port

			rjmp zacatek			;skok na ZACATEK



;zpozdí cca 500ms (cyklů 1999998, odchylka -2 cykly)
zpozdi:		ldi R16, $12	;$12 do R16
on1:		ldi R17, $BC	;$BC do R17
on2:		ldi R18, $C4	;$C4 do R18
on3:		dec R18			;sniž R18 o 1
			brne on3		;pokud po snížení o 1 R18=0 skoč na on3
			dec R17			;sniž R17
			brne on2		;pokud po snížení o 1 R17=0 skoč na on2
			dec R16			;sniž R16
			brne on1		;pokud po snížení o 1 R16=0 skoč na on1
			ret				;návrat z rutiny

No ta zpožďovací smyčka byl můj v pořadí druhý program. INC má tu nevýhodu že nezjistíš že ti registr přetekl. Jasně, mužu použít dec a zkoumat kdy je registr nulový,ale zrovna v případě zpožďovací smyčky není delší čas potřebný pro add na škodu. Navíc změnou hodnoty v r18 mužu čekací smyčku urychlit.

K tomu timeru - snažím se naučit používat pokud možno všechno co mega nabízí. čili začal jsem s jednoduchou smyčkou

start: nop
rjmp start

potom jsem udělal tu zpožďovací symyčku a blikání. Blikač jsem upravil tak,aby blikal podle vstupního portu. teď vyhodím čekání a nacpu tam timer. Potom si říkám že by nějak mohli jít místo čekání megu uspat a po určité době probrat watchdogem, ale zatím jsem to nezkoumal.

Koukal jsem do insktrukčního souboru, INC ovlivňuje příznak Z (přetečení),S, V, N
Takže INC použít můžeš. Nevidím v tom problém.

Není náhodou přetečení C ?
Z je nulový výsledek ne ?

Jo já sem vůl. Když to přeteče, tak je v registru nula čili z=1

AVR mají totiž řek bych dost promakaně vymyšlené instrukce, všechny totiž se dají použít “na všechno” :slight_smile:

Jak bys teda kopíroval jeden bit třeba PD0 do výstupu PB0?
mně napadá jenom pomocí sbis a sbic testovat hodnotu na určitém pinu a podle toho jaké je ji nastavit pomcí SBI A CBI na výstupním pinu.

A eště jeden dotaz když potřbuju přeskočit jedn příkaz tak mi přijde zbytečné používat návěsti. podle manálu skoro všecky skákací intrukce vykonávají PC<-PC+1+k
Když jsem ale napsal BRCS 1 tak mi to začalo bloudit po kódu kde sem udělal chybu ?

A eště neco - bit H v SREG je "půlpřetečení tj je 1 pokud hodnota v registru je větší než 128 ?
A bít V slouží k čemu ?

Testovat bit je jedna možnost, přemejšlim o druhý… Pomocí XORu se dá chytře negovat bit, ale my potřebujeme pouze jeden bit překopírovat…
přemýšlím o tom, chce to zas použít nějaké log. funkce… Jen vymyslet jak je nakombinovat… Nějak to jít musí…

Když potřebuješ přeskočit jednu instrukci, použij nějakou instrukci přeskoku a nebo tam prostě dej to návěští, nebudešě mít problémy.
Podle mě, když dáš k=1, tak ti to skočí o -63 instrukcí dozadu, což je víceméně v pořádku. Abys skočil o 1 dopředu, musí být k=65 (domnívám se, raději to otestuju v simulátoru)

k čemu je H V a spol, co třeba se podívat do toho instrukčního souboru, popis je tam více než jasný. H, ne, pokud je hodnota větší než 15, to sou základy… Přenos mezi 3tím a 4tým bitem…
Včko tam máš taky jasně napsaný…
Set if two’s complement overflow resulted from the operation; cleared otherwise.
Nastaven, jestliže přetečení dvojkového doplňku bylo výsledkem operace, jinak vynulováno.
Problém je akorát v tom, že nemám páru co je jedničkový a dvojkový doplněk :smiley: (vím jak je spočítat, ale nechápu na co to je dobrý)

Nevim co máš za instrukční soubor, používej originál, a to tento:
jan16.czela.net/download/AVR_is.pdf

EDIT: Zkoušel jsem to v simulátoru, neni to tak, číslo opravdu se zapisuje se znaménkem, tedy 1čku jsi měl správně, proč to ale dělá to co dělá, nechápu. PIŠ TAM PROSTĚ TY NÁVĚŠTÍ a nevymýšlej blbosti, vyhneš se pak takovýmhle potížím…

BTW toto “<-” měla být šipka
Používám origoš instrukce - mám je vytištěné. K těm blbostem - člověk tak napadá jak by si usnadnil práci a případně zpřehlednil kód.

jinak v drtiv většině případů než se na nco zeptám tak se to pokuším najít všude možně.
U toho véčka jsem se dostal přesně tam kde ty - netuším co je doplněk.
U háčka jsem čekla že carry nasatne tehdy když k 255 něco přičtu
tudíž half-carry nastane při 128 ale jak vidím tak je to brané vzhledem k bitům.

Jinak díky za rady.

ad šipka, nejsem blb, šipka se takle běžně píše…

no teda já spoíš jen nevím na co ten doplněk je dobrý. Máš tam i vysvětlenou činnost instrukce, tak si z toho můžeme odvodit na co to je dobrý…

H je samozřejmě vzhledem k bitům - nečekaně, indikuje přenos mezi nižším a vyšším nibble. :slight_smile:

Honza

nacist bit se da jeste pomoci maskovani (log. soucin obrazu brany a cisla, ktery bude mit “1” na miste toho bitu, kterej chces precist). Kdyby ti nevadilo prepsani cely brany, na kterou to chces dostat, tak to tam muzes primo poslat, ale pokud smis ovlivnit jen danej bit, je treba zase podminka a vystupni branu zase maskovat (and pro nulovani bitu, or pro nastaveni)

dvojkovej doplnek se pouziva pro zobrazeni znamenkovych cisel a to z toho duvodu, ze se s nim mnohem lepe pocita.

aha… takže se to bez podmínky asi neobejde…
Já jsem přišel přesně na to co říkáš ty… ale nedomyslel jsem ten koncec, kdy je jednou třeba AND a jednou OR… Já to chtěl vymyslet bez podmínky :slight_smile:

Přetečení po insrukci INC lze zjišťovat a to pro oba typy (signed i unsigned). Pokud je registr brán jako unsigned, indikátorem přetečení je příznak ZERO. Pro signed slouží OVERFLOW. Viz nápověda v AVR studiu.

Jinak instrukce INC je stejně tak rychlá jako ADD, resp. SUBI. Přičítání 1 by se řešilo odečtením -1, resp. odečtením 255. Tato instrukce modifikuje příznak CARRY na rozdíl od INC.

2 technik - nemáš úplně pravdu…
add a inc je sice stejně rychlé, na přičtení 1 ale potřebuješ instrukce dvě:
ldi Rr, 1
add Rd,Rr
to musi byt instrukce dve… pokud si teda nevyhradis registr ve kterem je stale cislo 1 :slight_smile:

A co myslíš, že udělá instrukce
SUBI R16,255 ?
Zvětší R16 o 1, stejně jako INC R16. Rozdíl je pouze v příznaku CARRY, který se generuje obráceně na rozdíl od ADD. Při přetečení je C= 0, ve všech ostatních případech je C=1.