
Magnetisk loop #04
Arduino som PWM
(Return later for English version – – est. August 2016)
(Download Gerber-files for the PCB: PWM MagLoop Gerber)
Da jeg havde bygget en magnetisk loop antenne, fik jeg brug for at kunne kontrollere den motor, som er forbundet til antennens drejekondensator. Det optimale er selvfølgelig at benytte en stepper motor, men en almindelig DC motor kan sagtens bruges. Den motor, som jeg benytter, er forsynet med udveksling, men det er ikke tilstrækkeligt, når man virkelig skal fintune en antenne med så smal en båndbredde. Vi taler om ganske få kHz, så motoren skal kunne køre særdeles langsomt. Skal man derimod flytte til den anden ende af båndet, skal det gå noget hurtigere. Pulse Width Modulation kan være løsningen på det problem og til min første loop antenne lavede jeg en PWM baseret på en NE555. Opskriften på det kan man finde mange steder. Her er f. eks. en med formler og printudlæg. Der skal blot tilføjes en transistor, som kan tåle strømmen gennem motoren og et dobbelt relæ, så man kan køre reverse.
Hardware
Det er imidlertid oplagt at benytte en Arduino til at løse opgaven.
En Arduino, som er bygget op over en Atmega328 (f. eks. Nano og Uno) har indbygget PWM signal på ben 3, 5, 6, 9, 10 og 11. På ben 5 og 6 er frekvensen af signalet 980 Hz. Der er tale om et 8-bits output, hvilket betyder, at virkningsgraden kan sættes fra 0 – 255. Man sætter virkningsgraden med kommandoen:
analogWrite(pin, value)
analogWrite har INTET at gøre med de analoge pins eller med analogRead. Det er ikke nødvendigt at sætte den pågældende pin op som OUTPUT, før man kalder analogWrite.
Der skal kun benyttes ganske få eksterne komponenter:
- IRF520 Mosfet (eller tilsvarende)
- 2 relæer (5V)
- 1N4001 diode
- 4 pushbuttons
- 5 LEDs (6 hvis man vil have indikator for ON/OFF)
- 5 modstande på 220 Ω
Jeg bygger som oftest mine Arduino konstruktioner op på et breadboard først, så jeg kan justere kode og opbygning, inden det eventuelt skal på print og i kasse. Min konstruktion ser ud som på denne Fritzing illustration (klik på den for at se den i stor udgave):
Det er værd at bemærke følgende:
- For at kunne køre begge veje, skal motoren tilsluttes via to relæer og dens ledninger skal sluttes til relæernes midterste ben, som det ses på tegningen. De små røde ledninger er +9V. PWM signalet fra Arduinoen bliver ført frem i de violette ledninger.
- Spolen inde i motoren kan reagere med en modsat rettet spænding, når vi pludselig sender en strøm igennem den. Det kan lave en del ballade i vores kredsløb, så derfor skal der være en beskyttelsediode, som fanger denne modsatrettede peak. Bemærk at den IKKE kan sidde direkte på motoren, fordi vi vender polariteten, når motoren skal køre reverse.
- Der er 9 V (fra batteriet) i den øverste række rød/blå. !!!
- Arduinoen bliver drevet af de 9 V, som bliver ført frem til ben 30 (Vin). Pas på, der er IKKE polaritetsbeskyttelse.
- Det burde kunne lades sig gøre at køre på 12 V (Altså som i tolv, ikke som i 13,6). Der er dog rapporter om, at visse af de billige kloner fra Kina kan få problemer. Men no worry. Du vil opdage det på røgen 😉
- Der er 5 V (fra Arduino) i den nederste række rød/blå. !!!
- GND fra 5 V og fra 9 V skal forbindes.
- På de lange breadboards er de øverste, gennemgående røde/blå strømskinner ofte afbrudt på midten. Du skal selv forbinde de to halvdele med en lille lus.
- Ditto i forhold til de nederste.
Et billede af min prototype…….
Software
Jeg har valgt, at min PWM styring skal arbejde med tre hastigheder og at disse skal vælges med to pushbuttons. Trykker man på ‘Fast’, sættes duty-cycle til 100%. Taster man en gang til, sættes duty-cycle til ‘Medium’. Trykker man ‘Slow’, sættes den til 50/255. Taster man igen, er vi tilbage ved ‘Medium’. De to pushbuttons er med andre ord kodet til at fungere som toggle on/off.
Der sker imidlertid ikke noget, før man enten taster ‘Forward’ eller ‘Reverse’. Og motoren kører kun så længe, man trykker på en af disse to taster.
Jeg har lavet en klasse, som er kernen i koden. Den håndterer inputs fra pushbuttons, den styrer relæet og duty-cycle på vores PWM signal. Klassen, jsPWM, har jeg gemt som et library, der kan hentes her i zip-format. Hvis du installerer det i Arduino IDE, kan du gå ind under ‘File/Examples/jsPWM. Her kan du enten åbne PWM_w_LIBRARY, som bruger mit library. Eller du kan åbne PWM_w_CLASS. Den sidste sketch kan køre, uden at du installerer library. Den kan også åbnes direkte ved at du henter zip-filen og pakker den ud. Men uanset om du vælger det ene eller det andet, skal du vælge pins (eller se, hvilke jeg har valgt), så du kan få din hardware til at passe med sketchen.
Du kan også copy-paste fra boksen nederst i denne post.
Du SKAL have disse 4 – de er til de 4 pushbuttons:
const byte SLOW_PIN = 2; //set PWM efficiency low – TOGGLE
const byte FAST_PIN = 3; //set PWM efficiency high – TOGGLE
const byte REVERSE_PIN = 4; // reverse button
const byte FORWARD_PIN = 5; // forward button
PWM signalet kan findes her:
const byte PWM_PIN = 6; // PWM output
Du KAN installere nogle eller alle af disse (men lad bare koden stå, selv om du ikke sætter en LED til den pågældende PIN):
const byte FAST_LED_PIN = 7;
const byte MEDIUM_LED_PIN = 8;
const byte SLOW_LED_PIN = 9;
const byte REVERSE_LED_PIN = 10;
const byte FORWARD_LED_PIN = 11;
Relæet bliver styret herfra:
const byte RELAY_PIN = 12;
Jeg anbefaler at du ikke ændrer ved ovenstående tildelinger af PINs!
Derimod skal du sandsynligvis ændre ved disse værdier. Prøv dig frem, så det passer til dit setup:
const byte SLOW_PWM = 50;
const byte MEDIUM_PWM = 100;
const byte FAST_PWM = 255;
For at vore toggle buttons ikke skal gå helt amok, bør der være et lille tidsrum, før den samme PIN bliver aflæst igen. Som default har jeg valgt 1/4 sekund.
const unsigned int BUTTON_DELAY = 250;
TIPS
- Det kan være en fordel at montere LEDs og pushbuttons først. På den måde kan det være mere overskueligt at teste, om kontrollogikken fungerer. De to LEDs for ‘Slow’ og ‘Fast’ skal lyse, når man taster de tilhørende pushbuttons. ‘Medium’ skal lyse, når intet andet er valgt. Forward og reverse skal ligeledes kunne aktiveres af de tilhørende pushbuttons.
- Dernæst er det en god ide at slutte motoren til de 9 V og PWM signalet fra vores mosfet. På den måde kan man let teste, om der er hul igennem. Hvis alt fungerer, er det blot at tilslutte relæerne.
- Stumperne er helt almindelige og gængse og kan fås mange steder. Men på Ebay eller Aliexpress får du virkelig meget for pengene. Og så længe man holder sig til at købe komponenter, er kvaliteten som oftest ganske god. Søg eksempelvis på ‘Arduino relay’ eller ‘Arduino pushbuttons’. Så er du godt i gang.
- I denne type konstruktioner er det en STOR fordel at bruge oscilloskop. Har du ikke et, så kig på brugtgrej.dk. Her er det fra tid til anden muligt at erhverve sig et scop for en slik. Det forholder sig nemlig sådan, at de fleste af os, der ofte bruger scop har anskaffet et digitalt, der ikke fylder så meget på bordet. Du kan også annoncere efter et. det skal ikke koste mere end max. 300-500 kr.
- – men man kommer nu også langt med et godt multimeter 😉
Links:
# | Titel | Title |
---|---|---|
01 | Intro | Intro |
02 | Materialer | BOM |
03 | Opbygningen | How to build |
04 | Arduino som PWM | Arduino running as PWM |
04A | Arduino med H-Bridge | |
05 | Kloge Åge | Elmers |
06 | On Air | On air |
07 | Vidunder eller myter? | Wonder or myths? |
08 | Fjernfelt | Far Field |
09 | Nærfelt | Near Field |
Koden til min Pulse Width Generator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
//MANDATORY: You MUST install 4 pushbuttons const byte SLOW_PIN = 2; //set PWM efficiency low - TOGGLE const byte FAST_PIN = 3; //set PWM efficiency high - TOGGLE // otherwise PWM efficiency is medium const byte REVERSE_PIN = 4; // reverse button const byte FORWARD_PIN = 5; // forward button const byte PWM_PIN = 6; // PWM output //OPTIONALLY: You MAY install some or all of 5 LEDs, // - but you need the constants for compatibility const byte FAST_LED_PIN = 7; const byte MEDIUM_LED_PIN = 8; const byte SLOW_LED_PIN = 9; const byte REVERSE_LED_PIN = 10; const byte FORWARD_LED_PIN = 11; const byte RELAY_PIN = 12; //adjust this to match the motor of your choice const byte SLOW_PWM = 50; const byte MEDIUM_PWM = 100; const byte FAST_PWM = 255; //delay between toggle FAST/SLOW/MEDIUM const unsigned int BUTTON_DELAY = 500; //start of CLASS class jsPWM { public: jsPWM(byte SlowPin, byte FastPin, byte ReversePin, byte ForwardPin, byte PWMPin, byte FastLedPin, byte MediumLedPin, byte SlowLedPin, byte ReverseLedPin, byte ForwardLedPin, byte RelayPin, byte SlowPwm, byte MediumPWM, byte FastPWM, unsigned int ButtonDelay); void run(); private: boolean _Forward = false, _Reverse = false, _Fast = false, _Slow = false, _Medium = false; byte _PWMEfficiency = 0; byte _SlowPin=0, _FastPin=0, _ReversePin=0, _ForwardPin=0; byte _PWMPin, _FastLedPin, _MediumLedPin, _SlowLedPin; byte _ReverseLedPin=0, _ForwardLedPin=0, _RelayPin=0; byte _SlowPwm=0, _MediumPWM=0, _FastPWM=0; unsigned int _ButtonDelay=0; unsigned long _DelayFast = millis(), _DelaySlow = millis(); void readButtons(boolean &Forward, boolean &Reverse, boolean &Fast, boolean &Slow ); void showStatus(); void turnLedOnOff(byte Pin, boolean Button); void controlPWM(); }; // * * * * IMPLEMENTATION OF THE CLASS jsPWM::jsPWM(byte SlowPin, byte FastPin, byte ReversePin, byte ForwardPin, byte PWMPin, byte FastLedPin, byte MediumLedPin, byte SlowLedPin, byte ReverseLedPin, byte ForwardLedPin, byte RelayPin, byte SlowPwm, byte MediumPWM, byte FastPWM, unsigned int ButtonDelay) { _SlowPin = SlowPin; _FastPin = FastPin; _ReversePin = ReversePin; _ForwardPin = ForwardPin; _PWMPin = PWMPin; _FastLedPin = FastLedPin; _MediumLedPin = MediumLedPin; _SlowLedPin = SlowLedPin; _ReverseLedPin = ReverseLedPin; _ForwardLedPin = ForwardLedPin; _RelayPin = RelayPin; _SlowPwm = SlowPwm; _MediumPWM = MediumPWM; _FastPWM = FastPWM; _ButtonDelay=ButtonDelay; _PWMEfficiency = MediumPWM; _Medium = false; pinMode(_ForwardPin, INPUT_PULLUP); pinMode(_FastPin, INPUT_PULLUP); pinMode(_SlowPin, INPUT_PULLUP); pinMode(_ReversePin, INPUT_PULLUP); pinMode(_PWMPin, OUTPUT); analogWrite(_PWMPin, 0); // Motor off pinMode(_FastLedPin, OUTPUT); pinMode(_MediumLedPin, OUTPUT); pinMode(_SlowLedPin, OUTPUT); pinMode(_ReverseLedPin, OUTPUT); pinMode(_ForwardLedPin, OUTPUT); pinMode(_RelayPin, OUTPUT); } void jsPWM::controlPWM() { if (_Forward == true || _Reverse == true) { analogWrite(_PWMPin, _PWMEfficiency); } else { analogWrite(_PWMPin, 0); } } void jsPWM::run() { readButtons(_Forward, _Reverse, _Fast, _Slow); controlPWM(); } void jsPWM::readButtons(boolean &Forward, boolean &Reverse, boolean &Fast, boolean &Slow) { Forward = (digitalRead(_ForwardPin) == LOW);//goes low when activated if (Forward == true) { Reverse = false; digitalWrite(_RelayPin, HIGH); } showStatus(); Reverse = (digitalRead(_ReversePin) == LOW);//goes low when activated if (Reverse == true) { Forward = false; digitalWrite(_RelayPin, LOW); } showStatus(); if (digitalRead(_FastPin) == LOW) { if (millis() - _DelayFast > _ButtonDelay) { Fast = !Fast; _DelayFast = millis(); } } if (Fast == true) { Slow = false; _PWMEfficiency = _FastPWM; } showStatus(); if (digitalRead(_SlowPin) == LOW) { if (millis() - _DelaySlow > _ButtonDelay) { Slow = !Slow; _DelaySlow = millis(); } } if (Slow == true) { Fast = false; _PWMEfficiency = _SlowPwm; } if (Fast == false && Slow == false) { _Medium = true; _PWMEfficiency = _MediumPWM; } else { _Medium = false; } showStatus(); } void jsPWM::showStatus() { turnLedOnOff(_ForwardLedPin, _Forward); turnLedOnOff(_ReverseLedPin, _Reverse); turnLedOnOff(_FastLedPin, _Fast); turnLedOnOff(_SlowLedPin, _Slow); turnLedOnOff(_MediumLedPin, _Medium); } void jsPWM::turnLedOnOff(byte LedPin, boolean ButtonOn) { if (ButtonOn) { digitalWrite(LedPin, HIGH); } else { digitalWrite(LedPin, LOW); } } jsPWM MyPWM(SLOW_PIN, FAST_PIN, REVERSE_PIN, FORWARD_PIN, PWM_PIN, FAST_LED_PIN , MEDIUM_LED_PIN, SLOW_LED_PIN, REVERSE_LED_PIN, FORWARD_LED_PIN, RELAY_PIN, SLOW_PWM , MEDIUM_PWM, FAST_PWM, BUTTON_DELAY); void setup() { } void loop() { MyPWM.run(); } |