Mikrokontroléry rady AVR – vstupno-výstupné porty

V druhom pokračovaní seriálu o jedno-čipoch s jadrom AVR som sa rozhodol opísať jednotlivé porty týchto MCU (GPIO) a ich ovládanie. Konkrétne sa budem zaoberať Atmegou32 keďže je často používaná a na tomto webe môžete nájsť aj vývojovú dosku s týmto MCU, ale uvediem aj porty, ktoré práve tento MCU nemá ale majú ich ostatné (viac vývodové) MCU.

Popis vstupno-výstupných registrov

Všetky dole popísané porty slúžia predovšetkým ako 8-bitové obojsmerné vstupno-výstupné porty s možnosťou pripojiť (softwarovo) vnútorný pull-up odpor na každý z pinov. Zápis do portov (vstupno-výstupného registra) sa deje synchrónne tzn. zapíšu sa naraz všetky zvolené bity. Ich ďalšie funkcie, ktorými disponujú sú opísané dole.

PORTA (PA7 – PA0) – slúži ako analógový vstup do AD prevodníka

PORTB(PB7 – PB0) – na tento port sú pripojené vnútorné periférie: SPI rozhranie (PB7 – PB4), analógový komparátor (PB3, PB2) a vstupy do čítačov/časovačov 0 a 1 (PB1, PB0).

PORTC(PC7 – PC0) – tento port poskytuje JTAG rozhranie, ktoré slúži na ladenie programov priamo v aplikáciách a taktiež rozhranie TWI (TwoWireInterface) alebo aj I2C (PC0, PC1).

PORTD(PD7 – PD0) – poskytuje výstupy z čítačov/časovačov (PD7, PD5, PD4), inputCapturePin (PD6), vstupy externých prerušení INT (PD3, PD2) a takisto je na tento port pripojená jednotka USART (PD1, PD0).

Okrem týchto portov existujú ešte vo viac vývodových MCU aj porty E, F, a aj G (napr. Atmega128). Ich vlastnosti a funkcie sa dajú nastavovať tzv. vstupno-výstupnými registrami, ktoré budú popísané ďalej a v/v registre ostatných periférií budú opísané v ďalších článkoch kde sa budem venovať jednotlivým vstupno-výstupným perifériám.

obr1

Obr.1 Porty na ATmega16/32

Vstupno-výstupné registre

Základné vstupno-výstupné registre, ktoré slúžia na ovládanie jednotlivých pinov portov sú:

a) PORTx – zápisom bitu na príslušné miesto bajtu do tohto registra nastavíme pin buď na log0 alebo log1 prípadne (ak nastavíme port ako vstupný) zapneme alebo vypneme pull-up rezistor. Pre povolenie funkcie týchto pull-up rezistorov je potrebné nastaviť bit PUD v registri SFIOR (automaticky).

b) DDRx – zápisom do tohto registra môžeme nastaviť príslušný pin buď ako vstupný (log0) alebo výstupný (log1).

c) PINx – register, ktorý slúži pre čítanie z portu. Teda ak chceme zistiť stav (nastavenie) pinov portu, prečítame ho z tohto registra.

Peknou ukážkou nastavenia portov a funkcií je tabuľka z datasheetu Atmega32:

obr2

Obr.2 Nastavenie portov

Zapisovanie do vstupno-výstupných registrov

V tejto časti článku chcem opísať možnosti zápisu a čítania vstupno-výstupných registrov. Uvediem príklady v dvoch jazykoch a to assembler a C.

Príklad: potrebujeme nastaviť piny PD5 a PD0 portu D ako výstupné a ich logická úroveň bude pre PD5 log0 a PD0 log1.

Máme viacero možností zápisu:

a) zápis dát v binárnej forme – možný iba v assembleri:

LDI R16, 0b00100001
OUT DDRD, R16
LDI R16, 0b00000001
OUT PORTD, R16

b) zápis dát v hexadecimálnom tvare
– pre assembler:

LDI R16, 0x21 ; podobne ďalšie riadky

– jazyk C:

DDRD = 0x21;
PORTD = 0x01;

c) zápis dát v desiatkovom tvare

d) nastavenie bitov pomocou definovaných konštánt (avr/io.h) – prehľadnejšie
– pre assembler:

LDI R16, (1<<PD0) | (1<<PD5)
OUT PORTD, R16

– jazyk C:

DDRD = (1<<PD0) | (1<<PD5);
PORTD = (1<<PD0);

Pre nastavenie jedného bitu vo v/v registri s výhodou používam v jazyku C makrá definované takto:

#define SETBIT(ADRESS,BIT) (ADRESS |= (1<<BIT))
#define CLRBIT(ADRESS,BIT) (ADRESS &= ~(1<<BIT))

Napr. pre nulovanie bitu PB2 v porte PORTB použijeme príkaz: CLRBIT(PORTB,PB2);
Z hore uvedených makier vidno spôsob nastavovania a nulovania bitu v registri. Pri použití |= alebo &= zabezpečíme aby sa ostatné bity registra nezmenili t.j. ich hodnota sa zachováva.

Často sa v programovaní využíva aj tzv. maskovanie. To je ak máme nejakú 8-bitovú premennú a pre nás je zaujímavá iba hodnota posledných (dolných) bitov tak sa tieto bity vymaskujú čiže horné bity „zmažeme“.
Pr. PORTA = 0x25; Chceme vymaskovať spodné štyri bity – čiže zachovať posledné štyri jednotky bajtu. Použijeme zápis: PORTA &= 0x0F; Po takomto zápise sa register A bude rovnať obsahu 0x05. Všetko má na svedomí logický súčin:

00100101
*00001111
----------
00000101

Pre čítanie zo v/v registra:
assembler: IN R16, TCNT0
jazyk C: unsigned char premenna; premenna = TCNT0;

Pre čítanie stavu pinu z konkrétneho portu nečítame stav z registra PORTA ale použijeme register PINA. Napríklad pri zisťovaní stavu pinu v podmienke if() použijeme formu:

if (PINB & (1<<PB0)) {} // ak bol pin PB0 nastavený na log1 tak podmienka platí
if (!(PINB & (1<<PB0))) {} // ak bol pin PB0 nastavený na log0 tak podmienka platí

Podobne sa dá pristupovať aj k bitom iných v/v registrov.
Čítanie je možné riešiť aj pomocou preddefinovaných makier v knižnici avr/io.h. Používajú sa na to funkcie bit_is_set() a bit_is_clear() :

if (bit_is_set(PINB,PB0)) {}
if (bit_is_clear(PINB,PB0)) {}

Príklady

Prikladám na stiahnutie projekty v AVRstudiu ako príklady k vývojovej doske uverejnenej na tomto webe. V assembleri je naprogramovaný ako príklad KITT na ledkách. Názorne ukazuje nastavovanie výstupných pinov portu. V jazyku C som spravil príklad kde po stlačení tlačidla sa zmení stav ledky (svieti – nesvieti). Všimnite si spôsob čítania stavu tlačidla, nastavenia pinu tlačidlo ako vstup a podobne.

Download kitt
Download tlacidlo

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *

Môžete použiť tieto HTML značky a atribúty: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>