AVRstudio a definovanie pinov

Mohol by mi niekto ukazat ako a ci sa da nejako jednoducho v Ccku nastavavat a definovat porty u ATmega8.

Napr PIC a prekladac od mikrocipu umiznuje nieco take:

#define clrp PORTCbits.RC0
#define clr PORTCbits.RC6
#define down PORTCbits.RC7
#define clkp PORTEbits.RE0

potom v programe staci uz len:

clrp=1; nastavi log 1 na Porte C0
clrp=0;

pripadne ide If (clk==0)…

Lebo S AVRstudio a WIN avr … viem nastavovat porty len tymi prisern9mi vecami:

PORTD |=0b00000001; no vyzera to hrozne na okamzite pochopenie
a potom
PORTD &=0b01111111;

Tak ak niekto ie jednoduchy a prehladny sposob ako nato budem rad ak mi ho ukaze. Aby bolo hned jasne s cim sa pracuje ako u picka.
Dakujem…

napriklad def_io_v01.h:

#define	IOB_11  2	// PD2
#define	OUT_IOB_11 	  (DDRD |= (1<<IOB_11))	
#define	IN_IOB_11 	  (DDRD &= ~(1<<IOB_11))	
#define	SET_IOB_11 	  (PORTD |= (1<<IOB_11))
#define	RES_IOB_11 	  (PORTD &= ~(1<<IOB_11))
#define	GET_IOB_11 	  (PIND & (1<<IOB_11))

#define	IOB_12  3	// PD3
#define	OUT_IOB_12 	  (DDRD |= (1<<IOB_12))	
#define	IN_IOB_12 	  (DDRD &= ~(1<<IOB_12))	
#define	SET_IOB_12 	  (PORTD |= (1<<IOB_12))
#define	RES_IOB_12 	  (PORTD &= ~(1<<IOB_12))
#define	GET_IOB_12 	  (PIND & (1<<IOB_12))


#define	RX0	  0	// PD0, RX0
#define	OUT_RX0 	  (DDRD |= (1<<RX0))	
#define	IN_RX0 	  (DDRD &= ~(1<<RX0))	
#define	SET_RX0 	  (PORTD |= (1<<RX0))
#define	RES_RX0 	  (PORTD &= ~(1<<RX0))
#define	GET_RX0 	  (PIND & (1<<RX0))

#define	TX0	  1	// PD1, TX0
#define	OUT_TX0 	  (DDRD |= (1<<TX0))	
#define	IN_TX0 	  (DDRD &= ~(1<<TX0))	
#define	SET_TX0 	  (PORTD |= (1<<TX0))
#define	RES_TX0 	  (PORTD &= ~(1<<TX0))
#define	GET_TX0 	  (PIND & (1<<TX0))

#define	COM0_SMER	  0	// PD0, RX0  
#define	OUT_COM0_SMER 	  (DDRD |= (1<<COM0_SMER))
#define	IN_COM0_SMER 	  (DDRD &= ~(1<<COM0_SMER))
#define	SET_COM0_SMER 	  (PORTD |= (1<<COM0_SMER))	
#define	RES_COM0_SMER 	  (PORTD &= ~(1<<COM0_SMER))
#define	GET_COM0_SMER 	  (PIND & (1<<COM0_SMER))	

a potom v

program_v01.c

// .... vsetky potrebne include pre ten ktory procesor, rozpisovat nebudem
#include "def_io_v01.h"

// funkcia jednoducheho invertora
int main(void)
{
   IN_IOB_21;
   OUT_IOB_11
   for(;;) {
    
     if (GET_IOB_21) RES_IOB_11; // zatvorky okolo GET_IOB_21 su zbytocne, ale kvoli prehladnosti sa hodia
     else SET_IOB_11;

   }

}

A kedze uz vidim, ako sa tu odporcovia C-cka na jednocipy jezia (v dobrom, samozrejme :slight_smile: ), lebo oni by to urcite v asm napisali efektivnejsie, ako manipulovat s celym portom, akoby sa zdalo z napisanych makier.

Tak uvadzam disasembler, aby bolo jasne, ze ak sa pouzije rozumny prekladac (v mojom pripade GCC cez WinAVR, optimalizacia -Os), tak preklad nemusi byt neefektivny. Prekladac totizto vie, kedy pouzit instrukcie bitovej manipulacie s pinmi portov a kedy treba pouzit manipulaciu s celym bajtom.

126:      			IN_IOB_21;
+00000716:   9854        CBI       0x0A,4         Clear bit in I/O register
127:      			OUT_IOB_11;
+00000717:   9A3B        SBI       0x07,3         Set bit in I/O register
128:      			if (GET_IOB_21) {
+00000718:   9B4C        SBIS      0x09,4         Skip if bit in I/O register set
+00000719:   C002        RJMP      PC+0x0003      Relative jump
129:      				RES_IOB_11;
+0000071A:   9843        CBI       0x08,3         Clear bit in I/O register
+0000071B:   C001        RJMP      PC+0x0002      Relative jump
132:      				SET_IOB_11;
+0000071C:   9A43        SBI       0x08,3         Set bit in I/O register

Pri -O0 to tak samozrejme neprelozi, lebo -O0 hovori: “co si si napisal, to dostanes”, ale uz od -O2 je to zoptimalizovane v takomto tvare.

I napriek tomuto prikladu efektivneho prekladu verim, ze rozsiahlejsi program napisany v C moze byt az 2x dlhsi a 2xpomalsi oproti tomu, ako to vie napisat odbornik asemblerista. Vzhladom na nizky vyskyt odbornikov asembleristov a vysoky vyskyt Flash v procesore sa mi to nezda byt ako velmi nevyhodny pomer.
Ak vsak ide o rychlost bez moznosti zmenit procesor, treba to zvazit.

Cislovanie riadkov si nevsimajte, dopisal som si to do mojho aktualneho projektu a hned to aj mazem :slight_smile:
[/code]

Ok dakujem zacnem si zvykat :slight_smile:

Urcite sa oplati. Je to daleko efektivnejsie i kvoli moznosti vyuzit kod z inych zdrojov. Zatial som nenarazil na problemy rychlosti. :slight_smile:

Ahojte
potreboval by som definovat v avr studiu byte. Byte ktory bude obsahovat osem roznych pinov z roznych portov. Cize napr. PB3,PB4,PD1,PC5 atd. Aky sposobom sa to definuje?

alongo:
Ja by som to vyriešil rutinkou, ktorá bude mať vstup byte, a vo vnútri si bity rozloží na príslušné piny. Ak sa to dá aj inak, rád sa poučím od iných.

Např. pro rychlý přístup rozpitvat na jednotlivé bity:

/* struktura: bit3: PC5, bit2: PD1, bit1: PB4, bit0: PB3 */ #define READ_BYTE() ((PORTB>>3)&3)|((PORTD&2)<<1)|((PORTC&0x20)>>2) inline void WRITE_BYTE(char data) { PORTB = (PORTB & ~0x18) | ((data & 3) << 3); PORTD = (PORTD & ~2) | ((data & 4) >> 1); PORTC = (PORTC & ~0x20) | ((data & 8) << 2); }
Nebo pro univerzálnější přístup tabulka:

[code]typedef struct MPORT_ { volatile unsigned char* port; char bit; } MPORT;

MPORT PortTab1[4] = { { &PORTB, 3 }, { &PORTB, 4 }, { &PORTD, 1 }, { &PORTC, 5 } };

unsigned char ReadByte(MPORT* mport, char bitnum) {
unsigned char d = 0;
mport += bitnum;
for (; bitnum > 0; bitnum–) {
d <<= 1;
d |= (mport->port >> mport->bit) & 1;
mport–;
}
return d;
}
void WriteByte(unsigned char data, MPORT
mport, char bitnum) {
for (; bitnum > 0; bitnum–) {
*mport->port = (*mport->port & ~(1 << mport->bit)) | ((data & 1) << mport->bit);
mport++;
}
}[/code]

EDIT: Oprava, pro READ funkce se musí použít PINx namísto PORTx.

Pozeram ze nie je to az take jednoduche ako som si predstavoval :slight_smile:. Vdaka za tip vyskusam to.

Takze:

#define READ_BYTE() mi nefunguje nechapem preco.

Co sa tyka funkcie WRITE_BYTE to mi ide v pohode len by som poprosil vysvetlenie preco posledny riadok: PORTC = (PORTC & ~0x20) | ((data & 8) << 2); na konci je bitovy posun do lava. Predpokladam ze tymto posunom urcujem na ktorom mieste bude bit v premenej “data”

Aha chyba, v READ funkcích se musí použít PINx, ne PORTx. To je špatně i u těch tabulkových funkcí.

U toho WRITE_BYTE se datový bit 3 posílá na bit 5 portu C, proto je oprava pozice o 2 bity doleva (5 - 3).

Neviem ci som dobre pochopil ale vyskusal som poskladat byte takto:

[code]/* struktura: bit6: PD4, bit5: PD3, bit4: PD2, bit3: PA0, bit2: PA1, bit1: PD1, bit0: PD0 */

inline void WRITE_BYTE(char data) {
PIND = (PIND & ~0x03) | (data & 3);
PINA = (PINA & ~0x02) | ((data & 4) >> 1);
PINA = (PINA & ~0x01) | ((data & 8) >> 3);
PIND = (PIND & ~0x1C)| ((data & 0x70) >> 2);

}[/code]

Funguje to v poriadku ked tam jednorazovo napisem hodnotu. Ale problem je ked dam funkciu, delay, funkciu tak to neprepise na novu hodnotu.

napr:

[code]while(1){
test = 0x05;
WRITE_BYTE(test);
_delay_ms(1000);

	test = 0x07;
	WRITE_BYTE(test);
	_delay_ms(1000);

}[/code]

Ne, ve WRITE funkci musí být použitý PORTx. PINx je pro čtecí funkci.

Takto si to myslel?

PORTD = (PIND & ~0x03) | (data & 3);

Ok problem vyrieseny. Teraz to funguje korektne. Panda38 vdaka za pomoc mal si pravdu problem bol ze som mal tam napisane PINx namiesto PORTx.

Takhle, ale zřejmě jsi na to už přišel:

PORTD = (PORTD & ~0x03) | (data & 3);

Ano presne takto ako si to napisal vdaka este raz :slight_smile:

Nedalo mi to tak som to vyskusal este cez “define” takto:

#define READ_BYTE() ((PINB>>3)&3)|((PIND&2)<<1)|((PINC&0x20)>>2) 

Lenze stale mi to nefunguje aj ked som zmenil PORTx na PINx ale nic sa nedeje. Zapisal som to takto

[code] test = 0x0F;

 	test = READ_BYTE();[/code]

Vyskúšaj toto:

[code]#define READ_BYTE() ((PINB>>3)&3)|((PIND&2)<<1)|((PINC&0x20)>>2)

test = 0x00;
test |= READ_BYTE();
[/code]

a daj vedieť či to stále nefunguje.

Myslím si však, že s tou rutinou, ktorú som spomínal úplne na začiatku by to bolo menej náročné na programovú pamäť ako cez define.

sqad takze nefunguje to ani tym sposobom. Nemyslel si taku rutinu, ktoru sme tu preberali (WRITE_BYTE)?

Myslis ked to budem riesit cez define bude to narocnejsie na programovu pamät?
Respektive co by bolo najvhodnejsie pouzit aby to zabralo co najmenej pamate.

Vyskúšaj tento program, malo by to ísť:

[code]#include <avr/io.h>

#define nop(); asm(“NOP”);
#define READ_BYTE() ((PINB>>3)&3)|((PIND&2)<<1)|((PINC&0x20)>>2)

//*************************************************************************************
// MAIN PROGRAM

void main(void)
{
char volatile test;

while (1)
{
	nop();
	test = 0x00;
	test |= READ_BYTE();
	nop();
}

}
[/code]

Predtým ti to asi nefungovalo kvôli tomu, že si mal zapnuté optimalizácie v projekte, a potom čo si do premennej test zapísal, ale ďalej si ju nepoužíval, kompilátor ju jednoducho vyhodil.
Preto je v tomto pri definovaní premennej test uviesť volatile - tým zadáš, že kompilátor nemá optimalizovať premennú test.

Rutinou som myslel takú, ktorá bude mať pre zápis vstup byte, a vo vnútri si bity rozloží na príslušné piny, alebo pre načítavanie bude v jej vnútri ,zozbieranie" log. hodnôt z pinov, a výstup bude byte.

Na to či je lepšie načítavať z pinov cez define alebo rutinu, budú asi rôzne názory.
Podľa mňa, keď si zvolíš postup cez define, potom sa v programe všetko označené ako
,READ_BYTE()"
prepíše na
,((PINB>>3)&3)|((PIND&2)<<1)|((PINC&0x20)>>2)".

Ak by si však použil rutinu, spracovanie by možno trvalo trochu dlhšie, avšak to isté miesto v programe by si využil viac krát. Preto si myslím, že rutina je z tohto dôvodu výhodnejšia, hlavne vtedy, ak by si funkciu ,read_byte()" použil veľa krát.

Ak kecám, tak ma opravte.