Makra v assembleru - best practices pro práci s porty

Prosím o radu s makry, koumal jsem jak jednoduše psát instrukce pro porty AVR v assembleru a vyzkoušel jsem následující způsob s makry:

;***********************************************************
.MACRO DIR_OUT ;@0=port,pin
sbi ddr@0
.ENDMACRO
;***********************************************************
.MACRO CLR_OUT ;@0=port,pin
cbi port@0
.ENDMACRO
;***********************************************************
.MACRO SET_OUT ;@0=port,pin
sbi port@0
.ENDMACRO
;***********************************************************

nadefinuji názevy použitých pinů např:
#define led_PWR b,5 ; pin 5 na portu B
… atd.

a pak už stačí jen psát:

;kód
DIR_OUT led_PWR ;nastaví pin 5 na portu B jako výstupní
CLR_OUT led_PWR ;pin 5 na portu B = 0
SET_OUT led_PWR ;pin 5 na portu B = 1

Funguje to, je to velmi přehledné a podobně by to šlo udělat i pro instrukce IN, jen nevím, jestli bych si takhle nezadělal na nějaké problémy.

Co na to odborníci?

:arrow_right: administrator: přejmenováno z "Pomoc s makry v assembleru"

#define led_PWR b,5 ; pin 5 na portu B SET_OUT led_PWR

Nevím, nějak se mi to nezdá přehlednější než prosté

#define led_PWR portb,5 sbi led_PWR

Ale je správné, že experimentuješ s makry a s kódem vůbec.
Tím se člověk učí.

No jo, ale já můžu mít jeden název např to “led_PWR” pro všechny dostupné instrukce s pinem portu. Ty musíš pro instrukce DDRB,5 a PINB,5 mít další definice s jinýmy názvy. Nebo se pletu?

Zkrátka koumám, jak mít pro jeden pin CPU jen jeden název, psát instrukce pro práci s porty vždy jen na jeden řádek a nemuset stále dokola v instrukcích uvádět port i pin.

Prosím, poraďte, v jiných programech pro AVR jsem viděl v makrech použitý příkaz:

.IF ISREG(@0)

ale když jej použiji v AVR studiu tak mi to ohlásí chybu.

Ohlásí chybu:
Illegal use of undefined or forward referenced symbol ‘isreg’ in conditional
(použití nedefinovaného symbolu “ISREG”).

To znamená, že překladač nezná výraz “isreg”.
Uživatel ho musí před použitím definovat.

Děkuji za vysvětlení. Poraď prosím ještě, co mám udělat proto, abych mohl makra obsahující “ISREG” používat.

Odpověď na Tvůj poslední příspěvek je jednoduchá : nadefinovat symbol/makro ISREG.

Ale vrátím se k dotazu na makra :
Osobně nevidím problém v jejich použití. A výhodou je, že Ti opravdu stačí jeden název pro všechny operace s pinem. Dovolil jsem si nadhodit, jak by asi ty Tvoje makra mohly vypadat.

[code];***********************************************************
.MACRO SKIP_IN_SET ;@0=port,pin
sbis pin@0
.ENDMACRO
;***********************************************************

.MACRO SKIP_IN_CLR ;@0=port,pin
sbic pin@0
.ENDMACRO
;***********************************************************
[/code]
A dovolil jsem si něco přidat :

[code];***********************************************************
.MACRO DIR_IN ;@0=port,pin Možná jsi ho jenom nenapsal do svého dotazu, ale může se hodit - uvidíš dále.
cbi ddr@0
.ENDMACRO
;***********************************************************

.MACRO TOGGLE_OUT ;@0=port,pin
sbi pin@0
.ENDMACRO
;***********************************************************
[/code]

;kód

TOGGLE_OUT led_PWR ;změna pin 5 na portu B 0<=>1

Neumí to sice úplně všechny AVRka (pokud vím, tak ATmega8, 16, 32, 64, 128 to neumí), ale můžeš toho využít ke změně hodnoty na pozici daného pinu v registru PORT (!!!).

V datashetech tahle vlastnost je trošku shovaná, ale lze to tam najít.

Například Datasheet ATmega48/88/168/328, 14. I/O ports -> 14.1. Overview :
However, writing a logic one to a bit in the PINx Register, will result in a toggle in the corresponding bit in the Data Register.

a samozřejmě v zapojení portu.

A k čemu ty makra použít ? Jako příklad uvedu třeba sdílení pinu výstupními signály pro 74595-ku a vstupními signály od tlačítek.
74595-ka používá signály :
DATA = Vstup sériových dat
CLK = Hodinový signál pro zápis do posuvného registru
WR = Zapisovací impuls do výstupního registru.
OE = Aktivace výstupů 74595-ky - OE=0 - data jsou na výstupech, OE=1 - výstupy jsou vypnuté.

Využití signálů je tedy následující :
OE musí zůstat v log. 0, aby byla 74595-ka aktivní. Pokud by se multiplexoval, výstupy by se zapínaly a vypínaly = není vhodné k použití.
CLK = Zapisuje data do posuvného registru. Za určitých podmínek je možné jej využít, ale není to vhodné.
WR = Přepisuje stav posuvného registru do výstupního registru 74595-ky. Za určitých podmínek je možné jej využít.
DATA = Je možné použití tohoto signálu k multiplexaci.

CLK a WR je možné k multiplexaci s tlačítkem použít, ale nelze je použít současně. Když použiješ CLK, tak se stiskem tlačítka data posouvají. Výstupní registry zůstanou, ale nesmíš je signálem WR přepsat z výstupních. Mění se ale poslední výstupní pin (Q7’) 74595-ek, který slouží k jejich řetězení. Proto je vhodnější použít pro multiplexování signál WR. Díky tomu se nemění data v posuvných registrech 74595-ek a ani jejich poslední výstupní piny, jenom se přepisují výstupní registry stále stejnými daty.

Tlačítka lze připojit jak na VCC, tak na GND (příklad počítá s připojením na GND), v každém případě ale musí být splěno to, že tlačítka jsou k signálům připojená přes odpor tak, aby ani při stisknutém tlačítku měl vstup 74595-ky hodnotu, jaká je na výstupu MCU.

[code]DIR_OUT IO_DATA595 ; Nastavit IO pin DATA pro 74595 jako výstup
CLR_OUT IO_WR595 ; Vynulovat WR signál pro 74595
DIR_OUT IO_WR595 ; Nastavit IO pin WR pro 74595 jako výstup
call zapis_data_do_74595 ; Zavolat rutinu pro zápis bytu do 74595
DIR_IN IO_DATA595 ; Nastavit IO pin DATA pro 74595 jako vstup
SET_OUT IO_DATA595 ; Aktivovat pull-up pinu DATA pro 74595
DIR_IN IO_WR595 ; Nastavit IO pin WR pro 74595 jako vstup
SET_OUT IO_WR595 ; Aktivovat pull-up pinu WR pro 74595

SKIP_IN_SET IO_DATA595 ; Přeskočit, není-li stisknuto tlačítko na pinu DATA
rcall Stisknute_tlacitko_na_DATA_lince
SKIP_IN_SET IO_WR595 ; Přeskočit, není-li stisknuto tlačítko na pinu WR
rcall Stisknute_tlacitko_na_WRITE_lince

SKIP_IN_CLK IO_DATA595 ; Přeskočit, je-li stisknuto tlačítko na pinu DATA
rcall Nestisknute_tlacitko_na_DATA_lince
SKIP_IN_CLK IO_WR595 ; Přeskočit, je-li stisknuto tlačítko na pinu WR
rcall Nestisknute_tlacitko_na_WRITE_lince
[/code]

Přeju hodně úspěchů při programování.

Pro práci se vstupy a výstupy CPU jsem si připravil makra viz níže:
Ale poraď, jak nadefinuji symbol/makro ISREG abych je mohl třeba takhle použít.

.MACRO MOV16
.IF ISREG(@0)
MOV @0 + 0, @1 + 0
MOV @0 + 1, @1 + 1
.ELSE
LDS R20, @1 + 0
STS @0 + 0, R20
LDS R20, @1 + 1
STS @0 + 1, R20
.ENDIF
.ENDMACRO

;************************************************************
; makra pro práci se vstupy a výstupy CPU
;************************************************************
;************************************************************
;* DIR_OUT - Nastaví pin na portu jako výstupní
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO DIR_OUT ;@0=port,bit (např B,2)
sbi DDR@0
.ENDMACRO

;************************************************************
;* DIR_IN - Nastaví pin na portu jako vstupní
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO DIR_IN ;@0=port,bit (např B,2)
cbi DDR@0
.ENDMACRO

;************************************************************
;* SET_OUT - výstup = 1
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO SET_OUT ;@0=port,bit (např B,2)
sbi PORT@0
.ENDMACRO

;************************************************************
;* CLR_OUT - výstup = 0
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO CLR_OUT ;@0=port,bit (např B,2)
cbi PORT@0
.ENDMACRO

;************************************************************
;* ON_PULL - vstup s PULL-UPem
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO ON_PULL ;@0=port,bit (např B,2)
sbi PORT@0
.ENDMACRO

;************************************************************
;* OF_PULL - vstup bez PULL-UPu
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO OF_PULL ;@0=port,bit (např B,2)
cbi PORT@0
.ENDMACRO

;************************************************************
;* SKIS_IN - Přeskok násl. instr. když vstup (00~1F)== 1
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO SKIS_IN ;@0=port,testovaný bit (např B,2)
sbis PIN@0
.ENDMACRO

;*************************************************************
;* SKIC_IN - Přeskok násl. instr. když vstup (00~1F)== 0
;* název pinu = např. #define pin_CLK B,2
;*************************************************************
.MACRO SKIC_IN ;@0=port,testovaný bit (např B,2)
sbic PIN@0
.ENDMACRO

;************************************************************
;* BRIS_IN - Skok když vstup (00~1F) == 1
;* název pinu = např. #define pin_CLK B,2
;*************************************************************
.MACRO BRIS_IN ;@0=port,testovaný bit, @1=cíl skoku
sbic PIN@0
rjmp @1
.ENDMACRO

;************************************************************
;* BRIC_IN - Skok když vstup (00~1F) == 0
;* název pinu = např. #define pin_CLK B,2
;************************************************************
.MACRO BRIC_IN ;@0=port,testovaný bit, @1=cíl skoku
sbis PIN@0
rjmp @1
.ENDMACRO

;************************************************************

Nadefinovat makro ISREG tak, jak si představuješ asi nepůjde nebo to nebude vůbec jednoduché. Nicméně, pro přesun mezi dvěma páry registrů existuje instrukce movw (například movw r2:r3, r0:r1). Pro přesun mezi dvěma paměťovými místy si pak můžeš nadefinovat makro MOV16 pro přesun v paměti.

Já jsem si myslel, že to nebude jednoduché, protože jsem na netu nenašel nic, čeho bych se mohl chytit, nicméně v některých programech jsou tato makra použita, takže to již někdo vymyslel a nejspíš jim to i funguje. Na ISREG se mi líbí, že při psaní programu v assembleru není potřeba rozlišovat, zda parametr @0 ukazuje na regisr nebo SRAM a makro se o vyhodnocení samo postará. Ten přesun registrového páru jsem uvedl jen jako příklad, ISREG by se dalo výborně použít i v mnoha dalších funkcích. Jen zjistit jak na to

Já to chápu. Na druhou stranu, nemá smysl se příliš dlouho zabývat něčím, co mi ušetří jen minimum námahy. Koumal s zkoušel jsem to všelijak - a upřímně, jen díky tomu, že jsem momentálně ve stavu, kdy toho moc dělat nemůžu.