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
“w” - co treba “working register” muze si ho pojmenovat treba “babicka”, to je jeho vec
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… )
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.
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.
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
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.
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 (vím jak je spočítat, ale nechápu na co to je dobrý)
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.
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
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
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.