Analóg perifériák

A fejezet tartalma:

Analóg jelfeldolgozás

A körülöttünk levő világ fizikai jellemzői (pl. hőmérséklet, nyomás, szélsebesség) általában folytonosan változó mennyiségek. Az ezeket elektromos jellé alakító érzékelők (szenzorok) kimenőjele a fizikai mennyiséggel analóg (arányos) módon változó folytonos x(t) mennyiség, ahol t az időbeli változásra utal. Mivel e jelek feldolgozását digitális működésű mikrovezérlővel szeretnénk megoldani, szükséges az érzékelőkből bejövő analóg jel mintavételezése és kvantálása (digitalizálása) egy esetleges jelkondicionálás után. A feldolgozás ezután már digitális adatokkal operál. A mintavételezés és kvantálás feladatát az analóg-digitális átalakító (ADC - Analog to Digital  Converter) végzi el, amely lehet a mikrovezérlő beépített perifériája, vagy külön beszerezhető külső periféria.

Előfordulhat olyan eset, hogy nincs szükségünk a bejövő analóg jel értékének ismeretére (nem kell digitalizálnunk), csupán arra vagyunk kíváncsiak, hogy a bejövő jel nagysága egy kijelölt szintet meghalad-e, vagy sem. Ilyen esetekben a bonyolult működésű ADC helyett egy analóg komparátor (összehasonlító) is megfelel. A legtöbb mikrovezérlő rendelkezik egy vagy több beépített analóg komparátorral, de külső IC-t is használhatunk erre a célra. Az analóg komparátor kimenőjele logikai jel, amelyet a mikrovezérlővel vizsgálhatunk, vagy más perifériák indítására (triggerelés) is felhasználhatjuk.

Ha a jelfeldolgozás eredményeként analóg beavatkozójelet kell előállítanunk, akkor vagy digitális-analóg átalakítót (DAC - Digital to Analog Converter) használunk (amely a mikrovezérlő belső vagy külső perifériája), vagy a PWM fejezetben ismertetett impulzus-szélesség modulációt használjuk, s ha szükséges, egy aluláteresztő jellel "simíthatjuk" a jelet. Természetesen mindkét esetben kvantált, azaz lépcsős lesz a kimenőjel, de kellően finom felbontásnál a "lépcsők" hatása elhanyagolható.

1. ábra: Analóg világban élünk, de digitális mikrovezérlővel dolgozunk

Az analóg adatgyűjtő ág elemei


2. ábra: Az analóg adatgyűjtő ág elemei

Az analóg beavatkozó ág elemei

A FRDM-KL25Z kártya analóg perifériái

A FRDM-KL25Z kártya az alábbi analóg perifériákkal rendelkezik:

Analóg komparátor:
amelynek az invertáló és neminvertáló bemenete egy-egy analóg multiplexer segítségével  6  külső kivezetés, illetve 1 belső referencia közül választható ki. A belső referencia egy 6 bites DAC kimenete.

Analóg-digitális átalakító: amely 16 bites felbontású, fokozatos megközelítés elvén működő (SAR), s a mérendő csatorna két differenciális, vagy legfeljebb 14 db single-ended bemenet közül választható ki.

Digitális-analóg átalakító: amely 12 bites felbontású, s amelynek kimenőjele kivezethető  (PTE30), vagy valamelyik periféria rendelkezésére bocsátható referencia jelként (pl. Analóg komparátor, ADC).

Az alábbiakban részletesen ismertetjük ezen perifériák felépítését, illetve használatát.

Analóg komparátor

Az analóg komparátor a műveleti erősítőkhöz hasonlóan egy invertáló (Vin-) és egy neminvertáló (Vin+) bemenettel rendelkezik, s kimenete logikai '1', ha a neminvertáló bemenetre kapcsolt feszültség nagyobb, mint az invertáló bemenetre kapcsolt feszültség, egyébként pedig logikai '0'.



3. ábra: Az analóg komparátor működésének szemléltetése állandó Vin- jelszint esetén

Az MKL25Z128VLK4 mikrovezérlő analóg komparátorának blokkvázlata a 4. ábrán látható. A komparátor neminvertáló (INP) és invertáló (INM) bemenetei egy-egy analóg multiplexer segítségével rendelhetők kivezetésekhez, vagy belső referenciához. A belső referencia lehet a komparátor modulhoz tartozó 6 bites DAC, vagy a 12 bites DAC kimenőjele.  A legegyszerűbb, folyamatos üzemmódon kívül lehetőség van a kimenőjel mintavételezésére, (digitális) szűrésére és invertálására is. A kimenőjel kivetéshez rendelhető (PTC0, PTC5, PTE0 valamelyike), vagy a belső perifériák  indítására (triggerelés), illetve programmegszakítás keltésére használható.

4. ábra: Az MKL25Z128VLK4 mikrovezérlő analóg komparátorának blokkvázlata

A ComparatorIn periféria-könyvtár

Az analóg komparátor használatát a standard mbed API nem támogatja, külön programkönyvtárt kell készíteni vagy beszerezni hozzá. Az alábbiakban a Frank Vannieuwkerke által készített és közzétett ComparatorIn periféria-könyvtár használatát mutatjuk be.

A ComaparatorIn objektumosztály az analóg komparátor konfigurálására és kezelésére szolgál. Az alábbi táblázatban csak a legfontosabb tagfüggvényeit foglaltuk össze. A részletes dokumentáció a ComparatorIn periféria-könyvtár honlapján található.

1. táblázat: A ComparatorIn objektumosztály legfontosabb tagfüggvényei
Függvény
Használat
ComparatorIn név(pinP, pinM)
Létrehoz egy "név" nevű ComparatorIn  objektumot és a pinP paraméterrel megadott kivezetést a neminvertáló, a pinM paraméterrel megadott kivezetést az invertáló bemenethez rendeli.
OutputPin(pin)
A komparátor kimenetének hozzárendelése a megadott kivezetéshez
treshold(float t)
A belső referenciaforrást t*VREFH értékre állítja (t: 0-1.0 közötti float érték, VREFH pedig a kártyán beállított (általában 3.3V) analóg referencia értéke.
rising(*fptr)
A felfutáshoz tartozó megszakítást engedélyezi és visszahívási függvényt rendel hozzá (*fptr: függvény pointer)
falling(*fptr)
A lefutáshoz tartozó megszakítást engedélyezi és visszahívási függvényt rendel hozzá (*fptr: függvény pointer)
status()
A komparátor kimeneti állapotának lekérdezése (0: ha VinP < VinM, 1: ha VinP > VinM)
A legelső tagfüggvény egy C++ konstruktor, amelynek neve kötelezően megegyezik az objektumosztály nevével. A ComparatorIn nevű konstruktor használatával hozhatjuk létre az analóg komparátort kezelő objektumot, melynek neminvertáló és invertáló bemenetei a paraméterekben megadott lábhoz rendelődnek. A FRDM-KL25Z kártya esetén az alábbi kivezetéseket rendelhetjük az analóg komparátor bemeneteihez:

2. táblázat: Az analóg komparátor bemeneteihez rendelhető kivezetések
Kivezetés Csatorna Funkció Megjegyzés
PTC6 000 IN0 CMP0_IN0
PTC7 001 IN1 CMP0_IN1
PTC8 010 IN2 CMP0_IN2
PTC9 011 IN3 CMP0_IN3
PTE30 100 IN4 CMP0_IN4 12-bit DAC kimenet
PTE29 101 IN5 CMP0_IN5

110 IN6
1V internal Bandgap*
NC 111 IN7
belső 6-bites DAC
* Még nincs implementálva!

Speciális kivezetések:

Mintapélda: az analóg komparátor használata

Az alábbi programban az analóg komparátor működését vizsgáljuk. A mikrovezérlő PTE29 kivezetését rendeljük az analóg komparátor neminvertáló bemenetéhez, s erre a bemenetre egy fotoellenállásból és egy 10 kΩ-os ellenállásból kialakított osztó közös pontját kötjük (lásd 5. ábra). Az általunk használt kadmiumszulfid (CdS) fotoellenállás ellenállása megvilágított állapotban kicsiny (100 Lux esetén kb.  3 kΩ), sötét állapotban viszont nagy (akár 100-300 kΩ is lehet).

Az analóg komparátor invertáló lábát a mikrovezérlő PTE30 kivezetéséhez rendeljük. Ez a kivezetés egyúttal a 12 bites DAC kimenete is, tehát az analóg komparátor referencia feszültségét (a komparátor viszonyítási szintjét) a DAC segítségével állíthatjuk be.

A programban a referencia feszültséget 1 V-ra állítjuk. Megvilágított állapotban a fotoellenállás ellenállása kicsiny, a PTE29 lábra csatlakoztatott feszültség kisebb lesz, mint a beállított 1 V-os küszöb, a komparátor nem billen, kimenetén '0' érték olvasható. Eltakart állapotban, vagy sötét környezetben a fotoellenállás ellenállása megnövekszik, így az analóg komparátor neminvertáló bemenetére (esetünkben PTE29) jutó jel feszültsége meghaladja az 1 V-os referencia feszültséget. A komparátor állapota átbillen, a kimenetén '1' logikai szint olvasható.  

A programban a komparátor kimenetének vizsgálatára kétféle módszert is mutatunk:

A főprogramban a status() tagfüggvény hívásával kérdezzük le az analóg komparátor kimenetének az állapotát, az eredmény kiíratjuk az alapértelmezett kimenetre. A kiíratáskor tulajdonképpen az OpenSDA hibavadász és USB-UART protokol konverter áramkörön keresztül kommunikálunk a számítógéppel. A számítógép felől ez a kommunikációs csatorna virtuális soros portnak látszik (a Windows eszközkezelőjében mbed Serial Port (COMxx) néven találjuk meg a COM és LPT portok között. Az alapértelmezett beállítás: 9600 baud, 8 bit, 1 stop bit, paritás és adatfolyam-vezérlés nélkül. Bármilyen terminálemulációs program (Hyperterminal, PuTTY,stb.) megfelel a kiírások nyomon követéséhez.

Megszakítás szinten minden állapotváltáskor a megfelelő visszahívási függvény (cmp_rise_ISR, vagy cmp_fall_ISR) meghívásra kerül, s a zöld LED kigyullad, vagy kialszik).

Van a programnak még egy érdekessége: a mikrovezérlő PTE29-es kivezetését nem csak az analóg komparátor, hanem az analóg-digitális átalakító (ADC) egyik bemenetéhez is hozzárendeljük, így az 5. ábrán látható osztó feszültségét meg tudjuk mérni és a kapott értéket ki tudjuk íratni. 

A program működése összefoglalva:


Hardver követelmények:

5. ábra: Analóg jel előállítása  CdS fotoellenállás és egy 10 k
Ω-os ellenállás felhasználásával

1. lista: A 05_comparator_demo/main.cpp program listája
/** 05_comparator_demo
* Based on library ComparatorIn and example program ComparatorIn_demo
* written by Frank Vannieuwkerke
* Link: https://developer.mbed.org/users/frankvnk/code/ComparatorIn_demo/
*/

#include "mbed.h"
#include "ComparatorIn.h"

DigitalOut blinker(LED_BLUE); // blinking LED
DigitalOut cmpled(LED_GREEN); // signing comparator status
AnalogIn cmp_lvl(PTE29); // ADC input to check comparator input
ComparatorIn compi(PTE29, PTE30); // in+ = PTE29, in- = 12-bit DAC

// Comparator interrupt callback functions
void cmp_rise_ISR(void)
{
cmpled = 0; // LED ON at rising edge
}

void cmp_fall_ISR(void)
{
cmpled = 1; // LED OFF at falling edge
}


int main()
{
cmpled = 1; // LED OFF at the beginning

compi.rising(&cmp_rise_ISR); // Set pointer to rising interrupt function
compi.falling(&cmp_fall_ISR); // Set pointer to falling interrupt function
compi.treshold(0.3); // Set comparator threshold to 1V = 0.3 * 3.3V

while(1)
{
printf("Light sensor : %7.5f Volt\n",cmp_lvl*3.3);
blinker = 1; // binking LED OFF
wait(2); // wait for 2 sec
blinker = 0; // blinking LED ON
wait(0.2);
if (compi.status() == 0x01) // poll comparator status
{
printf("*** Treshold reached : %7.5f\n",cmp_lvl*3.3);
}
}
}
A blinker nevű digitális kimenetet a kék LED-hez rendeltük. Ennek felvillanásai jelzik, hogy mikor vizsgáljuk szoftveresen a komparátor kimenetét. A működéshez természetesen nincs szükség erre a LED-re.

A cmpled nevű digitális kimenetet a zöld LED-hez rendeltünk. Ezt a LED-et az analóg komparátor megszakításai kapcsolgatják (felfutó élre bekapcsol, lefutó élre kikapcsol).

A kártya PTE29 kivezetését egyidejűleg két eszköz bemenetéhez is hozzárendeljük: az analóg komparátor neminvertáló bemenetéhez és az ADC bemenetéhez. Ez utóbbira cmp_lvl (komparátor jelszint) néven hivatkozhatunk lekérdezéskor. A PTE29 kivezetésre kapcsolt feszültség (az 5. ábrán bemutatott osztó jele) tehát működteti az analóg komparátort és ugyanakkor meg tudjuk mérni az ADC segítségével.

Az analóg komparátort kezelő objektumot compi néven definiáltuk, ezzel a névvel hivatkozhatunk rá.

A cmp_rise_ISR és cmp_fall_ISR nevű függvényeket azért definiáltuk, mert ezeket fogjuk meghívatni az analóg komparátor megszakításaiból. A hozzárendeléseket a  compi.rising(), illetve compi.falling() tagfüggvények hívásával végezhetjük el, nem feledve, hogy ezek paramétere függvénymutató, tehát paraméterként a függvény neve elé egy '&' jelet kell írnunk. A LED kapcsolgatásánál pedig tartsuk észben, hogy a közös anódú LED-ek a megfelelő katód lehúzására világítanak ('0' szint a kimeneten)!

A komparálási szint a compi.treshold() tagfüggvény hívásával állítható be, melynek paramétere 0.0 - 1.0 közötti szám, s a VREFH analóg referencia-feszültség megfelelő hányadát jelenti.

Megjegyzés: a VREFH referencia-feszültség tényleges értéke a FRDM-KL25Z kártya verziójától és konfigurálásától függ:
  1. A régebbi kiadású (Rev D) kártyánál a tápellátó ágba kötött D1 dióda miatt 3,3 V helyett 2,9 V körüli volt a tápfeszültség és VREFH értéke is. A D1 dióda áthidalásával a feszültség 3,3 V-ra állítható.
  2. Az újabb kiadású (Rev E) kártyánál a tápellátó ágban található D12 dióda áthidalható a J20 átkötéssel, ekkor a tápfeszültség és VREFH értéke is 3,3 V lesz.
  3. Átforrasztással lehetőség van az Arduino kártyához hasonló módon külső analóg referenciaforrás használatára (ennek részleteit a FRDM-KL25Z kártya dokumentációjából kell kideríteni).
  4. További lehetőség az újabb kiadású kártyáknál az, hogy a D9 Zener dióda (3,0V), az R77 ellenállás (1k) beforrasztása és az R80 rövidzár eltávolítása után 3,0 V lesz VREFH értéke.

A fenti programnál azt feltételezzük, hogy a kártya verziójától (Rev D, vagy Rev E) függően az 1. vagy a 2. pont választásával a VREFH értékét 3,3 V-nak állítottuk be. A programban szereplő compi.treshold(0.3) beállítással a komparálási szint 0,3 * 3,3 V azaz kb. 1 V lesz.

A printf kiíratás az alapértelmezett stdio-ra, az UART0 soros portra történik, amely az OpenSDA által biztosított USB-UART protokoll konverteren keresztül kommunikál a számítógéppel.

A cmp_lvl objektumra történő hivatkozás a cmp_lvl.read() tagfüggvény hívás rövidített változatának felel meg, ami egy-egy ADC konverziót indít és annak eredményével tér vissza. A visszatérési érték 0 - 1.0 közötti érték, amely a mért feszültséget a VREFH megfelelő hányadaként fejezi ki. Ha a mért feszültséget Voltban akarjuk kifejezni, akkor szorozzuk meg a kapott értéket 3,3V-tal, VREFH értékével.

Analóg-digitális átalakító (ADC)

Az MKL25Z128VLK4 mikrovezérlő analóg-digitális átalakítója (ADC) lehetővé teszi, hogy a bejövő analóg feszültséget 65536 jelszintet megkülönböztetni tudó eszközzel a bejövő jel nagyságával arányos 16 bites számmá konvertáljuk (differenciális bemenet használata esetén előjeles eredményt kapunk, aszimmetrikus bemenet esetén pedig előjel nélkülit). Az elektronikában különféle elven működő ADC-ket használnak, amelyek sebességben, pontosságban és természetesen az árukban is jelentősen eltérnek egymástól. 

Az MKL25Z128VLK4 mikrovezérlő analóg-digitális átalakítója a fokozatos megközelítés (successive approximation, SAR) elvén működik. E módszer lényege a következő: a mintavételezett jelet először összehasonlítjuk a referenciafeszültség felével. Ha a vizsgált jel ennél nagyobb, akkor a legmagasabb helyiértékre 1-et, különben pedig 0-át írunk. A következő lépésben a referenciafeszültség azon tartományát felezzük meg, amelyikbe a bemenő jel az előző vizsgálatnál esett. Tehát ha az első vizsgálatnál a referencia feszültség felénél kisebb volt a vizsgált jel, akkor a második lépésben a referenciafeszültség negyedével hasonlítjuk össze, ellenkező esetben pedig a referenciafeszültség háromnegyedével. Ha a bejövő jel nagyobb volt, mint az összehasonlításhoz használt jel, akkor a soron következő helyiértékre 1-et írunk, különben pedig 0-át. Az eljárást tovább folytatva, tizenhat lépésben megkapjuk a 16 bites eredményt. Ezt a digitalizálási folyamatot a továbbiakban konverziónak hívjuk.

Az ADC előtt a beépített többcsatornás analóg multiplexerek segítségével választhatjuk ki a megmérni kívánt analóg jel bemenetét. A kiválasztást léptethetjük is, így többcsatornás analóg adatgyűjtőt is kialakíthatunk, természetesen az egyes csatornákat csak egymás után, nem pedig egyidejűleg konvertálhatjuk. Az MKL25Z128VLK4 mikrovezérlő analóg-digitális átalakítója bemenetén található analóg multiplexerek segítségével elvileg 4 differenciális vagy 24 aszimmetrikus (single-ended) bemenet közül választhatunk, a gyakorlatban azonban csak két differenciális, vagy legfeljebb 14 db single-ended mérőcsatorna közül választhatunk (a többi bemenet nincs kivezetve). Az ADC differenciális bemenetű csatornái a 3. táblázatban, az aszimmetrikus bemenetű csatornái pedig a 4. táblázatban felsorolt kivezetéseken érhetők el.

3. táblázat: Az ADC differenciális csatornáinak elérhetősége
Kivezetés
ADC csatorna
Funkció
PTE20
ADC0_DP0
ADC 0. differenciális csatorna + ága
PTE21
ADC0_DM0
ADC 0. differenciális csatorna - ága
PTE22
ADC0_DP3 ADC 3. differenciális csatorna + ága
PTE23
ADC0_DM3 ADC 3. differenciális csatorna - ága
4. táblázat: Az ADC aszimmetrikus bemenetű csatornáinak elérhetősége
Kivezetés
ADC csatorna
Arduino
Megjegyzés
PTE20
ADC0_SE0

Arduino kompatibilis csatlakozón nem érhető el!
PTE21
ADC0_SE4a
Arduino kompatibilis csatlakozón nem érhető el!
PTE22
ADC0_SE3
Arduino kompatibilis csatlakozón nem érhető el!
PTE23
ADC0_SE7a
Arduino kompatibilis csatlakozón nem érhető el!
PTE29
ADC0_SE23
Arduino kompatibilis csatlakozón nem érhető el!
PTE30
ADC0_SE4b
Ugyanide csatlakozik a DAC kimenete is!
PTB0
ADC0_SE8 A0
Arduino kompatibilis analóg csatorna
PTB1
ADC0_SE9 A1
Arduino kompatibilis analóg csatorna
PTB2
ADC0_SE12 A2
Arduino kompatibilis analóg csatorna
PTB3
ADC0_SE13 A3
Arduino kompatibilis analóg csatorna
PTC0
ADC0_SE14
Arduino kompatibilis csatlakozón nem érhető el!
PTC1
ADC0_SE15 A5
Arduino kompatibilis analóg csatorna
PTC2
ADC0_SE11 A4
Arduino kompatibilis analóg csatorna
PTD1
ADC0_SE5b D13
Az Arduinonál ez digitális csatorna
PTD5
ADC0_SE6b D9
Az Arduinonál ez digitális csatorna
PTD6
ADC0_SE7b
Arduino kompatibilis csatlakozón nem érhető el!
Megjegyzés: a 4a és 4b, valamint a 7a és 7b feltehetőleg azonos analóg csatornákat jelölnek, ezért egyidejűleg nem használhatók független bemenetként!

Az MKL25Z128VLK4 mikrovezérlő analóg-digitális átalakítójának blokkvázlata az alábbi ábrán látható. A bonyolult felépítés sokféle üzemmódot tesz lehetővé, de ennek részleteivel itt nem foglalkozunk. Az mbed API standard periféria-könyvtára ugyanis az ADC-nek csupán a legegyszerűbb üzemmódját támogatja.

6. ábra: Az ADC blokkvázlata


Az AnalogIn periféria-könyvtár

Az AnalogIn objektumosztály az ADC konfigurálására és kezelésére szolgál. Mivel része a standard mbed API-nak, így nem kell külön importálni.

5. táblázat: Az AnalogIn objektumosztály legfontosabb tagfüggvényei
Függvény
Használat
AnalogIn név(pin)
Létrehoz egy "név" nevű AnalogIn  objektumot és a pin paraméterrel megadott kivezetést az ADC egyik analóg bemeneteként konfigurálja.
read()
Egy konverziót indít, majd visszatér az eredménnyel. A visszatérési érték 0 - 1.0 közötti float érték, amely a mért feszültséget a VREFH analóg referencia megfelelő hányadaként fejezi ki. Ha a mért feszültséget Voltban akarjuk kifejezni, akkor szorozzuk meg a kapott értéket VREFH értékével (a tápáramkör D1, vagy D12 diódájának áthidalása esetén ez 3,3 V).
read_u16()
Egy konverziót indít, majd visszatér az eredménnyel. A visszatérési érték 0 - 0xFFFF közötti uint16 érték, amely a mért feszültséget VREFH/65536 egységekben fejezi ki.
operator float()
Rövidített alak read() helyett
Megjegyzés: Az AnalogIn objektumosztály felhasználásával csak aszimmetrikus (single-ended) bemeneteket tudunk kezelni. Differenciális ADC bemenet kezelésére külön objektumosztályt kell írni (vagy importálni). Jelen sorok írásakor csak a FRDM-KL64F kártyához volt elérhető egy Analogin_Diff könyvtár (az mbed Components/other kategóriában), ami minimális módosítással valószínűleg FRDM-KL25Z kártyára is adaptálható.

Mintapélda: Analóg hőmérő használata

Az alábbi programban egy Microchip MCP9700A analóg hőmérő kimenő feszültségét mérjük meg az ADC segítségével, s az eredményt az alapértelmezett stdio kimenetre (az UART0 soros portra) kiíratjuk.

Az MCP9700A analóg hőmérő az alábbi paraméterekkel rendelkezik:

Hardver követelmények:




2. lista: A 05_analog_thermometer/main.cpp program listája
#include "mbed.h"

AnalogIn ain(A0); // Analog input at PTB0

int main()
{
printf("\r\n05_analog_thermometer program\r\n");
while(1) {
uint16_t raw = ain.read_u16(); // read raw 16-bit data
float voltage = ain.read()*3300; // read voltage in millivolts
float tempC = (voltage -500)/10; // tempereature in Celsius
printf("ADC: 0x%04X voltage: %5.0f temp: %5.1f C\r\n",raw,voltage,tempC);
wait(2);
}
}

A programban két másodpercenként kiíratjuk a nyers, 16 bites adatokat (hexadecimálisan), továbbá a feszültségre átszámolt értéket (mV-okban) és a hőmérő karakterisztikája alapján kiszámolt hőmérsékletet is (Celsius fokokban). A program futási eredménye a 9. ábrán látható.

9. ábra: A 05_analog_thermometer program futási eredménye 


Mintapélda: Analóg hőmérő átlagolással

Ha megnézzük az előző program futási eredményét a 9. ábrán, akkor láthatjuk, hogy az egyes mérések szórása (ingadozása) nagy.  Az alábbi programban ezért pontonként több mérést végzünk, s az eredményeket átlagoljuk, hogy az elektromos zavarjelek okozta ingadozásokat a kiátlagolás révén lecsökkentsük.

Az átlagolásra több lehetőségünk is van: hardveres és szoftveres átlagolás.

Hardveres átlagolás: az MKL25Z128VLK4 mikrovezérlő analóg-digitális átalakítója hardveresen is támogatja az ADC mérések átlagolását (több mérést végez, s a mérések átlagát adja meg eredményül). Az ADC SC3 vezérlőregiszterének AVGE bitjének '1'-be állítása engedélyezi az átlagolást, s az SC3 regiszter kétbites AVGS bitcsoportja szabja meg, hogy hány mérést átlagoljunk (00: 4, 01: 8, 10: 16, 11: 32 minta átlagolása). Alapértelmezetten az AnalogIn objektumok lekérdezésekor 4 mérés átlagát kapjuk. Az alábbi utasítás beszúrásával (célszerűen a main() függvény elején) az előző programban a hardveres átlagolást átállíthatjuk 32-re.
    ADC0->SC3 = ADC_SC3_AVGE_MASK           // Hardware Average Enable
| ADC_SC3_AVGS(3); // 32 Samples Averaged

Szoftveres átlagolás: A következő programban az átlagolást 16 bites nyers adatokon végezzük, hogy elkerüljük a lebegőpontos (float) számábrázolásból adódó hibák felhamozódását és a lebegőpontos műveletek miatti többletszámolást (a lebegőpontos műveleteket csak a Cortex-M4F kategóriájú mikrovezérlők képesek hatékonyan elvégezni). Az összegzéshez egy 32 bites előjel nélküli változót deklarálunk mysum néven.

Az átlagolás általában úgy történik, hogy nullázzuk az összegzésre használt változót, majd n darab mérés eredményét hozzáadjuk, s végül az eredményt n-nel elosztjuk. Nekünk viszont a feszültség kiszámításához az átlagértéket 3300-zal meg kell szorozni (ez VREFH értéke mV-okban), majd a kapott eredményt 216 = 65536-tal el kell osztani.

Vegyük észre, hogy ha 3300 mintavétel eredményét adjuk össze, akkor az n = 3300-zal történő osztás, majd az azt követö 3300-zal történő szorzás megtakarítható! A 216 = 65536-tal történő osztás pedig 16 bináris helyiértékkel történő jobbraléptetéssel elvégezhető. A jobbraléptetés műveleti jele a C nyelvben ">>".


3. lista: A 05_analog_thermometer2/main.cpp program listája
#include "mbed.h"

AnalogIn ain(A0); // Analog input at PTB0
uint32_t mysum; // Used for summation

int main()
{
printf("\r\n05_analog_thermometer2 - with averaging\r\n");
while(1) {
mysum = 0;
for(int i=0; i<3300; i++) {
mysum += ain.read_u16(); // sum up raw 16-bit data
}
float voltage = mysum>>16; // voltage in millivolts
float tempC = (voltage -500)/10; // tempereature in Celsius
printf("voltage: %5.0f mV temp: %5.1f C\r\n",voltage,tempC);
wait(2);
}
}
 
A nyers értékekekt ebben a programban nem íratjuk ki, csak az átlagértékből kiszámolt feszültség és hőmérséklet adatokat. A program futási eredménye a 10. ábrán látható.

10. ábra: A 05_analog_thermometer2 program futási eredménye

Látható, hogy a nagyszámú mintavételből átlagolt eredmények már nem ingadoznak. Változás csak az utolsó három adatnál észlelhető, amikor "kézrátétellel" melegíteni kezdtük a hőmérőt.

Mintapélda: Az ADC extra funkcióinak használata

Az alábbi programban bemutatjuk, hogy hogyan használhatjuk az ADC belső csatornáit a beépített hőmérő és a  megmérésére. megmutatjuk, hogy az ADC belső hőérzékelőjének kiválasztásával (az ADC 26-os csatornája) hogyan mérhetünk hőmérsékletet, s hogyan mérhetjük meg a beépített bandgap referencia feszültségét (ADC 27-es csatorna). Egyúttal bekapcsoljuk a 32 mintából történő hardver átlagolást is.

Az ADC kezeléséhez nem írtunk teljes inicializálást végző eljárást, csupán felülírjuk az mbed API AnalogIn konstruktor függvényének inicializálását (csak azokat a regisztereket írjuk felül, amelyeket módosítani akarunk). Ezért fontos, hogy ne felejtsük ki az AnalogIn objektumosztály példányosítását mindazon analóg bemenetekre, amelyeket használni akarunk, s amelyek fizikai kivezetéshez rendelhetők. A beépített hőmérő és a bandgap referencia nincs kivezetve, ezért ezeket nem kell külön inicializálni, ellenben a bandgap referenciát be kell kapcsolnunk a PMC->REGSC regiszter BGBE bitjének 1-be állításávan (alapértelmezetten nincs bekapcsolva).

Az ADC inicializálás felülírásához és az extra csatornák kiolvashatóságához készítettünk egy adc_read() függvényt. A változtatások lényege:
Az ADC programmegszakítások kiszolgálása az ADC0_IRQHandler() függványben történik. Itt törölnünk kell az ADC-hez tartozó megszakításjelző bitet, majd elküldjük a kapott eredményt (az ADC0->R[0] kiolvasott tartalmát) a put() metódus segítségével a queue néven példányosított üzenetsorba. Az üzenetsor itt egy négyelemű FIFO tárként működik.

A belső hőmérő jelének feldolgozását a Freescale KL25xx Reference Manual (KL25P80M48SF0RM.pdf) 28.4.8 alfejezete ismerteti:

Temp = 25 - (VTemp - V25)/m

ahol V25 a 25 ºC-on mért feszültség (kb. 716 mV), m pedig a meredekség (kb. 1620 µV/ºC)

Azt ne feledjük, hogy a belső hőmérő mindig a lapka hőmérsékletét méri, ami a mikrovezérlő pillanatnyi fogyasztásától függően több fokkal is magasabb lehet a környezeti hőmérsékletnél.

Hardver követelmények:
4. lista: A 05_ADC_extra/main.cpp program listája
#include "mbed.h"
AnalogIn adc(A0);

uint16_t adc_read(uint32_t ch) {
ADC0->SC3 = ADC_SC3_AVGE_MASK // Hardware Average Enable
| ADC_SC3_AVGS(3); // 32 Samples Averaged
// start conversion
ADC0->SC1[0] = ch;

// Wait Conversion Complete
while ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK);

// Return value
return (uint16_t)ADC0->R[0];
}

int main() {
/*
* The v25 value is the voltage reading at 25C, it comes from the ADC
* electricals table in the processor manual. V25 is in millivolts.
*/
int32_t v25 = 716;

/*
* The m value is slope of the temperature sensor values, again from
* the ADC electricals table in the processor manual.
* M in microvolts per degree.
*/
int32_t m = 1620;
PMC->REGSC |= PMC_REGSC_BGBE_MASK; //Enable bandgap reference

while (true) {
uint16_t a1 = adc_read(8);
uint16_t a2 = adc_read(26);
uint16_t a3 = adc_read(27);
float v1 = a1*3.3f/65536;
float v2 = a2*3300.0f/65536;
float temp = 25.0f-(v2-v25)*1000.0f/m;
float v3 = a3*3.3f/65536;
printf("A0 = %6.3f V Temp = %5.2f C Bgap = %6.3f V\n",v1,temp,v3);
wait_ms(2000);
}
}

A program futási eredménye az alábbi ábrán látható.

11. ábra: A 05_ADC_extra program futási eredménye


Digitális-analóg átalakító (DAC)

Az MKL25Z128VLK4 mikrovezérlő digitális-analóg átalakítója (DAC) 12 bites felbontású, kimenőjele kivezethető  (PTE30), vagy valamelyik periféria rendelkezésére bocsátható referencia jelként (pl. analóg komparátor, ADC). Kimenő feszültsége 0 - 3.3V (azaz 0 - VREFH) között 4096 fokozatban változtatható. A DAC blokkvázlata a 12. ábrán látható. DACREF_1 (VREFH) és DACREF_2 (VDDA) választása esetünkben irreleváns, mivel
 a két bemenet a kártyán gyárilag össze van kötve. A két referencia bemenet (VREFH és VDDA) szétválasztása csak forrasztással lehetséges.


12. ábra: A 12-bites DAC blokkvázlata

Az AnalogOut periféria-könyvtár

Az AnalogOut objektumosztály a DAC konfigurálására és kezelésére szolgál. Mivel része a standard mbed API-nak, így nem kell külön importálni.

6. táblázat: Az AnalogOut objektumosztály tagfüggvényei
Függvény
Használat
AnalogOut név(pin)
Létrehoz egy "név" nevű AnalogOut  objektumot és a pin paraméterrel megadott kivezetést a DAC analóg kimeneteként konfigurálja. Esetünkben a pin értéke csak PTE30, vagy NC lehet (NC = nincs kapcsolat).
write(data)
A DAC kimenetet beállítja a data*VREFH feszültségre. A paraméter 0 - 1.0 közötti float érték, amely a beállítandó feszültséget a VREFH analóg referencia megfelelő hányadaként fejezi ki.
write_u16(data)
A DAC kimenetét beállítja a data/0xFFFF*VREFH feszültségre. A paraméter értéke 0 - 0xFFFF közötti uint16 érték, amely a mért feszültséget VREFH/65535 egységekben fejezi ki.
read()
Visszaolvassa a legutoljára beállított értéket (0 - 1.0 közötti float érték)
operator = data
Rövidített alak write(data) helyett
operator float()
Rövidített alak read() helyett
Megjegyzés: Az AnalogOut objektumosztály write_u16(data) tagfüggvényénél az uint16_t típusú data paraméter értékét "balra igazítva" kell megadni úgy, mintha egy 16 bites DAC felső 12 bitjét írnánk!
 

Mintapélda: DAC kimenőfeszültségének léptetése

Oszcilloszkóp híján az alábbi programban 5 másodpercenként léptetjük a DAC kimenő feszültségét, így egy egyszerű voltmérő segítségével ellenőrizhetjük a működést. A lépésköz kb. 0,42 V, ennyivel nő a feszültség minden lépésben, amíg a ciklusban a maximális értéket (esetünkben kb. 2.94 V) el nem érjük.

Hardver követelmények:


5. lista: A 05_dac12_test/main.cpp program listája
#include "mbed.h"


AnalogOut aout(PTE30);

int main()
{

while(1) {
for (uint16_t i = 0; i < 0xffff; i += 0x2000) {
aout.write_u16(i);
wait(5);
}
}
}
A működést a PTE30 kivezetésen megjelenő feszültség mérésével ellenőrizhetjük.