• 1
  • 2

Digital/Analog & Input/Output

. .

Digital/Analog a Input/Output

  

Všetke nižšie navrhnuté makra a funkcie sú implementované v config_diall.h, odkaz >> Tu <<


Analogovo-Digitálny prevodník

Použitie A/D prevodníka je prvým krokom pri oživovaní procesora.
A/D prevodníkom určujeme aký typ vstupného signálu (digital/analog) bude privedený na daný vstup procesora.
Vstup procesora, ktorý podporuje A/D prevodník, sa označuje ako AN. Ostatné piny procesor ako analógové
nenastaví - nastavenie ignoruje.

Pri nastavení sa nerozlišuje na aký port je daný pin namapovaný. Berie sa len číslo podporovaného pinu.

Pre procesor PIC24FJ64GB002 sú A/D vstupy nadefinované na pinoch:
2 - (AN0, RA0)
3 - (AN1, RA1)
4 - (AN2, RB0)
5 - (AN3, RB1)
6 - (AN4, RB2)
7 - (AN5, RB3)
26 - (AN9, RB15)
25 - (AN10, RB14)
24 - (AN11, RB13)

A/D prevodníky sa nastavujú prostredníctvom AD1PCFG.

config_diall.h

#define AD_Set_Digital(__pin__) AD1PCFG |= 1<<__pin__ 
#define AD_Set_Analog(__pin__) AD1PCFG &= ~(1<<__pin__)


Makro AD_Set_Digital(0) nastaví A/D na 0. pozícií do módu digital (log. 1) .
Makro AD_Set_Analog(2) nastaví A/D na 2. pozícií do módu analog (log. 0).


Pre čo najmenšie zaťaženie procesora a zjednotenie nastavovania, navrhnem funkciu s kontrolou a ukážem na konkrétnej implementácií jej použitie. Funkcia sa podstatne hodí aj pre MCU v prevedení QFN/TQFP, kde by bol podstatný problém s počítaním jednotlivých pinov.

config_diall.h

void Init_Port (unsigned int port, int index, char* status)
{
    if(status == "digital" && _port_ != 189)
     {
        if( _Anl_pins[_port_][index]!= __No__Used_ )
          {
             AD_Set_Digital(_Anl_pins[_port_][index]);
           }
     }

   if(status == "analog" && _port_ != 189)
     {
        if( _Anl_pins[_port_][index]!= __No__Used_ )
          {
            AD_Set_Analog(_Anl_pins[_port_][index]);
          }
     }
}
 

Funkcia Init_Port obsahuje tri vstupné parametre: názov registru, číslo portu a príznak, či má ísť o analogové/digitálne nastavenie.

Funkcia využíva dvojrozmerné pole v ktorom sú definované použité registre procesora a knim čisla portov, ktoré podporujú A/D prevodník. Pokial sa overí, že daný vstup na danom porte je podporovaný, nastaví ho.
Výhodou je akési "rozdelenie" jednotlivých vstupov k jednotlivým portom registra.
Stačí nám touto funkciou vedieť názov registra a číslo podporovaného vstupu (portu), napríklad PORTB a 0, a funkcia si vypočíta z poľa, že chceme na register PORTB, port 0 (RB0) nastaviť prevodník a nastaví nám pin 4 na analog/digital.

Uľahčíme si prácu tým, že nemusíme vypočítavať číslo pinu, funkcia si ho sama zistí z konkrétneho indexu.
Pre rôzne procesory je však nutné správne definovať obsah dvojrozmerného poľa.

Ostatná konfigurácia ako: počet pinov, čísla portov, čísla nezapojených portov, piny podporované oscilátormi,... je deklarovaná v konfiguračnom prostredí config_diall.h .
Stačí nám vedieť napríklad - počet pinov, a v cykle "for" ich môžme touto funkciou nastavovať, nezapojené porty preskakovať a pod., čím sa nám celkovo zníži zložitosť algoritmov a celkový čas initu bude kratší. 


Ďaľšou možnosťou, ako nastaviť analógové porty, je možnosť použiť funkciu Init_Port2
Ukážka použitia funkcie:

config_diall.h


Init_Port2(&PORTA, 0, "analog"); // --> AN0
Init_Port2(&PORTA, 1, "analog"); // --> AN1
Init_Port2(&PORTB, 0, "analog"); // --> AN2
Init_Port2(&PORTB, 1, "analog"); // --> AN3
Init_Port2(&PORTB, 2, "analog"); // --> AN4
Init_Port2(&PORTB, 3, "analog"); // --> AN5
Init_Port2(&PORTB, 15, "digital"); // --> AN9
Init_Port2(&PORTB, 14, "digital"); // --> AN10
Init_Port2(&PORTB, 13, "digital"); // --> AN11

 

 

 

alebo :

config_diall.h


AD_Set_Analog(AN0);
AD_Set_Analog(AN1);
AD_Set_Analog(AN2);
AD_Set_Analog(AN3);
AD_Set_Analog(AN4);
AD_Set_Analog(AN5);
AD_Set_Digital(AN9);
AD_Set_Digital(AN10);
AD_Set_Digital(AN11);

 

 

 

 


Input/Output & Set port

Ďalším krokom konfigurácie MCU je nastavenie jednotlivých portov procesora ako vstupné alebo výstupné - input/output.

Periféria zapojené ako výstupné sú ovládané procesorom. Zariadenia, ktoré sú zapojené ako vstupné, ovládajú procesor.

Konfigurácia sa nastavuje pomocou I/O registrov TRISx, kde x znamená označenie registra, ktorý procesor podporuje. Procesor PIC24FJ64GB002 podporuje registre PORTA/PORTB. Z tochto dôvodu bude mať dva konfiguračné I/O registre TRISA/TRISB.
Teória používania riadiacích registrov tak, ako aj mapovanie na porty, je popísaná v článku >>Bitový posun<<.

Máme napríklad 5-bitový register PORTA, ktorého jednotlivé porty RA0-RA4 sú namapované na piny (2, 3, 9, 10, 12). Pred samotnou prácou vývoja, musíme stanoviť v akom móde majú byť nastavené. Ak chceme, aby sme mali port RA0 (druhý pin) ako vstupný, musíme do registra TRISA nastaviť na nultú pozíciu hodnotu log. 1 Naopak, ak má byť tento port výstupný, musíme na daný bit-port registra nastaviť hodnotu log. 0 .

TRISA |= 1<<0 - port RA0 nastavíme ako výstupný - log. 1 . 
TRISA &= ~(1<<0) - port RA0 nastavíme ako vstupný - log. 0.


Set Port

Ako som už vyššie spomenul, ovládanie jednotlivých bitov registra nám umožňuje PORTx, kde x nám reprezentuje označenie daného registra.

PORTA |= 1<<0 - na port RA0 nastavíme log. 1.
PORTA &= ~(1<<0) -na port RA0 nastavíme log. 0.

Z jednotlivých príkazov vidíme, že sématika je rovnaká. Mení sa nám len označenie registrov.
Aby sme nemuseli pri každej operácií zbytočne písať rovnakú syntaktiku príkazov, a aby sme mohli pracovať s portami prostredníctvom referencií - pointrov alebo v štruktúrach, navrhnem pár užitočných makier pre deklaráciu podobnej sématiky príkazov:

config_diall.h

#define Bit_Set_(_set_bit_on_,__pin__) PORT ## _set_bit_on_ |= 1<<__pin__
#define Bit_Clr_(_set_bit_clr_,__pin__) PORT ## _set_bit_clr_ &= ~(1<<__pin__)
#define Bit_Toogle_(_set_bit_tgl_,__pin__) PORT ## _set_bit_tgl_ ^= (1<<__pin__)
#define Bit_Set(_set_bit_on_,__pin__) _set_bit_on_ |= 1<<__pin__
#define Bit_Clr(_set_bit_clr_,__pin__) _set_bit_clr_ &= ~(1<<__pin__)
#define Bit_Toogle(_set_bit_tgl_,__pin__) _set_bit_tgl_ ^= (1<<__pin__);

#define Config_IN_(_set_bit_in_,__pin__) TRIS ## _set_bit_in_ |= 1<<__pin__
#define Config_OUT_(_set_bit_out_,__pin__) TRIS ## _set_bit_out_ &= ~(1<<__pin__)
#define Config_IN(_set_bit_in_,__pin__) _set_bit_in_ |= 1<<__pin__
#define Config_OUT(_set_bit_out_,__pin__) _set_bit_out_ &= ~(1<<__pin__)

#define Set_Pin_Left(_set_bit_out_,__val__,__position__) _set_bit_out_ = __val__<<__position__
#define Set_Pin_Right(_set_bit_out_,__val__,__position__) _set_bit_out_ = __val__<<__position__

#define Set_On(__set_me__) __set_me__ = ON
#define Set_Off(__set_me__) __set_me__ = OFF



1. Makra Bit_Set_, Bit_Clr_, Bit_Toogle_ berú ako vstupný parameter označenie/názov registra PORT (napríklad A) a číslo namapovaného bitu registra na pin (číslo portu).
   Príklad:
               Bit_Set_(A,0) nám nastaví na RA0 log. 1.
                Bit_Clr_(A,0) nastavuje na RA0 log. 0.
                Bit_Toogle_(A,0) zmení (zneguje) aktuálnu hodnotu daného portu RA0 na opačnú.

2. Makra Bit_Set, Bit_Clr, Bit_Toogle berú na rozdiel od makier vyššie celé označenia registrov a číslo
namapovaného bitu registra na pin (číslo portu).
   Príklad:
                Bit_Toogle(PORTB, 5) zneguje akuálnu hodnotu na porte RB5 na opačnú.

3. Makra Config_x pracujú podobne ako makra Bit_x vyššie, ale sú určené pre ovládanie registra TRIS .
Je jasné, že by sme mohli používať len makra Bit_Set a Bit_Clr a ako prvý vstupný parameter by sme obmieňali registre PORTA/TRISA/..., avšak, nie je zlé vytvoriť rovnaké makra inak pomenované. Vyhneme sa možným nedorozumeniam alebo chaosu pri písaní dlhých kódov.

4. Makra Set_Pin_Lenft, Set_Pin_Right berú ako vstupné parametre hodnoty - log. 1/log. 0 a počet miest o ktoré sa má hodnota posunúť a nastaviť (doprava/doľava).

5. Makra Set_On, Set_Off slúžia ako pomocné a dovoľujú nastaviť hodnotu passovanej premennej "set_me" na ON - log. 1/Off - log. 0.
   Príklad:
                Set_Off(RB4_) - nastaví port RB4 ako výstupný.
                Set_On(RB4) - nastaví na port RB4 log 1.



Load port

Ako nastavovanie logických úrovní na porty registrov, potrebujeme neakým spôsobom tieto úrovne aj načitávať a spracovať, napríklad: tlačidlá, optočleny, opto-interupty,... .

V prvej časti sme si ukázali, ako nastaviť neaký port vstupným alebo výstupným a teraz je nutné si uvedomiť, že zistenie logickej úrovne na portoch nezávisí od toho, či je port vstupný alebo výstupný.
Inými slovami, rovnakým spôsobom zisťujeme aktuálne logické hodnoty portov ako na vstupoch, tak aj na výstupoch.

Navrhnuté makrá:


config_diall.h

#define Get_Value(__reg__,__port__) __reg__ & (1 << __port__)
#define Get_Switch(__reg__,__port__) ~Get_Value(__reg__,__port__)
#define ReSwitching(__x__) ~(__x__)



Get_Value(PORTB,8) - pokiaľ sa na 8. porte registra PORTB (RB8) nachádza log. 1, vráti "1".
Get_Switch(PORTB,8) - vracia znegovanú hodnotu prvého makra (použ. pri tlačidlách zavedených na GND).
ReSwitching(Get_Switch(PORTB,8)) - umožňuje vrátiť znegovanú hodnotu premennej alebo podcelku (funkcie).


Pri písaní projektov si všetky makrá, funkcie a ich spôsob práce osvojíme pod kožu.