Definování I/O portů v poli

Zdravím a už zase otravuji. Potřeboval bych poradit, zda lze definování I/O registrů nějak nacpat například do pole kvůli zjednodušení kódu. Například budu mít na výstupech plno relátek (nebo vstupů) rozházených různě po pinech mcu a ovládat (nebo číst stav) je budu třeba podle jednotlivých bitů v jedné proměnné např. typu int. Představoval jsem si to nějak takto, ale AvrStudio mi to nechce překousat.

uint8_t RELE_DEF[5][4] = {
		&PORTA, &DDRA, &PINA, PINA0,		// rele 1
		&PORTB, &DDRB, &PINB, PINB1,	// rele 2
		&PORTA, &DDRA, &PINA, PINA2,	// rele 3
		&PORTD, &DDRD, &PIND, PIND0,	// rele 4
		&PORTA, &DDRA, &PINA, PINA4,	// rele 5
		};

nebo nějak přes sturktůru

typedef struct {#define PORT_REG; #define DDR_REG; #define PIN_REG; #define PIN;} device;
	
	device RELE_DEF[5] = {
		PORTA, DDRA, PINA, PINA0,		// rele 1
		PORTB, DDRB, PINB, PINB1,	// rele 2
		PORTA, DDRA, PINA, PINA2,	// rele 3
		PORTD, DDRD, PIND, PIND0,	// rele 4
		PORTA, DDRA, PINA, PINA4,	// rele 5
		};

Potom by stačilo pro inicializaci, čtení nebo nastavení bitu prohnat přes nějaký cyklus, např. for{}, který by používal prvky z pole.

for (uint8_t t = 0; t < 5; t++)
	{
		*RELE_DEF[t][1] |= (1<<RELE_DEF[t][3]) // nastavení jako výstup
		// nebo RELE_DEF[t].DDR_REG |= (1<<RELE_DEF[t].PIN)
	}

Dá se to nějak tak krásně sjednotit? Mě se to zatím nijak nepodařilo. :frowning:

I/O - port je bit v nějakém registru. Mužeš mít pole struktur a tak struktura bude složená z ukazatele na ten registr a číslo bitu v něm. Ale mnohem lepší by bylo přistupovat k I/O tak jak jsem to naznačil v tomto vlakně https://forum.mcontrollers.com/t/c-a-flagy/3550/5 a přenést ty piny do své bitové struktury stylem MUJ_BIT_00=IO_00 atd.

Tak jsem zkusil sesmolit tu první variantu a po několikátém pokusu to překladač pobral jen s dvouma varováníma (1. missing braces around initializer -Wmissing-braces] a 2. (near initialization for ‘rele[0]’) -Wmissing-braces])
, ale podle simulátoru to funguje. :smiley:

#include <avr/io.h>

typedef struct  
{
	volatile uint8_t *PORT;
	volatile uint8_t *DDR;
	volatile uint8_t *PIN_REG;
	uint8_t PIN;
} device;

device rele[4] = {
	&PORTA, &DDRA, &PINA, PINA0,		// rele1
	&PORTB, &DDRB, &PINB, PINB3,		// rele2
	&PORTA, &DDRA, &PINA, PINA5,		// rele3
	&PORTC, &DDRC, &PINC, PINC6,		// rele4
	};

int main(void)
{
	uint8_t stavRele;
	for (uint8_t t = 0; t < 4; t++)
	{
		*rele[t].DDR |= (1<<rele[t].PIN);	// nastavení jako výstup
	}
    while(1)
    {
        for (uint8_t t = 0; t < 4; t++)
        {
	       if (stavRele & (1<<t)) *rele[t].PORT |= (1<<rele[t].PIN);	// nastavení nebo nulování rele podle bitu proměnné
		   else *rele[t].PORT &= ~(1<<rele[t].PIN);
			
        }
		stavRele = ~stavRele;	// neguje obsah pro vyzkoušení
    }
}

ale nejde mi do hlavy, jak jsi myslel tu druhou variantu. Co jsem pročítal to vlákno, tak tam si definuješ fci jednoho bitu, příp. pinu. To bych musel definovat fci pro každej pin a bit zvlášť. Ale potom bych asi nemohl pracovat se všemi vstupy (výstupy) z jedné funkce. Nebo teda alespoň nevím jak :frowning:

Nedefinuju funkci. Definuju jeden bit v nejakem vstupne/vystupnim portu. Je to bit v bitovem poli. Podle me je jednodussi (prehlednejsi a mozna i rychlejsi) tohle:

void NastavRele(void)
{
RELE_0=stavRele.R_0;
RELE_1=stavRele.R_1;
.
.
RELE_n=stavRele.R_n;
}

kde RELE_0 az RELE_n si nadefinujes jak jsem naznacil, nez to co jsi spachal Ty. To co definujes v tom poli struktur je dost neprehledne a nemuzes pristoupit k jednomu konkretnimu RELE primo ale zase pres nejakej software, kterej to slozi z tech hodnot v tom poli.

S tou funkcí jsem to napsal blbě. Přehlednější a rychlejší to asi bude a co jsem pochitil v tom vlákně, tak ještě rychlejší by bylo asi jak psal Balů, ale složitější na psaní

if(stavRele.R_0 == 1) RELE_0 = 1; else RELE_0 = 0;

Něco zkusím a uvidím. Nicméně děkuji za rady a hlavně odkaz na to vlákno. Zase jsem se dozvěděl něco novýho, co mi hodně zjednoduší a hlavně zpřehlední jinou věcičku.