Avtorja: Mag. Vladimir Mitrović, Robert Sedak
E-pošta: vmitrovic12@gmail.com
V tem nadaljevanju se bomo naučili kako lahko s programom vplivamo na hitrost in smer vrtenja enosmernega (DC) elektromotorja.
Programe bomo napisali v programskih jezikih Bascom-AVR in Arduino IDE in jih nato s pomočjo razvojnega sistema Shield-B preverili, ali vse dela tako, kakor smo si zamislili.
Elektromotor lahko upočasnimo, če mu napajalno napetost ali delovni tok zmanjšamo pod nominalne vrednosti. Obstaja tudi tretji način, ki ga prikazujemo z risbo na sliki 6.
Ta vsebina je samo za naročnike
Tukaj skozi elektromotor pošiljamo tokovne impulze stalne frekvence, večje ali manjše širine; bolj kot so ti impulzi širši, bo srednji tok skozi motor (prikazan je z rdečim stolpcem z leve strani vsakega diagrama) večji in tudi motor se bo hitreje vrtel. Zgornji in spodnji diagram prikazujeta mejne vrednosti, v katerih ni impulzov in motor se ne bo vrtel (zgoraj) ali pa se bo vrtel s polno hitrostjo, ker je stalno vezan na napajalno napetost (spodaj). Postopek se imenuje pulzno-širinska modulacija (PWM), in motor se bo stalno in brez trzljajev vrtel samo, če je frekvenca impulzov dovolj visoka, pa vendar ne previsoka (pri malih elektromotorjih je optimalna frekvenca 50-200 Hz).
Mikrokontroler na Arduino Uno ploščici, ATmega328P ima vgrajena vezja, ki lahko generirajo nize impulzov kot tisti na sliki 6. Kako dela eno od teh vezij, Timer0, je prikazano na sliki 7. Timer0 šteje impulze, ki jih dovajamo na njegov vhod; v tem primeru so to impulzi frekvence 62,5 kHz. Če ga konfiguriramo tako, da dela v PWM načinu, bo štel impulze od 0 do 255 in nato nazaj, od 255 do 0. Trenutna vrednost števca se primerja s številom vpisanim v registre OCR0A in OCR0B:
- Ko se med štetjem navzgor izenači vrednost števca s številom v enem od vzporednih registrov, bo mikrokontroler postavil ustrezen priključek v stanje “0”;
- Ko se med štetjem navzdol izenači vrednost števca s številom v enem od vzporednih registrov, bo mikrokontroler postavil ustrezen priključek v stanje “1”.
Tako z vpisom ustreznega števila v vzporedne registre določamo širino impulzov, ki jih Timer0 generira na ustreznih priključkih OC0A (~6 na Arduino Uno ploščici) in OC0B (~5 na Arduino Uno ploščici). Širina impulzov bo večja, kolikor je večja vrednost vpisana v vzporedni register, frekvenca impulzov je določena z vhodno frekvenco (v našem primeru, 62,5 kHz) in procesom štetja (256 navzgor + 256 navzdol = 512):
f = 62.500 : 512 ≈ 122 Hz
Opomba: Timer0 je zelo zmogljivo vezje in lahko dela na več različnih načinov; generiranje širinsko moduliranih impulzov je samo eden od njih. Način dela timerja določamo med postopkom konfiguracije, ki bo v Bascom-AVR programu bolj jasno vidna, medtem ko je v Arduino IDE postopek “skrit” za ukazom, s katerim “opisujemo” kaj želimo doseči. Važno je ugotoviti, da se potem, ko timer konfiguriramo, z njim ne ukvarjamo več; timer bo generiral zadani niz impulzov, dokler ne spremenimo vrednosti v enem od vzporednih registrov ali dokler mu ne spremenimo načina dela ali dokler ga ne zaustavimo.
Shema vezja za krmiljenje hitrost vrtenja enosmernega elektromotorja je prikazana na sliki 8. Elektromotor E je vezan med priključka M1 in -M, zato ga vklopimo z vezanjem + priključka napajalne napetosti na M1. To naredijo elektronska vezja znotraj integriranega vezja L272M, krmiljena z impulzi, ki jih generira mikrokontroler na svojem OC0B (~5) priključku. Uporabili bomo še potenciometer RV1 na Shield-B ploščici.
- programska naloga: Napišite program, ki bo krmilil hitrost elektromotorja E v vezju prikazanem na sliki 8. Program mora brati napetost na drsniku potenciometra RV1 in proporcionalno s to napetostjo generirati ustrezen niz impulzov na OC0B (~5) priključku mikrokontrolerja v razponu prikazanem na sliki 6.
Bascom-AVR rešitev (program Shield-B_2.bas)
Po uvodnih konfiguracijskih ukazih, ki se nanašajo na uporabljen mikrokontroler in pogoje, v katerih dela, bomo konfigurirali tudi analogno-digitalni pretvornik in ga pripravili za branje napetosti na drsniku potenciometra RV1:
Config ADC = Single , Prescaler = Auto ,
Reference = Avcc
V ukazu za konfiguracijo boste opazili stavek Reference = Avcc, s katerim smo določili, da se vhodna napetost primerja z napajalno napetostjo. To je uporabljeno zato, ker napetost na drsniku potenciometra prav tako zajema vrednosti od 0 do 5 V. Ostali ukazi določajo način dela A/D pretvornika in v večini primerov nam bo ustrezalo v obliki, v kateri so navedene. Dimenzionirali bomo tudi spremenljivko Rv1, v katero bomo shranili branje napetosti drsnika potenciometra RV1:
Dim Rv1 As Word
Spremenljivka je tipa Word, da bi v njo lahko shranili 10-bitni rezultat A/D pretvorbe. Priključka PC0, ki ga uporabljamo kot vhod v A/D pretvornik, ni potrebno posebej konfigurirati, kot tudi PD5 – takoj ko konfiguriramo Timer0, bo priključek PD5 izgubil svojo funkcijo digitalnega vhoda ali izhoda in “zasedel” ga bo PWM izhod Timera0, OC0B:
Config Timer0 = Pwm , Prescale = 256 ,
Compare B Pwm = Clear Up ,
Compare A = Disconnect
Timer0 je postavljen v PWM način dela s faktorjem deljenja 256, Compare A in Compare B sta v Bascom-AVR imeni za vzporedne (OCR) registre. V tej nalogi bomo uporabili samo OCR0B register, zato smo OCR0A razklenili (disconnect) od njegovega izhodnega priključka OC0A.
Sedaj vstopamo v glavno programsko zanko, v kateri najprej preberemo napetost drsnika potenciometra:
Do
Rv1 = Getadc(0)
Prejeti rezultat je število v razponu od 0 (drsnik je v spodnjem položaju, vhodna napetost je 0 V) do 1023 (drsnik je v gornjem položaju, vhodna napetost je 5 V). Preden ga prenesemo v vzporedni register OCR0B, ga moramo “zmanjšati” v razpon 0-255 (OCR0B je 8-bitni register, zato v njega ne moremo vpisati število večje od 255):
Rv1 = Rv1 / 4
OCR0B = Rv1
Loop
In to je vse, vse preostalo delo opravljajo vezja Timera0! Kolikor je število v OCR0B registru večje, toliko širša bo širina impulza in motor se bo hitreje vrtel; to je prav to, kar smo želeli doseči!
Arduino rešitev (program Shield-B_2.ino)
V Arduino IDE obstaja funkcija analogWrite(), ki nam omogoča enostavno krmiljenje PWM priključkov, oziroma OC izhodov timerja. Funkcija sprejema dva argumenta: število priključka in vrednost od 0 do 255 (označuje širino pulza). Funkcija prepoznava, ali se lahko priključek poveže z OC izhodom timerja in če lahko, prepozna s katerim izhodom. Priključka 5 ni potrebno konfigurirali kot izhodnega, ker bomo uporabili PWM izhod timerja OC0B. Arduino IDE samodejno konfigurira timerje v PWM načinu dela s faktorjem deljenja 64, zato nam tega ni potrebno narediti.
Na začetku programa bomo definirali spremenljivko RV1 kot int in definirali vrednost 0. V njo bomo shranili prebrano vrednost s potenciometra RV1.
int RV1 = 0;
Ker funkcija analogWrite() direktno krmili priključek 5, v funkciji setup() ni potrebno posebej definirati načina dela priključka. Zato bo funkcija setup() brez ukaza:
void setup() {
}
V funkciji loop() bomo prebrali napetost drsnika potenciometra RV1 in ga shranili v spremenljivko RV1, nato bomo vrednost spremenljivke RV1 delili s 4 in s pomočjo ukaza analogWrite() dodali to vrednost ustreznemu OC registru timerja za priključek 5.
void loop() {
RV1 = analogRead(A0);
RV1 = RV1 /4;
analogWrite(5, RV1);
}
Samo za radovedne: ukaz analogWrite() najprej definira priključek kot izhodni in nato preverja, ali je vrednost širine impulzov 0 ali 255. V kolikor je širina impulzov 0, definira stanje priključka LOW; če je širina impulzov 255, definira stanje priključka HIGH. Za vse vrednosti širine impulzov med 0 in 255 preverja, če se priključek lahko veže na enega od timerjev in če je to možno, veže priključek s timerjem in vpisuje vrednost v ustrezen OC register. S tem algoritmom je omogočena uporaba ukaza analogWrite() tudi s priključki, ki se ne morejo vezati na nek timer.
Impulzi, ki jih proizvaja mikrokontroler na svojem OC0B (~5) izhodu, razen da krmilijo integrirano vezja L272M, in preko njega tudi hitrost vrtenja elektromotorja, določajo tudi intenzivnost svetilnosti svetleče diode D2 na razvojnem sistemu Shield-B. Dioda bo svetila toliko bolj, kolikor so impulzi širši oziroma, kolikor se motor hitreje vrti. To nam lahko kaže pravilno delovanje programa tudi če na razvojni sistem ne vežemo elektromotorja!
Lahko opazimo, da se elektromotor ne bo zavrtel pri zelo ozkih impulzih, pri katerih je LED-ica že začela svetiti. To je normalno, motor ima določeno vztrajnost, ki jo je potrebno premagati, da bi ga pognali iz mirovnega stanja. Kakšna širina impulzov je potrebna za začetek vrtenja, je odvisno od karakteristik samega elektromotorja in od frekvence impulzov, s katerimi ga vrtimo.
Če želimo iz programa menjati smer vrtenja DC elektromotorja, moramo njegove priključke vezati na priključke M1 in M2 razvojnega sistema Shield-B (slika 9). Kako deluje takšno vezje, bomo pojasnili s pomočjo slike 10.
S1 in S2 sta elektronski stikali vgrajeni v integrirano vezje L272M, M1 in M2 pa sta priključka, na katera je priključen elektromotor. Ko sta stikali v položaju prikazanem na sliki 10 zgoraj, skozi elektromotor teče tok “iz leve proti desni”, in motor se vrti v enim smeri. Ko sta stikali v položaju prikazanem na sliki 10 spodaj, skozi elektromotor teče tok “iz desne proti levi”, in motor se vrti v nasprotni smeri. Ko sta obe stikali v zgornjem ali v spodnjem položaju, je tokovni krog je prekinjen in elektromotor se ne vrti.
Vezje spominja na črko H in zato je dobilo ime H-most. Prednost takšnega vezja je očitna: s programskim postavljanjem elektronskih stikal v različne položaje lahko zavrtimo elektromotor v eno ali v drugo smer ali ga zaustavimo. Pomanjkljivost pa je, da smo izkoristili oba izhodna priključka in zato je na opisani način možno vezati samo en elektromotor.
V vezju, katerega shema je prikazana na sliki 9, s stikali krmilimo napetost na + vhodih integriranega vezja L272M. Ko je krmilna napetost enega od stikal pod 2 V, bo stikalo v “spodnjem” položaju, oziroma, njen izhodni priključek bo vezan na – pol napajalne napetosti. Ko je krmilna napetost enega od stikal višja od 2 V, bo stikalo v “zgornjem” položaju oziroma, njen izhodni priključek bo vezan na + pol napajalne napetosti. (točna napetost, pri kateri stikalo menja stanje je odvisna od padca napetosti na zelenem segmentu LED-ice D1g, ki znaša okoli 2 V.) Tok bo stekel skozi elektromotor ko sta stikali v različnih stanjih, smer toka in s tem tudi smer vrtenja pa sta odvisna od tega, katero stikalo je v “zgornjem” in katero je v “spodnjem” položaju.
- programska naloga (H most): Za vezje po shemi na sliki 9 napišite program, ki bo:
dokler držimo pritisnjeno tipko SW2, zavrtite elektromotor E v eni smeri,
dokler držimo pritisnjeno tipko SW3, zavrtite elektromotor E v nasprotni smeri,
ko spustimo obe tipki, zaustavite motor.
Bascom-AVR rešitev (program Shield-B_3.bas)
Po uvodnih konfiguracijskih ukazih, ki se nanašajo na uporabljen mikrokontroler in pogoje, v katerih dela, bomo konfigurirali priključka PD5 in PD6 kot izhodna
Config PORTD.5 = Output
Config PORTD.6 = Output
medtem ko bomo priključka PC2 in PC3 konfigurirali kot vhodna z vključenima pull-up uporoma:
Config PORTC.2 = Input
Config PORTC.3 = Input
PORTC.2 = 1
PORTC.3 = 1
Nato vstopamo v glavno zanko, v kateri preverjamo, ali je katera od tipk pritisnjena. Če je to tipka SW2, bomo postavili izhode PD5 in PD6 v različni stanji in tako zavrteti elektromotor:
Do
If PINC.2 = 0 Then
PORTD.5 = 1
PORTD.6 = 0
Za razliko od prvega programa moramo tukaj počakati, da se tipko spusti in šele potem lahko krenemo dalje:
While PINC.2 = 0
Wend
End If
Isto proceduro bomo ponovili s tipko SW3, samo da bomo tukaj izhoda postavili v nasprotni stanji:
If PINC.3 = 0 Then
PORTD.5 = 0
PORTD.6 = 1
While PINC.3 = 0
Wend
End If
Če ni pritisnjena niti ena tipka, oba izhoda postavljamo v isto stanje, da bi tako zaustavili elektromotor:
PORTD.5 = 0
PORTD.6 = 0
Loop
Arduino rešitev (program Shield-B_3.ino)
V funkciji setup() konfiguriramo priključka 5 (PD5) in 6 (PD6) kot izhodna, priključka A2 (PC2) in A3 (PC3) pa kot vhodna z vključenima pull-up uporoma:
void setup() {
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
}
Nato v funkciji loop() uporabimo isto programsko logiku kot v Bascom-AVR primeru. Za branje stanja tipk uporabimo ukaz digitalRead(), za postavljanje stanja priključkov 5 in 6 uporabimo ukaz digitalWrite().
void loop() {
if (digitalRead(A2) == 0) {
digitalWrite(5, HIGH);
digitalWrite(6, LOW);
while(digitalRead(A2) == 0){}
}
if (digitalRead(A3) == 0) {
digitalWrite(5, LOW);
digitalWrite(6, HIGH);
while(digitalRead(A3) == 0){}
}
digitalWrite(5, LOW);
digitalWrite(6, LOW);
}
Naslednja programska naloga se nanaša na shemo na sliki 11; v njej bomo kombinirali obe aktivnosti: spremembo hitrosti in spremembo smeri vrtenja!
- programska naloga (H most): Za vezje po shemi na sliki 11 napišite program, ki bo krmilil s hitrostjo in smerjo vrtenja elektromotorja E na naslednji način:
dokler je drsnik potenciometra RV1 v srednjem položaju, motor stoji;
ko premikamo drsnik potenciometra RV1 po enem skrajnem položaju, naj se motor vrti vse hitreje v eni smeri;
ko premikamo drsnik potenciometra RV1 po drugem skrajnem položaju, naj se motor vrti vse hitreje v nasprotni smeri.
Bascom-AVR rešitev (program Shield-B_4.bas)
Analogno-digitalni pretvornik bomo pripravili za branje napetosti na drsniku potenciometra RV1 na isti način kot v 2. programski nalogi:
Config ADC = Single , Prescaler = Auto ,
Reference = Avcc
Timer0 dela na isti način kot v 2. programski nalogi, vendar sedaj potrebujemo PWM impulze na obeh izhodih, prav tako, kot je tudi bilo prikazano na shemi na sliki 7. Zato bomo med konfiguracije vključili tudi OC0A in OC0B:
Config Timer0 = Pwm , Prescale = 256 ,
Compare A Pwm = Clear Up ,
Compare B Pwm = Clear Up
V glavni zanki preberemo napetost drsnika potenciometra in z deljenjem s faktorjem 2 privedemo branje znotraj razpona 0-511:
Do
Rv1 = Getadc(0)
Rv1 = Rv1 / 2
Če je vrednost večja od 255, jo zmanjšujemo za 255 in dobljeni rezultat prenesemo v OCR0A register, v OCR0B pa vpišemo 0:
If Rv1 >= 256 Then
Ocr0a = Rv1 – 256
Ocr0b = 0
S tem smo OC0B izhod postavili na 0 V, dokler so na OC0A izhodu impulzi, katerih širina je proporcionalna odklonu drsnika potenciometra od srednjega položaja. Zato se bo tudi elektromotor vrtel toliko hitreje, kolikor je odklon večji. Če je vrednost branja 255 ali manjša, jo odštejemo od 255 in prenesemo v OCR0B, v OCR0A register pa vpišemo 0:
Else
Ocr0a = 0
Ocr0b = 255 – Rv1
End If
Loop
Tako smo OC0A izhod postavili na 0 V, dokler so na OC0B izhodu impulzi, katerih širina je proporcionalna odklonu drsnika potenciometra od srednjega položaja. In tukaj se bo elektromotor vrtel toliko hitreje, kolikor je odklon drsnika večji. Vendar pa sedaj tok teče v nasprotni smeri in smer vrtenja se bo spremenila.
Arduino rešitev (program Shield-B_4.ino)
Na začetku programa bomo definirati spremenljivko RV1 kot int in ji dodelili začetno vrednost 0. V spremenljivko bomo shranjevali prebrano vrednost s potenciometra RV1.
int RV1 = 0;
Ker funkcija analogWrite() direktno krmili priključka ~5 in ~6, nam v funkciji setup() ni potrebno posebej definirati načina dela teh priključkov. Zato bo funkcija setup() brez ukazov:
void setup() {
}
V funkciji loop() uporabimo isto programsko logiku kot v Bascom-AVR primeru. S pomočjo ukaza analogWrite() bomo dodali vrednosti pripadajočima OC registroma timerja, ki krmilita priključka ~5 in ~6.
void loop() {
RV1 = analogRead(A0);
RV1 = RV1 /2;
if (RV1 >= 256) {
analogWrite(5, RV1 – 256);
analogWrite(6, 0);
} else {
analogWrite(5, 0);
analogWrite(6, 255 – RV1);
}
}
Opomba: Programe Shield-B_2.bas, Shield-B_2.ino, Shield-B_3.bas, Shield-B_3.ino, Shield-B_4.bas in Shield-B_4.ino lahko brezplačno dobite od uredništva revije Svet elektronike!
https://svet-el.si