Impulzus-szélesség moduláció (PWM)
A fejezet tartalma:- Az impulzus-szélesség moduláció alapjai
- A PWM kimenetek kezelése mbed környezetben
- Mintapélda: LED fényerejének vezérlése soros kapcsolaton (03_pwm_led)
- Mintapélda: dallam lejátszása piezo csipogón (03_pwm_music)
- Szervó motorok
vezérlése
Az impulzus-szélesség moduláció alapjai
A mikrovezérlők alkalmazásainál gyakran előforduló feladat, hogy hogy valamilyen mennyiséget (egy fogyasztó teljesítményét) folyamatosan vagy fokozatosan kell szabályozni.Az egyik kézenfekvő megoldás egy digitális-analóg átalakító (DAC) alkalmazása. A Freescale Kinetis MKL25Z128VLK4 mikrovezérlő is rendelkezik egy 12-bites felbontású DAC periférifériával, amelynek kimenete a mikrovezérlő PTE30 kivezetésén (a FRDM-KL25Z kártya J10-11 kivezetése) érhető el. Ez azonban csupán egyetlen kimenet vezérlésére képes.
Egy másik lehetőség az impulzus-szélesség moduláció (Pulse Width Modulation - PWM) alkalmazása. Ennek elve az, hogy az analóg kimenő feszültségjelek helyettesíthetők digitális impulzussorozat-jelekkel, amelyek hosszabb időtartamra vonatkoztatott átlagfeszültsége egyenértékű az analóg feszültségjellel. Ilyen jeleket hardveresen a mikrovezérlő időzítő és digitális összehasonlító perifériáinak felhasználásával állíthatunk elő. A digitális impulzussorozat frekvenciáját úgy kell (elegendően nagyra) megválasztani, hogy az, a vezérelt vagy szabályozott eszköz megfelelő működését biztosítsa. Például a szabályozott fényforrás folyamatos működésűnek látsszon (a szemünk ne vegyen észre villogást), vagy egy egyenáramú motor ne lökésszerűen változó szögsebességgel forogjon.
Az impulzus-szélesség moduláció (PWM) lényege tehát az, hogy olyan állandó periódusidejű (frekvenciájú) jeleket keltünk, ahol a szabályozás a jel kitöltési tényezőjének változtatásával történik. Néhány különböző kitöltési tényezőjű PWM jelet mutat be a következő ábra:
1. ábra: Azonos periódusú, de különböző kitöltésű impulzus-sorozatok
A kitöltési tényező az impulzusszélesség (azaz a bekapcsolt állapot ideje) és a periódusidő hányadosa. Ha százalákosan akarjuk megadni, akkor a hányadost még meg kell szorozni 100 %-kal.
kitöltési
tényező = impulzusszélesség/periódusidő
Ha a kitöltési tényezőt százalékosan akarjuk megadni, akkor a hányadost még meg kell szorozni 100 %-kal:
kitöltési
tényező [%] = 100 % * impulzusszélesség/periódusidő
Habár a PWM jeleket szoftveresen is előállíthatjuk (egyszerű I/O parancsok és megfelelő késleltetések alkalmazásával), a mikrovezérlők hardveres támogatást is nyújtanak a PWM jelek előállításához. A hardveres támogatás előnye az, hogy (a beállítás után) a periodikus jelek keltése nem vesz igénybe CPU időt, s "hardveres pontosságú", azaz a programmegszakítások, vagy a programfutás menete nem befolyásolják a jelek időzítési viszonyait.
A Freescale Kinetis MKL25Z128VLK4 mikrovezérlő esetében a három 16 bites időzítő/számláló (Timer0, Timer1, Timer2) és a hozzájuk kapcsolódó multifunkciós csatornák segítségével állíthatunk elő PWM jelet. A csatornák száma összesen 10 db (TPM0: CH0..CH5, TPM1: CH0..CH1, TPM2: CH0..CH1), tehát egyidejűleg legfeljebb ennyi PWM jelet tudunk előállítani. Az egyidejűleg keltett PWM jelek nem teljesen függetlenek egymástól: az azonos Timer-hez kapcsolódó PWM csatornák periódusideje közös, s a jelek kezdete (a felfutás) azonos idejű (Edge Aligned mód).
Egy Timer/PWM modul (TPM) vázlatos felépítése az alábbi ábrán látható. A TPM modul központi eleme az órajelválasztót és az előszámlálót követő 16 bites számláló (az ábrán "Module counter") és a változó darabszámú (legfeljebb 6 db) csatorna, amelyek üzemmódja bemeneti jelelfogás (Input Capture), kimeneti digitális komparátor (Output Compare), illetve PWM lehet.
2.
ábra: Egy Timer/PWM Modul (TPM) blokkvázlata
A FRDM-KL25Z kártya azon kivezetései használhatók impulzus-szélesség modulált (PWM) kimenetként, amelyek az alábbi ábrán PWM feliratú lila címkével vannak megjelölve. Fentieken kívül PWM kimenetként használhatók a kártyán található RGB LED-hez tartozó kivezetések is: LED_RED (PTB18), LED_GREEN (PTB19), LED_BLUE (PTD1).
Azt, hogy a fenti ábrán lila címkével megjelölt kivezetések melyik TPM modul melyik csatornájához vannak rendelve, s ennek megfelelően mely kivezetések nem használhatók egyidejűleg független PWM kimenetként, a FRDM-KL25Z Pinouts dokumentumban ellenőrizhető: az ALT3 oszlopból azok az FTMx_CHn (ahol x:0,1,2; n:0..5) jelű kivezetések használhatók PWM kimenetként, amelyek zöld alapszínű cellában vannak).
A PWM kimenetek kezelése mbed környezetben
Az mbed környezetben a PwmOut objektumosztály szolgál a PWM kimenetek konfigurálására és kezelésére. A tagfüggvények felsorolása az alábbi táblázatban található.Függvény |
Felhasználás |
---|---|
PwmOut
név(PinName pin) |
A konstruktor, amely létrehoz egy "név" nevű PwmOut objektumot és a pin paraméterrel megadott kimenethez rendeli |
write(float
adat) |
A kitöltési tényező beállítása a
megadott (0.0 - 1.0 közötti) értékre |
read() |
Az utoljára beállított kitöltési tényező adja meg (0.0 - 1.0 közötti float) |
period(float
sec) |
A periódusidő megadása
másodpercben (float típusú paraméter) |
period_ms(int ms) | A periódusidő megadása milliszekundumban (int típusú paraméter) |
period_us(int us) | A periódusidő megadása mikroszekundumban (int típusú paraméter) |
pulsewidth(float
sec) |
Az impulzusszélesség (a magas
szintű állapot ideje) megadása másodpercben |
pulsewidth_ms(int ms) | Az impulzusszélesség megadása
milliszekundumban (int típusú paraméter) |
pulsewidth_us(int us) | Az impulzusszélesség megadása mikroszekundumban (int típusú paraméter) |
operator = adat |
Rövidített alak név.write(adat) helyett |
operator
int() |
Rövidített alak név.read() helyett |
Mintapélda:
LED fényerejének vezérlése soros kapcsolaton
Az alábbi 03_pwm_led nevű
programban a számítógépről, soros kapcsolaton keresztül vezéreljük a FRDM-KL25Z kártyán a vörös
fényerejét. A soros terminálról (Hyperterminal, PuTTY, stb.) az '1',
'5', vagy '9' karakter elküldése a LED_RED
kimenet 0.99, 0.5, 0.01 kitöltésű 50 Hz-es négyszögjelre állítja be,
ami a LED negatív logikája miatt 1 %-os, 50 %-os, illetve 99 %-os
teljesítménynek felel meg.Hardver követelmények:
- FRDM-KL25Z kártya
- Az SDA portot csatlakoztassuk a PC-hez, és kapcsolódjunk egy terminál programmal az mbed Serial Port-hoz (a Windows Eszközkezelőjében tudjuk megnézni, hogy a COM portok közül melyik sorszámot kapta a fent nevezett eszköz)
1. lista: A 03_pwm_led/main.cpp program listája
#include "mbed.h"
PwmOut myled(LED_RED);
Serial pc(USBTX, USBRX); // tx, rx
int main() {
myled.period_ms(20); //Period = 20 ms
myled.write(1.0); //Led off at start
while(1) {
char c = pc.getc(); //read next character
if(c=='1') {
myled = 0.99f; //LED has negative logic!
pc.printf("Duty cycle = 0.01\r\n");
}
else if(c=='5') {
myled = 0.5f;
pc.printf("Duty cycle = 0.5\r\n");
}
else if(c=='9') {
myled = 0.01f; //LED has negative logic!
pc.printf("Duty cycle = 0.99\r\n");
}
wait(0.2);
}
}
Mintapélda:
dallam lejátszása piezo csipogón
Az alábbi 03_pwm_music
nevű programmal egy rövid zeneszámot játszunk le. A hang
megszólaltatáshoz egy piezo csipogót (piezo buzzer) hajtunk meg a
keltett PWM jellel. Ezt a mintaprogramot, amely az Oranges and Lemons
c. régi angol népdalt játssza le Rob Toulson és
Tim Wilmshurst: ARM mbed Course
Material - Pulse Width Modulation tananyagából vettük
kölcsön.3.
ábra: A lejátszani kívánt dallam kottája
A fenti kottát az alábbi táblázattal is megadhatjuk, ahol a hangok frekvenciáját is feltüntettük.
A hangok tartamáról elég annyit tudnunk,
hogy a nyolcadhang fele annyi ideig tart, mint egy negyedhang, a
félhang pedig a negyedhang idejének kétszereséig tart. Ha a negyedhang
idejét félmásodpercnek vesszük (ez a percenkénti 120 negyedhangos
Allegretto tempónak felel meg), akkor a negyedhang ideje 0.25 s, a
félhangé pedig 1 s lesz.
A hangkeltés módja
Egy PwmOut kimenetet úgy konfigurálunk, hogy a periódusidő a kívánt hangmagasságnak megfelelő frekvencia reciproka legyen, a kitöltést pedig 50 %-ra (0.5-re) állítjuk be. Például egy normál A hang (440 Hz) megszólaltatása így néz ki:PwmOut buzzer(D3);
buzzer.period(1.0/440);
buzzer = 0.5;
A hangkeltés időtartamát az egyszerűség kedvéért a szokásos késleltető
függvényekkel (wait(), wait_ms()
stb.) állíthatjuk be. A 120-as tempó esetén 0.25, 0.5 vagy 1.0 s
időtartam felel meg a nyolcad, negyed, illetve fél értéknek.wait(0.5*beat); //ahol beat = 1/2, 1, vagy 2
Megjegyzés: Bár a zene lejátszásához a hangokat egy PwmOut kimenet (és a hozzá tartozó TPM modul) segítségével keltjük, valójában most nem moduláljuk az impulzusok szélességét, hanem állandó, 50 %-os kitöltéssel dolgozunk, s csak a frekvenciát változtatjuk.
Hardver követelmények:
- FRDM-KL25Z kártya
- Egy piezo csipogó '+' jelű kivezetését kössünk a kártya D3 kimenetére, a csipogó másik kivezetését pedig kössük a kártya GND jelzésű pontjára.
//Borrowed from Rob Toulson and Tim Wilmshurst: ARM mbed Course Material - PWM
//Link: https://developer.mbed.org/cookbook/Course-Notes
#include "mbed.h"
PwmOut buzzer(D3);
float frequency[]={659,554,659,554,550,494,554,587,494,659,554,440}; //frequency array
float beat[]={1,1,1,1,1,0.5,0.5,1,1,1,1,2}; //beat array
int main() {
while (1) {
for (int i=0; i<12; i++) {
buzzer.period(1/(frequency[i])); // set PWM period
buzzer=0.5; // set duty cycle
wait(0.5*beat[i]); // hold for beat period
}
}
}
A frequency nevű tömbben
tároljuk a lejátszandó dallam hangjainak frekvenciáját. A hangok
időtartamát pedig a beat
nevű tömbben tároljuk (1: negyed, 0.5: nyolcad, 2: fél). A lejátszandó
hangok számát itt fix értéknek vettük a for ciklusban (12 db. hangunk
van). Általánosabb esetben a tömbökben szereplő elemek n száma így
adható meg:n = sizeof(frequency)/sizeof(frequency[0]);
Szavakban megfogalmazva: a tömbelemek száma = a tömb mérete bájtokban /
egy elem mérete bájtokban.Szervó motorok vezérlése
Az impulzusszélesség-moduláció egy speciális esete a szervó motorok vezérlőjele. Mivel főleg a rádiótávirányítású modellekben terjedt el a használatuk, ezeket többnyire "RC servo" néven emlegeti az angol nyelvű szakirodalom (RC = Radio Controlled). A szervó motorok felépítése és tipikus jelalakja az alábbi ábrákon látható (a képek forrása a ServoCity honlapja).
4.
ábra: A szervó motor "robbantott" képe
A szervó egy kisméretű egyenáramú motort tartalmaz, amely a fogaskerék áttételen keresztül mechanikai összeköttetésben áll egy potméter tengelyével. A beérkező vezérlőjelet feldolgozó beépített elektronika úgy irányítja a motor forgását előre vagy hátra, hogy a potméterrel összekötött tengely mindig az előírt szögállásba kerüljön.
5.
ábra: A szervó vezérlőjele 20 ms periódusidejű, 5-10 %-os kitöltésű jel
A különböző gyártmányú szervók vezérlőjele nem egységes, de a bejövő jel általában 50 Hz-es ismétlődési frekvenciájú (periódusidő = 20 ms), 5 - 10 %-os kitöltésű impulzus, amelynél az impulzus szélessége szabja meg a kívánt szögállást. Az 1,5 ms szélességű jel tartozik a középső, úgynevezett nyugalmi helyzethez, s 0,5-1 ms szélességű jel felel meg a bal szélső helyzetnek, valamint 2 - 2,5 ms szélességű jel felel meg a jobb szélső véghelyzetnek.
6.
ábra: Tipikus jelalakok szervó motor vezérléséhez
Mintapélda: Szervo motor vezérlése
Az alábbi programban két szélső helyzet között oda-vissza mozgatjuk a szervo motort. A vezérlés egy PwmOut kivezetés felhasználásával történik, amelyet a D3 (PTA12) kivezetéshez rendeltünk hozzá. A periódusidőt 20 ms-ra állítjuk be, az impulzusszélességet pedig 1000 és 2000 µs között változtatjuk, 20 µs-os lépésekben.Hardver követelmények:
- FRDM-KL25Z kártya
- Egy szervó motor, melynek vezérlő bemenetét a kártya D3 kivezetéséhez kötjük (másik két kivezetését pedig a +5V, illetve a GND kivezetésekre kell kötni).
#include "mbed.h"
PwmOut servo(D3);
int main() {
servo.period_ms(20); //Period = 20 ms (f=50 Hz)
while(true) {
for(int pw=1000; pw <= 2000; pw=pw+20) {
servo.pulsewidth_us(pw); //Set new servo position
wait_ms(200);
}
wait_ms(1000); //Wait before reverse direction
for(int pw=2000; pw >= 1000; pw=pw-20) {
servo.pulsewidth_us(pw); //Set new servo position
wait_ms(200);
}
wait_ms(1000);
}
}