Digitális ki- és bemenetek használata

A fejezet tartalma:
A mikrovezérlők legegyszerűbb perifériái az általános célú digitális ki- és bemenetek (general purpose I/O, röviden GPIO). Ezeket a hatékonyabb kezelés érdekében a mikrovezérlő adatút-szélességének megfelelően (esetünkben 32 bites) csoportokba rendezve kezelhetjük. Ezeket a rendezett csoportokat portoknak nevezzük. A Freescale Kinetis MKL25Z128VLK4 mikrovezérlő összesen 80 kivezetéssel rendelkezik, melyek közül 66 használható általános célú ki/bemenetként. Ezek a kivezetések 5 db 32 bites portba vannak szervezve (PortA, PortB, PortC, PortD, PortE), amelyeknek természetesen nincs minden bitje implementálva (5  db 32 bites port  akár 160 ki/bemenetet is  tartalmazhatna). Egy-egy port írása egyetlen utasítással, egyetlen órajel alatt elvégezhető - ez az értelme a portokba szervezésnek.

1. ábra: Az MKL25Z128VLK4 mikrovezérlő lábkiosztása

Természetesen arra is van lehetőség, hogy a portokon belül a kivezetéseket külön-külön kezeljünk: az üzemmód és adatáramlási irány beállítása, a kimenet írása, vagy a bemenet állapotának lekérdezése akár egyenként is történhet. Ilyenkor a porthoz tartozó regiszterek valamelyik bitjét vagy bitcsoportját írjuk/olvassuk, amihez a MKL25Z128VLK4 mikrovezérlő hatékony eszközt, egy Bit Manipulációs Egységet biztosít (BME).

A GPIO portok engedélyezése

Az ARM Cortex-M mikrovezérlőknél induláskor (vagy RESET után) általában minden periféria le van tiltva, hogy az áramfelvétel minél kisebb legyen. Első lépésként tehát a használni kívánt GPIO portot (a későbbiekben pedig majd minden perifériát, amit használni szeretnénk) először engedélyezni kell. A GPIO portok engedélyezése a Rendszer-integrációs modul (SIM) System Clock Gating Control Register 5 (SIM_SCGC5) nevű regiszterének beállításával történik. A SIM modul leírása a Freescale KL2x Reference Manual 12. fejezetében található.

A SIM_SCGC5 regiszter címe = 0x40048038, a portok engedélyezése az alábbi bitekhez kapcsolódik:
Bit
Port
Funkció leírása
9
PORTA
Az A port letiltása (0), vagy engedélyezése (1)
10
PORTB
A B port letiltása (0), vagy engedélyezése (1)
11
PORTC
A C port letiltása (0), vagy engedélyezése (1)
12
PORTD
A D port letiltása (0), vagy engedélyezése (1)
13
PORTE
Az E port letiltása (0), vagy engedélyezése (1)

Port kivezetések üzemmódjának vezérlése

Ha engedélyezünk egy portot, annak jele még nem feltétlenül jut el a mikrovezérlő lábaira. A lábaknak ugyanis többféle funkciója lehet (ezt multiplexelésnek hívjuk), s kivezetésenként egy-egy regiszter tartalma szabja meg, hogy az adott kivezetés milyen funkciót lásson el, s ha GPIO kivezetés, akkor ki- vagy bemenet legyen stb. Az egyes kivezetések üzemmódjának beállítása a Portvezérlő modul (bővebben lásd a Freescale KL2x Reference Manual 11. fejezetében)  PORTx_PCRn (Port Pin Control) speciális funkciójú regiszterek segítségével történik. Itt x a port jele (A – E), n pedig a porton belüli bitsorszám (0 – 31).

Azt a FRDM-KL25Z Pinouts dokumentumban találjuk meg. hogy a mikrovezérlő melyik lába melyik porthoz van besorolva, s hogy az általános célú I/O mellett milyen alternatív funkciók közül választhatunk. Példa gyanánt itt csak a PTA0 – PTA4 lábak lehetséges funkcióit soroljuk fel
Pin
Alt0
Alt1
Alt2
Alt3
Alt4
Alt5
Alt6
Alt7
PTA0
TSI0_CH1
PTA0
-
FTM0_CH5
-
-
-
SWD_CLK
PTA1
TSI0_CH2 PTA1
UART0_RX
FTM2_CH0 -
-
-

PTA2
TSI0_CH3 PTA2
UART0_TX
FTM2_CH1 -
-
-

PTA3
TSI0_CH4 PTA3
I2C1_SCL
FTM0_CH0 -
-
-
SWD_DIO
PTA4
TSI0_CH5 PTA4
I2C1_SDA
FTM0_CH1 -
-
-
NMI_b

A portkivezetések konfigurálása

Minden portkivezetéshez tartozik egy PORTx_PCRn speciális funkciójú regiszter, amelynek segítségével az adott kivezetés konfigurálható. A PORTx_PCRn regiszterek bitkiosztása az alábbi ábrán látható. A regiszterek magasabb helyiértékű fele a portkivezetések külső megszakítási forrásként történő  használatával kapcsolatos. Az alacsonyabb helyiértékű 16 bit  pedig a  funkció kiválasztásával (MUX bitcsoport),  illetve a kivezetés fizikai tulajdonságainak konfigurálásával kapcsolatosak.


2. ábra: A PORTx_PCRn regiszterek bitkiosztása

Az egyes bitek, vagy bitcsoport szerepe az alábbi táblázatban található:
Bit
Funkció leírása
PS
Pull-up select: Belső fel- vagy lehúzás kiválasztása (0: lehúzás, 1: felhúzás)
PE
Pull-up enable: Belső fel- vagy lehúzás engedélyezése (0: tilt, 1: enged)
SRE
Slew rate enable: felfutási sebesség korlátozásának engedélyezése (0: tilt, 1: enged)
PFE
Passive filter enable: passzív szűrő engedélyezés (0: tilt, 1: enged)
DSE
Drive Strength Enable: a kimeneti erősségének beállítása (0: alacsony, 1: magas)
MUX
Funkcióválasztás (0: analóg, 1: GPIO, 2 - 7: Alt2 - Alt7 választása)
Az adott portkivezetéshez tartozó PORTx_PCRn regiszter MUX bitcsoportjával – mint egy fokozatkapcsolóval – választhatjuk ki, hogy az adott kivezetés melyik funkciót szolgálja ki.

Például állítsuk a PTA3 kivezetést GPIO módba! Ehhez a PORTA_PCR3 regiszter MUX bitcsoportjába 1-et kell írnunk. Ahhoz, hogy a bitek a megfelelő helyiértékre kerüljenek, a biteket 8 bináris helyiértékkel balra kell tolni, így 1 helyett 0x100-at vagy (1 << 8)-at kell írnunk:
PORTA_PCR3 = 0x100      // PTA3 GPIO módba kerül
Nézzünk egy másik példát! Állítsuk a PTA3 kivezetést I2C módba! Ekkor a PORTA_PCR3 regiszter MUX bitcsoportjába 2-t kell írnunk, azaz a regiszterbe 0x200 vagy (2 << 8) írandó:
PORTA_PCR3 = 0x200      // PTA3 I2C módba kerül
Megjegyzés: A lentebb bemutatásra kerülő mintaprogramjaink szintaxisa egy kicsit eltér a Freescale KL2x Reference Manual 11. fejezetében és a fentebb használt elnevezésektől. A MKL25Z4.h fejléc állományban ugyanis, ami a Keil.Kinetis_KLxx_DFP.1.12.0.pack-ban települ, a portokhoz rendelt struktúrákban, tömbként (sorszámmal indexelhető formában) vannak definiálva a PORTx_PCRn regiszterek. Ennek megfelelően a hivatkozás formája portnév->PCR[index] formájú is lehet, például PORTA->PCR[3]. Kompatibilitási okokból azonban alias névként a PORTx_PCRn regiszternevek is definiálva vannak.

Makrodefiníciók a portvezérlő regiszterekhez

Nézzünk bele a MKL25Z4.h fejléc állományba! A portvezérlő regiszterek kapcsán ezeket a definíciókat látjuk:

1. lista: A portvezérlő regiszterek definiálása az MKL25Z4.h fejléc állományban (részlet)
/** PORT - Register Layout Typedef */
typedef struct {
__IO uint32_t PCR[32]; // Pin Control Register n, offset: 0x0, step: 0x4
__O uint32_t GPCLR; // Global Pin Control Low Register, offset: 0x80
__O uint32_t GPCHR; // Global Pin Control High Register, offset: 0x84
uint8_t RESERVED_0[24];
__IO uint32_t ISFR; // Interrupt Status Flag Register, offset: 0xA0
} PORT_Type

/** Peripheral PORTA base address */
#define PORTA_BASE (0x40049000u)
#define PORTA ((PORT_Type *)PORTA_BASE)

/** Peripheral PORTB base address */
#define PORTB_BASE (0x4004A000u)
#define PORTB ((PORT_Type *)PORTB_BASE)
...

Az MKL25Z4.h fejléc állományban a portvezérlő regiszterek tartalmának kényelmes feltöltéséhez a bitmezőkhöz is találunk makró definíciókat, melyek segítségével a port konfigurálást így is írhatjuk.
//PTA3 kivezetés GPIO módba állítva,  kimenet erőssége: magas és slew rate engedélyezve
PORTA->PCR[3] = PORT_PCR_MUX(1) | PORT_PCR_DSE(1) | PORT_PCR_SRE(1)

A GPIO portok elérése

Ha engedélyeztük a használni kívánt portokat és beállítottuk a kivezetések üzemmódját, akkor a konfigurált portokat írhatjuk/olvashatjuk. A kérdés csupán az, hogy merre találjuk, hogyan címezhetjük meg ezeket?

Először is, minden porthoz tartozik hat regiszter. Ezt a regiszterkészletet az MKL25Z4.h fejléc állományban célszerűen struktúraként definiálták. Másodszor pedig minden portnak van úgynevezett báziscíme, ami az említett regiszterkészlet kezdőcímét jelenti. Az ARM Cortex-M0+ mikrovezérlőknél a GPIO portoknak  - a kétféle elérés miatt - két ilyen báziscím is van:
Az MKL25Z128VLK4 mikrovezérlő GPIO portjainak báziscímei
GPIO báziscímek
FGPIO báziscímek
GPIO Port A (APB): 0x400F F000
FGPIO Port A (AHB): 0xF80F F000
GPIO Port B (APB): 0x400F F040
FGPIO Port B (AHB): 0xF80F F040
GPIO Port C (APB): 0x400F F080
FGPIO Port C (AHB): 0xF80F F080
GPIO Port D (APB): 0x400F F0C0 FGPIO Port D (AHB): 0xF80F F0C0
GPIO Port E (APB): 0x400F F100 FGPIO Port E (AHB): 0xF80F F100
A GPIO regiszterek címzése a struktúra kezdőcímére mutató báziscím és a struktúraelem megnevezésének kombinálásával történik, mint például: PTB->PDOR, vagy PTA->PDIR.

Megjegyzés: PTA, PTB, PTC, PTD és PTE csupán aliasok a GPIOA, GPIOB, GPIOC, GPIOD, GPIOE nevekhez!

A portok regiszterkészletének elérését az MKL25Z4.h fejléc állományban így definiálták:

2. lista: A GPIO portok regiszterkészletének definiálása az MKL25Z4.h fejléc állományban (részlet)
//GPIO regiszter struktúra
typedef struct {
__IO uint32_t PDOR; // Port Data Output Register, offset: 0x0 */
__O uint32_t PSOR; // Port Set Output Register, offset: 0x4 */
__O uint32_t PCOR; // Port Clear Output Register, offset: 0x8 */
__O uint32_t PTOR; // Port Toggle Output Register, offset: 0xC */
__I uint32_t PDIR; // Port Data Input Register, offset: 0x10 */
__IO uint32_t PDDR; // Port Data Direction Register, offset: 0x14 */
} GPIO_Type;

/* GPIO - Peripheral instance base addresses */
#define GPIOA_BASE (0x400FF000u)
#define GPIOA ((GPIO_Type *)GPIOA_BASE)

#define GPIOB_BASE (0x400FF040u)
#define GPIOB ((GPIO_Type *)GPIOB_BASE)

#define GPIOC_BASE (0x400FF080u)
#define GPIOC ((GPIO_Type *)GPIOC_BASE)

#define GPIOD_BASE (0x400FF0C0u)
#define GPIOD ((GPIO_Type *)GPIOD_BASE)

#define GPIOE_BASE (0x400FF100u)
#define GPIOE ((GPIO_Type *)GPIOE_BASE)

A GPIO portok regiszterkészlete

PDOR – Kimeneti adatregiszter. Amit ebbe a regiszterbe írunk, az jelenik meg az egyes bitekhez tartozó kivezetésen, ha az engedélyezve van és GPIO kimenetként van konfigurálva.

PSOR – 1-be állító regiszter. Az ebbe írt 1-eseknek megfelelő helyiértékeken a PDOR regiszter bitjei is 1-be állnak be. Ahová 0-t írtunk, azokon a helyiértékeken a PDOR tartalma nem változik, megőrzi előző állapotát.
 
PCOR – 0-ba törlő regiszter. Az ebbe írt 1-eseknek megfelelő helyiértékeken a PDOR regiszter bitjei 0-ba törlődnek. Ahová 0-t írtunk, azokon a helyiértékeken a PDOR tartalma nem változik, megőrzi előző állapotát.

PTOR – bit átbillentő regiszter. Az ebbe írt 1-eseknek megfelelő helyiértékeken a PDOR regiszter bitjei ellenkező állapotba billenek. Ahová 0-t írtunk, azokon a helyiértékeken a PDOR tartalma nem változik, megőrzi előző állapotát.

PDIR – bemeneti adatregiszter. Ezt olvassuk, ha a portkivezetések állapotát akarjuk beolvasni. Megjegyezzük, hogy a beolvasás nem csupán a bemenetre állított lábakon lehetséges, hanem minden digitális módba konfigurált kivezetés pillanatnyi állapota beolvasható!

PDDR – adatáramlási irány. Ebben a regiszterben állíthatjuk be, hogy a GPIO port egyes bitjeihez tartozó kivezetések kimenetként vagy bemenetként működjenek: 0: bemenet, 1: kimenet.

Az alábbi ábrán egyetlen GPIO kivezetés áramkörének  vázlatát mutatjuk be, melyen jól látható a  GPIO regiszterek szerepe.


3. ábra: Egy GPIO kivezetés meghajtó áramkörének sematikus vázlata


Mintapéldák

Az alábbi példaprogramokat Muhammad Ali Mazidi, Shujen Chen, Sarmad Naimi, Sepehr Naimi: Freescale ARM Cortex-M Embedded Programming című könyvének mintapéldái közül válogattuk.

Az eredeti mintaprogramokon az alábbi változtatásokat eszközöltük:
A FRDM-KL25Z kártyán a közös anódú RGB LED miatt a vezérlés negatív logikájú: akkor világít a LED, amikor a hozzá kapcsolt GPIO kimenet alacsony szintre húzza a katódot. Az RGB LED Cree gyártmányú, CLV1A-FKB-CJ1M1F1BB7R4S3 típusú. Adatlapja: CLV1A-FKB_Rev5.pdf.

Fontosabb paraméterei:

4. ábra: Az RGB LED bekötése a FRDM-KL25Z kártyán

Program2_1: regisztercímek definiálása

A kártyára épített zöld LED villogtatása. Amint a 4. ábrán láthatjuk, a LED a PTB19 kivezetésre csatlakozik, s mivel a LED anódja fixen a tápfeszültségre van kötve, a PTB19 kimenet alacsony szintre húzása kapcsolja be a LED-et. Ezért ügyeljünk arra, hogy negatív logikában gondolkodva írjuk meg a programot! A használt regiszterek címét ebben a programban mi definiáljuk.

Ez a program tulajdonképpen ugyanaz, amit "Az első projekt létrehozása" című fejezetben bemutattunk, ezért az ott leírt lépéseket kell végrehajtanunk a projekt létrehozásakor. Sikeres fordítás és programletöltés esetén a RESET gomb megnyomása után a zöld LED kb. 1 Hz-es frekvenciával villog.

3. lista: Program2_1/main.c listája
/* Program2_1
*
* A FRDM-KL25Z kártyára épített zöld LED (PTB19) villogtatása.
* A regiszterek eléréséhez magunk definiálunk szimbolikus neveket.
*
* A program forrása: Mazidi et al., Freescale ARM Cortex-M Embedded Programming
* http://www.microdigitaled.com/ARM/Freescale_ARM/Code/Ver1/Chapter2/Program2_1.txt
*/
#define SIM_SCGC5 (*((volatile unsigned int*)0x40048038))
#define PORTB_PCR19 (*((volatile unsigned int*)0x4004A04C))
#define GPIOB_PDDR (*((volatile unsigned int*)0x400FF054))
#define GPIOB_PDOR (*((volatile unsigned int*)0x400FF040))

int main (void) {
void delayMs(int n); // Elore deklaráljuk a delayMs() függvényt
SIM_SCGC5 |= 0x400; // Port B órajelének engedélyezése (bit10=1)
PORTB_PCR19 = 0x100; // PTB19 pin legyen GPIO (MUX = 1, Alt1 mode)
GPIOB_PDDR |= 0x80000; // PTB19 legyen kimenet (bit 19 = 1)
while (1) { // Végtelen ciklus...
GPIOB_PDOR &= ~0x80000; // Zöld LED felkapcsolása (bit19 = 0)
delayMs(500); // 500 ms várakozás
GPIOB_PDOR |= 0x80000; // Zöld LED lekapcsolása (bit19 = 1)
delayMs(500); // 500 ms várakozás
}
}
void delayMs(int n) { // Késlelteto függvény
int i, j;
for(i = 0 ; i < n; i++)
for (j = 0; j < 3500; j++); // Alapértelmezett órajelhez (20.97152 MHz)
}
A zöld LED vezérléséhez az alábbi regisztereket definiáltuk:
A CMSIS Core támogatásnak köszönhetően a vektortábla feltöltésével és az alapértelmezett rendszer órajel beállításával nem kell foglalkoznunk. Amikor a main() függvény meghívásra kerül, addigra ezek a lépések már megtörténnek. Ha másként nem rendelkeztünk, az alapértelmezett órajel 20.97152 MHz lesz. Ehhez igazítottuk a késleltetéshez használt delayMs() függvényben szereplő konstans értékét. Ez a primitív, kétszeres for ciklussal végzett késleltetés természetesen nem pontos és az alkalmazott fordítótól, illetve annak optimalizálási beállításaitól is függ a végrehajtási ideje. A késleltető függvénynek ezredmásodpercekben adhatjuk meg, hogy meddig várakozzon.

Program2_4: előre definiált regiszter struktúrák használata

Ebben a programban is a kártyára épített zöld LED villogtatjuk. Azonban a változatosság kedvéért a regiszterek eléréséhez most az MKL25Z4.h fejléc állományban azokat az előre definiált struktúrákat használjuk, amelyeket a fejezet elején ismertettünk.

4. lista: Program2_4/main.c listája
/* Program2_4
*
* A FRDM-KL25Z kártyára épített zöld LED (PTB19) villogtatása
* A regiszterek eléréséhez használt struktúrákat most a
* Keil MKL25Z4.h nevu fejléc állománya definiálja számunkra,
* amit be kell csatolnunk a program elején.
*
* A program forrása: Mazidi et al., Freescale ARM Cortex-M Embedded Programming
* http://www.microdigitaled.com/ARM/Freescale_ARM/Code/Ver1/Chapter2/Program2_4.txt
*/

#include <MKL25Z4.h>

int main (void) {
void delayMs(int n); // Elore deklaráljuk a delayMs() függvényt
SIM->SCGC5 |= 0x400; // Port B órajelének engedélyezése (bit10=1)
PORTB->PCR[19] = 0x100; // PTB19 pin legyen GPIO (MUX = 1, Alt1 mode)
PTB->PDDR |= 0x80000; // PTB19 legyen kimenet (bit 19 = 1)
while (1) { // Végtelen ciklus...
PTB->PDOR &= ~0x80000; // Zöld LED felkapcsolása (bit19 = 0)
delayMs(500); // 500 ms várakozás
PTB->PDOR |= 0x80000; // Zöld LED lekapcsolása (bit19 = 1)
delayMs(500); // 500 ms várakozás
}
}

void delayMs(int n) { // Késlelteto függvény
int i, j;
for(i = 0 ; i < n; i++)
for (j = 0; j < 3500; j++); // Alapértelmezett órajelhez (20.97152 MHz)
}
Az eltérő jelölések használatától eltekintve a program felépítése és működése megegyezik az előzővel.

Program2_5: a bitmanipulációs regiszterek használata

Ebben a programban is a kártyára épített zöld LED villogtatjuk. A villogtatást azonban most nem a PTB->PDOR kimeneti adatregiszter megcímzésével végezzük, az ugyanis nem túl hatékony és főleg nem atomi művelet (egy tartalom beolvasása - módosítása - visszaírása ciklust hajtunk végre, amelyet egy programmegszakítás megszakíthat). Ebben a programban a PSOR, PCOR illetve a PTOR regiszterek megcímzésével közvetlenül (hardveresen) módosítjuk a PDOR adatregiszter 19. bitjének tartalmát.

5. lista: Program2_5/main.c listája
/* Program2_5
* A FRDM-KL25Z kártyára épített zöld LED (PTB19) villogtatása.
* A kimenet vezérléséhez most használjuk a PSOR, PCOR, PTOR
* bitmanipulációs regisztereket!
*
* A program forrása: Mazidi et al., Freescale ARM Cortex-M Embedded Programming
* http://www.microdigitaled.com/ARM/Freescale_ARM/Code/Ver1/Chapter2/Program2_5.txt
*/


#include <MKL25Z4.h>

int main (void) {
void delayMs(int n); // Elore deklaráljuk a delayMs() függvényt
SIM->SCGC5 |= 0x400; // Port B órajelének engedélyezése (bit10=1)
PORTB->PCR[19] = 0x100; // PTB19 pin legyen GPIO (MUX = 1, Alt1 mode)
PTB->PDDR |= 0x80000; // PTB19 legyen kimenet (bit 19 = 1)
while (1) { // Végtelen ciklus...
//--- 1. változat: PCOR és PSOR (bit clear/bit set) használata
PTB->PCOR = 0x80000; // Zöld LED felkapcsolása (bit19 = 0)
delayMs(500); // 500 ms várakozás
PTB->PSOR = 0x80000; // Zöld LED lekapcsolása (bit19 = 1)
delayMs(500); // 500 ms várakozás
//--- 2. változat: PTOR (bit toggle) használata
// PTB->PTOR = 0x80000;
// delayMs(500);
}
}

void delayMs(int n) { // Késlelteto függvény
int i, j;
for(i = 0 ; i < n; i++)
for (j = 0; j < 3500; j++); // Alapértelmezett órajelhez (20.97152 MHz)
}
A főprogram végtelen ciklusában két lehetőségünk van:
A nem kívánt utasítások elé tegyünk kommentár jelet (//)!

Program2_7: RGB LED alapszín kombinációinak körbeléptetése

Ebben a programban mindhárom LED-et villogtatjuk. Mindhárom LED lehet ki- vagy bekapcsolt állapotban, így összesen 23 = 8 féle kombinációs lehetőség adódik. Legegyszerűbben úgy tudunk ezeken az állapotokon végiglépkedni, hogy deklarálunk egy számlálónak használt változót, amelyet minden ciklusban megnövelünk, s a számláló legalsó három bitjéhez rendelünk egy-egy LED-et. Ha az adott biten egyes áll, akkor bekapcsoljuk a hozzá rendelt LED-et, ha pedig nulla áll, akkor lekapcsoljuk az adott LED-et. A LED-el kapcsolgatásához most is a PCOR, PSOR bitmanipulációs regisztereket használjuk.

6. lista: Program2_7/main.c listája
/* Program2_7
*
* A FRDM-KL25Z kártyára épített RGB LED alapszín kombinációinak körbeléptetése.
*
* A program forrása: Mazidi et al., Freescale ARM Cortex-M Embedded Programming
* http://www.microdigitaled.com/ARM/Freescale_ARM/Code/Ver1/Chapter2/Program2_7.txt
*/

#include <MKL25Z4.h>

int main (void) {
void delayMs(int n);
int counter = 0;
SIM->SCGC5 |= 0x1400; // Port B és D engedélyezése (bit 10 és bit 12)
PORTB->PCR[18] = 0x100; // PTB18 legyen GPIO (MUX = 1)
PORTB->PCR[19] = 0x100; // PTB19 legyen GPIO (MUX = 1)
PORTD->PCR[1] = 0x100; // PTD1 legyen GPIO (MUX = 1)
PTB->PDDR |= 0xC0000; // PTB18 és PTB19 legyen kimenet (bit18 és 19=1)
PTD->PDDR |= 0x02; // PTD1 legyen kimenet (bit1 = 1)
while (1) {
if (counter & 1) PTB->PCOR = 0x40000; // Piros LED: BE (bit18 = 0)
else PTB->PSOR = 0x40000; // Piros LED: KI (bit18 = 1)
if (counter & 2) PTB->PCOR = 0x80000; // Zöld LED: BE (bit19 = 0)
else PTB->PSOR = 0x80000; // Zöld LED: KI (bit19 = 1)
if (counter & 4) PTD->PCOR = 0x02; // Kék LED: BE (bit1 = 0)
else PTD->PSOR = 0x02; // Kék LED: KI (bit1 = 0)
counter++;
delayMs(500);
}
}

void delayMs(int n) { // Késlelteto függvény
int i, j;
for(i = 0 ; i < n; i++)
for (j = 0; j < 3500; j++); // Alapértelmezett órajelhez (20.97152 MHz)
}

Program2_8: LED vezérlése nyomógombbal

Ebben a programban egy nyomógombbal vezéreljük a zöld LED-et. Ha a nyomógombot lenyomjuk, a LED világít. Amikor a nyomógombot felengedjük, a LED is kialszik. A LED vezérlés elve lényegében ugyanaz, mint az előző programban, csak most nem egy számláló, hanem  valamelyik GPIO port bemeneti adatregiszterének egyik bitjét vizsgáljuk.


5. ábra: A nyomógomb bekötésének vázlata

A nyomógombot a PTA12 kivezetés és a közös pont (GND) közé kötjük és lehúzásra használjuk. A nyomógomb felengedett állapotában a magas szintre húzáshoz bekapcsoljuk a  PTA12 kivezetéshez tartozó belső felhúzást: a  PORTA->PCR[12] regiszterben a PS és PE biteket is 1-be állítjuk.

7. lista: Program2_8/main.c listája
/* Program2_8
* LED vezérlése nyomógombbal. Ha a PTA12 bemenet és a GND
* közé kötött nyomógombot lenyomjuk, a zöld LED világítani kezd.
* Ha a nyomógombot felengedjük, a LED kialszik.
* A PTA12 bemenet felhúzásához bekapcsoljuk a belso felhúzást.
*
* A program forrása: Mazidi et al., Freescale ARM Cortex-M Embedded Programming
* http://www.microdigitaled.com/ARM/Freescale_ARM/Code/Ver1/Chapter2/Program2_8.txt
*/

#include <MKL25Z4.h>

int main (void) {
SIM->SCGC5 |= 0x400; // B port engedélyezése
PORTB->PCR[19] = 0x100; // PTB19 legyen GPIO (MUX = 1)
PTB->PDDR |= 0x80000; // PTB19 legyen kimenet (Zöld LED vezérlés)

SIM->SCGC5 |= 0x200; // A port engedélyezése
PORTA->PCR[12] = 0x103; // PTA12: GPIO, felhúzással (PE=1,PS=1, MUX=1)
PTA->PDDR &= ~0x1000; // PTA12 legyen bemenet (PDDR bit 12 = 0)

while (1) {
if (PTA->PDIR & 0x1000) // Gomblenyomás figyelése
PTB->PSOR = 0x80000; // Felengedve: LED KI
else
PTB->PCOR = 0x80000; // Lenyomva: LED be
}
}
Az inicializálás lépései:
A nyomógomb vizsgálata a PTA->PDIR bemeneti adatregiszter olvasásával történik. Ha ennek 12. bitje 1, akkor a bemenet magas szinten áll, azaz a nyomógomb felengedett állapotban van. Ha pedig a 12. bit tartalma 0, akkor a bemenet alacsony szinten áll, azaz a nyomógomb le van nyomva. Kétállapotú rendszer lévén, elegendő csupán az egyik feltételt vizsgálni, ha a feltétel nem teljesül, akkor értelemszerűen a másik állapot áll fenn.

A LED-el kapcsolgatásához most is a PCOR, PSOR bitmanipulációs regisztereket használjuk.

Letölthető projektek: