Arduino steruje mocą grzałki
Hej! Dziś na łamach bloga za pomocą Arduino zaprojektujemy i wykonamy na płytce stykowej tak zwany grupowy regulator mocy. Jest to urządzenie za pomocą którego będziemy mogli sterować mocą np. grzałki na prąd przemienny. Zapraszam do lektury!
Najczęściej kiedy chcemy wysterować moc jakiegoś urządzenia zasilanego prądem przemiennym projektujemy układ, który po każdym przejściu sinusoidy przez punkt 0 wycina jej część. Im większa część zostanie wycięta tym mniejsza będzie moc odbiornika.
Niestety niesie to ze sobą konsekwencje w postaci sporych zakłóceń, które mogą niekorzystnie wpływać na pracę mikrokontrolera jeżeli nie zostaną dobrze odfiltrowane. Jeżeli jednak potrzebujemy zbudować taki regulator do urządzenia o charakterze rezystancyjnym, o dużej bezwładności np. grzałka do wody to idealnym rozwiązaniem dla nas będzie zbudowanie grupowego regulatora mocy. Różni się od tego opisanego powyżej tym, że podczas działania generuje dużo mniejsze zakłócenia oraz jest bardzo prosty w implementacji.
Zasada działania jest prosta – zliczamy ile razy napięcie przeszło przez zero. Jeżeli chcemy wysterować grzałkę x/y częścią pełnej mocy to włączamy ją przy pierwszym przejściu na kolejne x przejść po czym wyłączamy, a następnie po y przejściach włączamy ponownie. Zilustrujmy to na przykładzie:
Napięcie w gniazdkach w Polsce ma kształt sinusoidy o częstotliwości 50 Hz. Oznacza to, że w każdej sekundzie mamy pięćdziesiąt pełnych okresów. Sinusoida przechodzi przez 0 dwa razy na każdy okres, więc jedna sekunda to sto takich przejść przez 0. Załóżmy, że chcielibyśmy wysterować naszą grzałkę na 25% mocy – oznacza to, że na każdą sekundę powinna być ona włączona przez ćwierć sekundy. Wiemy, że w sekundę sinusoida przejdzie przez zero sto razy. Zliczamy więc pierwsze 25 przejść, po czym wyłączamy grzałkę i czekamy przez 75 przejść. Po tym czasie zaczynamy proces od nowa. Wygląda banalnie prawda? I takie też jest w implementacji.
Schemat
Uwaga! Napięcie sieciowe 230V jest niebezpieczne dla życia i zdrowia. Z tego też powodu zalecam prototypowanie na niskim napięciu (np. przez zasilacz w szczelnej obudowie, który na wyjściu da nam 12V AC). Po zrobieniu gotowego układu na płytce drukowanej, który miałby pracować z napięciem sieciowym należy zachować szczególną ostrożność a w przypadku osób małoletnich wykonywać takie prace tylko pod nadzorem osoby dorosłej!
Potrzebne elementy:
- Triak BTA24-600BW
- Optotriak MOC3041
- Transoptor PC817
- Rezystor ograniczający prąd dla diody w PC817
- Rezystor o dużej rezystancji np. 10K
- Gotowy mostek prostowniczy lub 4 diody
- Potencjometr
- Arduino, breadboard, trochę kabelków
UWAGA! Na schemacie zaznaczony jest rezystor R1 o rezystancji 220 Ω. Jest to rezystancja odpowiednia dla niskiego naięcia (ok. 12V prądu przemiennego). Jeżeli chcielibyśmy podłączyć tam pełne napięcie sieciowe należy użyć rezystora o większej rezystancji (dla 230V dobry będzie 220 kΩ).
L oraz N na schemacie to kolejno faza i przewód zerowy, GND oraz VCC to zasilanie z Arduino. Pozostałe wejścia / wyjścia zostały opisane tak jak w programie.
Jak to ma działać? Optotriak będzie bezpiecznie z poziomu Arduino sterował dużym triakiem, rezystor posłuży jako obciążenie, coby przebieg był widoczny na oscyloskopie. Mostek prostowniczy wymusi na wejściu transoptora napięcie dodatnie (będziemy tam mieli moduł z sin(x) ), a transoptor da nam już logiczne 0 lub 1 na wejściu Arduino. Podłączymy go do wejścia obsługującego przerwania, żeby móc natychmiastowo reagować na zmianę stanu.
Kod programu
Oto cały listing:
const int ZERO_CROSSING = 2; const int OUT = 5; const int POT = A5; volatile int zeroCrossCount = 0; int power = 0; void setup() { pinMode(OUT, OUTPUT); pinMode(ZERO_CROSSING, INPUT_PULLUP); pinMode(POT, INPUT); attachInterrupt(digitalPinToInterrupt(ZERO_CROSSING), zeroCross, FALLING); } void loop() { power = map(analogRead(POT), 0, 1023, 0, 100); digitalWrite(OUT, zeroCrossCount < power || power == 100); } void zeroCross() { zeroCrossCount = (zeroCrossCount + 1) % 101; }
Na początku jak zwykle ustawiamy kilka przydatnych stałych i zmiennych. Zmienną zeroCrossCount deklarujemy jako volatile, gdyż będzie się ona bardzo często zmieniała i nie chcemy, żeby kompilator nam ją zoptymalizował
W funkcji setup() najważniejsze jest wywołania attachInterrupt(). Funkcja ta ustawia nam przerwanie na wybranym przez nas pinie. W momencie, kiedy stan na danym pinie zmieni się z wysokiego na niski (FALLING) to wywoła nam się funkcja o nazwie zeroCross().
Ważne jest, aby funkcja obsługująca przerwanie robiła jak najmniej. Tak, żeby zajmować jak najmniej czasu procesora – z tego też powodu u nas będzie ona tylko inkrementowała zmienną zeroCrossCount oraz pilnowała, aby ta nie była większa niż 100.
W funkcji loop() musimy zadbać o to, żeby przeskalować wartość odczytaną z potencjometru (0 – 1023) na wartość od 0 do 100. Pomoże nam w tym zadaniu funkcja map(). Teraz już tylko prosty warunek: jeżeli zeroCrossCount będzie mniejsze bądź równe ustalonej mocy (która przekłada się u nas na liczbę przejść przez 0) to wyrażenie zwróci nam TRUE, czyli stan wysoki. W przeciwnym wypadku FALSE, czyli stan niski. Należy też uwzględnić opcję, kiedy mamy power = 100 i zeroCrossCount = 100. W takim przypadku na wyjściu Arduino będzie logiczne zero, chociaż oczekiwalibyśmy stanu wysokiego – dlatego też dodajemy OR power == 100.
Oto i cała magia. Teraz wystarczy wgrać program na płytkę i sprawdzić przebieg na zaciskach rezystora obciążającego na oscyloskopie.
Witam
Mam prośbę czy mógł by Pan przedstawić kod wraz ze schematem regulatora pid i sterownika grupowego na Arduino , pid ma pobierać dane ds18b20 bardzo prosze o pomoc.
Witam!
W przypadku użycia grzałki która ma dużą bezwładność moim zdaniem najlepszym i najprostszym wyborem będzie ustawienie histerezy :) Czyli jeżeli temperatura przekroczy np. 60 stopni to wyłączamy grzałkę, a kiedy spadnie poniżej 55 załączamy ją ponownie. W ten sposób utrzymamy w miarę stabilną temperaturę :)
Mam grzałkę 1.5 kw i musi ona utrzymać temperaturę w miarę dokladna na.kolumnie 77,8 st.c. i chciałem zbudować sterownik dam od zara
Jestem pod wrażeniem. A czy da radę zrobić to samo z panelem fotowoltaicznym (który daje prąd stały i robi łuk przy rozłączeniu) oraz grzałką?
Witam autora, bardzo zaciekawił mnie projekt. Przymierzam się aby wykonać podobny układ.
W swoim projekcie chciałbym sterować mocą grzałki ale w zależności od temperatury.
Ze względu na specyfikę pracy standardowa histereza się tu nie sprawdzi. Układ ma działać w kanale dolotowym powietrza do rekuperatora (czerpni). Nagrzewnica ma się załączać możliwie jak najkrócej i z minimalną potrzebną mocą tak by dogrzewać powietrze i zapobiec zamarznięciu wymiennika. Stąd wybór sterowania grupowego. Chciałbym użyć czujnika temp DS18B20 zamiast potencjometru który podawałby by temperaturę powietrza z kanału dolotowego i w zależności od temp zadanej do której ma dążyć dobierał by odpowiednio moc grzania. Podpowiedział byś jak użyć tu funkcji MAP? Ewentualnie może masz jakieś inne wskazówki.
Cześć, przepraszam że dopeiro teraz odpowiadam na Twoje pytanie, ale miałem naprawdę ciężki tydzień :) Wracając do tematu – użycie funkcji map() może się tutaj w mojej opinii średnio sprawdzić, gdyż temperatura z DS18B20 będzie pewnie jako liczba zmiennoprzecinkowa, a map() operuje na liczbach całkowitych. Jednak to żaden problem samemu napisać sobie taką funkcję. Z dokumentacji Arduino funkcja map() stosuje taką matematykę:
return (x – in_min) * (out_max – out_min) / (in_max – in_min) + out_min;
gdzie x to liczba którą chcemy zmapować, in_* to wartości wejściowe, czyli zakres wartości x, którą mierzymy, a out_* to wyjścowe, czyli przedział, który chcemy uzyskać. Co prawda przy floatach będzie to minimalnie niedokładne z uwagi na to że niektóre liczby zmiennoprzecinkowe nie są wymierne w systemie dwójkowym. Dzięki takiej funkcji będziesz mógł obliczyć moc grzania np. w % i stąd już z górki :) Przy histerezie też bym został bo załóżmy że załączamy grzanie przy temepraturze 50 stopni C. Termometr wskaże 50, a po chwili przez jego niedokładność da wynik 49.9 i grzałka będzie nam się bezsensownie załączałą i wyłączała. Myślę że sensownym rozwiązaniem byłoby połączenie map() napisanej dla floatów i histerezy.
Nic się nie stało, wiadomo teraz gorący okres świąteczny. Dziękuję że poświeciłeś mi swój cenny czas.
Sprawdzę jak działa to wszystko po zmontowaniu bo grzałka ma swoją bezwładność ale dużo będzie zależało od prędkości przepływu powietrza i temperatury zewnętrznej. Słusznie zauważyłeś ze napewno trzeba będzie uniknąć takich sytuacji by grzalka załączała i wyłączała się co chwile wiec jakaś minimalna histereza się przyda. Aczkolwiek przy przekaźnikach ssr nie powinno to stanowić aż takiego problemu.
Pozdrawiam, mario
Witam
Wydaje się że rezystancja opornika R1 jest zdecydowanie za mała 220R (powinno być raczej 220k).
Po zamontowaniu w takiej konfiguracji rezystor najzwyczajniej spalił się, tak się również stało z PC817.
Poza tym układ działa prawidłowo.
Witam, oczywiście układ działa poprawnie z rezystancją 220R przy napięciu zmiennym 12V z transformatora. Ma Pan 100% racji, że w przypadku podłączenia tam 230V należy użyć rezystora o większej rezystancji (moje przeoczenie). Dziękuję za trafny komentarz i już poprawiam artykuł :)
witam mam pewien problem z zlozeniem obowodu w miejscu gdzie wyjscia z pc817 laczy sie z mostkiem. Otoz widze na zdjeciu ze jeden pin z moc laczy sie z bramka triaka drugi z wyjscie thermal 1 natomiast thermal 2 wedlug schematu idzie na ta sama sciezke co wyjscie ac – z mostka a na zdjeciu z thermal2 triaka wychodzi jakis bialy kabelek poza kadr.. czy ktos jest mi w stanie jakos jasniej przedstawic ten fragment schematu?