logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Atmega8][C] - sterowanie triakiem - weryfikacja programu

PJimi 18 Cze 2012 12:27 3985 15
  • #1 11013310
    PJimi
    Poziom 13  
    Witam,

    Chciałem poprosić o weryfikację mojego programu do sterowania mocą (poprzez triaka) na Atmega8.
    Działanie programu:
    Najpierw włączone jest przerwanie zewnętrzne na INT0 od detektora zera sieci.
    W przerwaniu od detektora załączany jest timer, którego wysterowanie (liczba impulsów do zliczenia) jest proporcjonalna do wskazania ADC (potencjometr). Następnie uruchamiane jest przerwanie od przepełnienia timera, które wytwarza impuls podany na bramkę triaka.
    Proszę o sugestie odnoście konstrukcji całego programu.
    Z góry dziękuję :)

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #2 11013499
    LordBlick
    VIP Zasłużony dla elektroda
    1. Konstrukcja SIGNAL(SIG_INTERRUPT0) jest przestarzała. Obecnie uzywa się ISR(INT0_vect)
    http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
    2. Nie rozumiesz w ogóle idei Timera - pożegnaj się z
    #include <util/delay.h>
    bo to od razu włosy z głowy rwać, po prostu wieszasz procesor na gałęzi z równie dobrym skutkiem... ;)
    Pierwszy z brzegu w Google przykład obsługi ISR(TIMER0_OVF_vect):
    https://www.elektroda.pl/rtvforum/topic2297391.html
    3. konwersję ADC wywal z przerwania do pętli głównej, zanim się skończy, to przeskoczysz 10 połówek sieci... Naprawdę tak często potrzebujesz odczytywać płożenie potencjometru ?
    4. Z jakim schematem mamy to zweryfikować ?
  • #3 11013528
    PJimi
    Poziom 13  
    Dzięki za rady. Nie ukrywam, że to jest jeden z moich pierwszych programów - nie licząc migania diodami i odczytu pomiaru z ADC na diodach :)

    Jeśli chodzi o "delay" to używam tej komendy tylko w funkcji w przerwaniu od przepełnienia timera. Ale jeśli nie powinienem to ok.

    Faktycznie - natknąłem się w internecie na informacje, że zamiast SIGNAL należy stosować ISR. ISR zastosowałem w przerwaniu od TIMERA0. Być może w przerwaniu zewnętrznym też powinienem.

    Przeanalizuje linki, które podpiąłeś - dzięki.
    Jakiś inne (cenne dla mnie) uwagi?
    Generalnie założenia i ogólna konstrukcja programu jest ok?
  • Pomocny post
    #5 11013542
    LordBlick
    VIP Zasłużony dla elektroda
    PJimi napisał:
    Generalnie założenia i ogólna konstrukcja programu jest ok?
    Generalnie to można się przyczepić do wszystkiego... ;) Nawet do tego, ze F_CPU to się do Makefile wrzuca.
    P.S. Zdążyłem co nieco dopisać wyżej 14 sekund po Twojej odpowiedzi.
  • Pomocny post
    #6 11013558
    tmf
    VIP Zasłużony dla elektroda
    Zobacz w nocie jak działa timer, w szczególności funkcje pinów OCx. Zauważ, że impuls wyzwalający triak może być generowany całkowicie sprzętowo. Dzięki OCx możesz ten impuls wygenerować z zadanym opóźnieniem, w takiej sytuacji wyzwalasz tylko timer w przerwaniu detekcji zera. Tak jak kolega wyżej sugerował zapomnij o delay, szczególnie w przerwnaiu. Zauważ, że takim odpowiednikiem delay jest czekanie w przerwaniu na zakończenie konwersji ADC. Jeśli nie zmieniasz multipleksera to puść ADC w trybie free running i zapomnij o startowaniu konwersji. Zawsze aktualną wartość będziesz miał w ADC. A potrzeby tego programu to wystarczy.
    Poza tym ADC*146 powoduje przekroczenie zakresu int - więc te obliczenia musisz zrealizować inaczej.
  • #7 11014184
    PJimi
    Poziom 13  
    LordBlick:

    3. konwersję ADC wywal z przerwania do pętli głównej, zanim się skończy, to przeskoczysz 10 połówek sieci... Naprawdę tak często potrzebujesz odczytywać płożenie potencjometru ?

    Właśnie tego się, bałem, że konwersja ADC trwa zbyt długo w porównaniu do czasu od startu do przepełnienia Timera. Nie muszę jej wykonywać co każde przejście przez zero - taka dokładność nie jest mi potrzebna. Tylko jeśli wrzucę ją do pętli głównej - to kiedy i jak często będzie wtedy wykonywana? Sprawę komplikuje dodatkowo fakt, że docelowo wartość ładowana do timera jako początkowa będzie pochodziła nie z jednego ADC a z 4 różnych. Ma być to sterownik prędkości obrotowej wentylatora, wiec dochodzą takie nastawy jak: Umax, Umin, Uoff i Uwyj. Buduję ten sterownik w oparciu o ten kit.

    4. Z jakim schematem mamy to zweryfikować ?

    Załączam schemat oparty o w/w kit.


    tmf:

    1. Co to znaczy, że impuls na triak może być generowany całkowicie sprzętowo?

    2. Mogę puścić ADC w trybie free running w głównej pętli tak jak zresztą sugerował LordBlick Rozumiem, że wtedy będzie się wykonywało cały czas raz po razie. A jak poradzić sobie w przypadku gdy będę potrzebował równolegle dokonywać obliczeń z 4 ADC?
  • Pomocny post
    #8 11014217
    tmf
    VIP Zasłużony dla elektroda
    ad. 1. To znaczy, że jak spojrzysz do noty procka, do opisu wyprowadzeń OCx timera to się okaże, że timer może sterować tym pinem prowadząc do zmiany jego stanu. W efekcie wcale nie musisz tego robić programowo. Ustawiasz w timerze opóźnienie, wyzwalasz go w przerwaniu zera i tyle.
    ad. 2. Musisz wtedy pamiętać, że wartość tuż po zmianie MUX będzie dotyczyła jeszcze poprzedniego kanału. Możesz też po prostu wykorzystać przerwania timera, a nie czekać na wynik. Możesz też samplowanie ADC przenieść do pętli głównej, możliwości jest wiele. Ale zacznij po kolei, np. od obsługi triaka, jak ta część ruszy to zajmij się następną.

    Dodano po 5 [minuty]:

    A propos schematu - masz kosmicznie skomplikowaną detekcję zera. Do tego wystarczą dwa rezystory i transoptor z diodą dwukierunkową. Poza tym jeśli układ ma sterować tylko wentylatorem, to może w ogóle wywalić trafo i całość zasilić korzystając z reaktancji kondensatora? Kilkanaście mA w ten sposób wyciągniesz, co jest wystarczające. Triaka przełącz na wyjście OC procesora, żeby móc korzystać sprzętowo z timera.
  • #9 11014371
    PJimi
    Poziom 13  
    ad.1. : Nie znałem takiej opcji Timera, ale z tego co piszesz brzmi zachęcająco. Doczytam w nocie, zmienię kod i przedstawię na forum. Rozumiem, że w ten sposób impuls będzie generowany od razu automatycznie po przepełnieniu timera nie "manualnie" w przerwaniu.

    ad. 2 : Nie do końca rozumiem o co chodzi z tym, że "Musisz wtedy pamiętać, że wartość tuż po zmianie MUX będzie dotyczyła jeszcze poprzedniego kanału." Ale generalnie póki co mam takie podejście jak wspomniałeś - najpierw uruchomię obsługę triaka a dopiero potem zajmę się peryferiami.

    Odnośnie schematu:

    Tak, wiem, że detekcja zera jest u mnie dość skomplikowana. Widywałem też schematy na elektrodzie, na których było to zrealizowane dużo prościej (zresztą podobnie jak napisałeś) - być może koniec końcem zdecyduje się właśnie na prostsze rozwiązanie. Wiem, tylko, że moja detekcja choć skomplikowana to podobno bardzo dokładna. Możliwe jednak, ze takiej dokładności nie potrzebuje i że wystarczy mi taka jak z proponowanego przez Ciebie układu.
    Jak przeprogramuje Timer na pewno przełączę sterowanie triaka na wyjście OC procesora.
    Nie wiem do końca o czym mówisz wspominając o zasilaniu z reaktancji kondensatora, ale wersja z trafem zapewnia mi przede wszystkim izolację galwaniczną od napięcia sieci oraz wyjście +12VDC dostępne dla użytkownika, na którym mi zależy. Układ będzie bowiem sterowany np. napięciem 0-10VDC, które może być podawane zadajnikiem wymagającym takiego właśnie zasilania.


    Co do "Poza tym ADC*146 powoduje przekroczenie zakresu int - więc te obliczenia musisz zrealizować inaczej."
    146/1023 zamieniam na 0,143 - powinno być ok.
    I tak jest to rozwiązanie tymczasowe. W praktyce równomierny wzrost liczby impulsów nie będzie powodował liniowej zmiany mocy ze względu na sinusoidalny kształt przebiegu kluczowanego. Należałoby całkować sinusa od zera do pi aby wyznaczyć kolejne wartości timera w celu zapewnienia liniowej charakterystyki. Mam taki program (wygrzebany na forum), który dla konkretnej wartości zegara, prescalera i doboru dzielnika wylicza ile impulsów powinno odpowiadać konkretnemu procentowi mocy maksymalnej (program w załączniku). Moje ustawienia to 1MHz, dzielnik 64 i Timer0. Docelowo chcę umieścić w programie jakąś macierz, z której dla konkretnej procentowej wartości mocy program będzie pobierał ilość impulsów do timera.

    PS - jestem pod sporym wrażeniem chęci pomocy na tym forum ludziom, którzy mówiąc krótko "nie śmigają w programowaniu" :p Mam nadzieję, że się szybko nie znudzicie moim problemem i będę mógł doprowadzić temat do końca. Dzięki :)
  • Pomocny post
    #10 11014764
    tmf
    VIP Zasłużony dla elektroda
    Zauważ, że zapis: TCNT0 = 109+((ADC*146)/1023); jest cały wyliczny na zmiennych typu int. Stąd też kompilator nie wylicza 146/1023 lecz najpierw mnoży *146, a potem dzieli przez 1023. W efekcie masz przepełnienie po mnożeniu i nieprawidłowy wynik.
  • #11 11016938
    PJimi
    Poziom 13  
    Wstawiam kod zmodyfikowany wg Waszych wskazówek. Proszę o wytkniecie błędów :)

    Modyfikacje:
    1. Uruchomienie konwersji ADC w trybie free-running i przeniesienie do pętli głównej.
    2. Wyrzucenie przerwania od przepełnienia Timera0.
    3. Zastosowanie sprzętowego wymuszenia zmiany stanu na pinie OC2 w przerwaniu od detektora zera.
    Wartość ładowaną do OCR2 biorę dzieląc max wskazanie ADC na 7, gdyż program liczący ilości impulsów (załączony wyżej) dla takich ustawień Timera0 wyliczył 146 imp dla min mocy. Wobec czego 1023/146=7. Nie wiem czy to dobre rozumowanie tym bardziej, ze nie będzie to liczba całkowita i impulsy są przecież niepodzielne. Zresztą docelowo do OCR2 będzie ładowana wartość z tablicy
    4. Zamiana funkcji SIGNAL sa ISR w przerwaniu od detektora zera.



    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #12 11017014
    LordBlick
    VIP Zasłużony dla elektroda
    PJimi napisał:
    Proszę o wytkniecie błędów
    1. Jak się ten program sprawuje w realnym świecie ?
    2. Dlaczego F_CPU jest w tym pliku, a nie w Makefile ?
    PJimi napisał:
    Uruchomienie konwersji ADC w trybie free-running i przeniesienie do pętli głównej
    Pętla główna
    Kod: text
    Zaloguj się, aby zobaczyć kod
    jest pusta, free-runnig tego nie wymaga. ;)
    3. Po co za każdym wystąpieniem INT0 wpisujesz do TCCR2 to samo ? Tu tylko wpisuj do TCNT2 zero, a ten setup wywal tam gdzie jego miejsce, czyli przed pętlę główną.
    4. Brak przerwania TIMER2 COMP w którym ustala się czas trwania impulsu wyzwalającego timer i w drugim kroku od razu wychodzi (koniec impulsu).
  • #13 11017118
    PJimi
    Poziom 13  
    1. Program oczywiście testowałem w realnym świecie, ale wczoraj. Tzn testowałem wersję, o której od Was teraz wiem, że nie miała prawa działać poprawnie :) Jutro będę mógł przeprowadzić kolejne testy na ulepszonym już kodzie.

    2. F_CPU jest w kodzie a nie w Makefile bo tak widziałem w jakichś przykładach. Zerknę gdzie to ustawić w Makefile i zmienię. A swoją drogą - czy nie definiowanie zegara 1MHz jest błędem? Czy może wartość zegara nie jest domyślnie ustawiona na 1MHz?

    3. Faktycznie - chyba nie potrzebnie w każdym INT0 wpisuje do TCCR2 wszystko. Setup (rozumiem, że ustawienia) wyrzuciłem przed pętlę główną.
    Wpisałem TCNT2=0 ale teraz wywala mi błąd. Chyba coś nie tak wpisałem. Rozumiem, że zerowanie TCNT2 automatycznie startuje timer zliczający do OCR2, tak?

    4. Tego punktu nie do końca rozumiem. Musze doczytać, ale wytłumacz proszę.

    Rzeczywiście - ADC nie jest w pętli głównej :p Co masz na myśli mówiąc, że "Pętla główna jest pusta, free-runnig tego nie wymaga." ? Chodzi o to, że raz zapuszczone free-running jeszcze przed pętlą chodzi cały czas i dlatego nie muszę umieszczać tej instrukcji w pętli głównej, tak?

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #14 11017161
    LordBlick
    VIP Zasłużony dla elektroda
    PJimi napisał:
    2. F_CPU jest w kodzie a nie w Makefile bo tak widziałem w jakichś przykładach. Zerknę gdzie to ustawić w Makefile i zmienię. A swoją drogą - czy nie definiowanie zegara 1MHz jest błędem? Czy może wartość zegara nie jest domyślnie ustawiona na 1MHz?
    Fabryka ustawia 1MHz, ale to Ty powinieneś się upewnić, czy tak jest w danym egzemplarzu, wrzucając jakiś testowy program .
    PJimi napisał:
    4. Tego punktu nie do końca rozumiem. Musze doczytać, ale wytłumacz proszę.
    Skoro sterujesz fazowo triak, to wyzwala się go impulsem. Impuls ma swój początek i koniec. Oba zdarzenia trzeba wygenerować. Najlepiej w obsłudze przerwania od licznika, chyba, ze w danym trybie pracy licznik sam z siebie zapewnia pożądany przebieg. Mój stan wiedzy wskazuje na konieczność obsługi przerwaniem - raz włączenie i ustawienie kolejnej wartości licznika dla wyłączenia, dwa - wyłączenie, tak, aby triak był wyłączony przy kolejnym przejściu przez zero.
    Tak w sumie to czego moc chcesz regulować ? Grzałka ? Jeśli tak, to w chodzi w rachubę jeszcze sterowanie grupowe.
    PJimi napisał:
    Chodzi o to, że raz zapuszczone free-running jeszcze przed pętlą chodzi cały czas i dlatego nie muszę umieszczać tej instrukcji w pętli głównej, tak?
    Tak.
  • #15 11017236
    PJimi
    Poziom 13  
    Jeszcze zmodyfikowałem program:

    1. Dodałem (nie wypełnioną jeszcze do końca wartościami ilości impulsów tabele)
    2. Nowe obliczenia co do zmiennej uzależnionej od ADC i ładowanej do OCR2. Nie wiem czy dobrze przywołuję dane z tabeli ?

    Pozostałe sprawy bez zmian...


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dodano po 13 [minuty]:

    Miałem taki przypadek, że Atmega8 była fabrycznie ustawiona na inne taktowanie niż 1MHz. Dziwiłem się czemu czasy z jakimi migają diody są inne od tych jakie wydawało mi się, że ustawiłem w programie.

    Co do wyłączania impulsu aby wyłączyć triak - a to nie jest tak czasem, że triak sam się wyłączy przy przejściu przez zero?
    Rozumiem natomiast, że trzeba zakończyć impuls żeby móc go potem rozpocząć jeszcze raz. Nie wiem natomiast jak to zrealizować. Z tego co rozumiem to w momencie zrównania licznika i OCR2 na pinie pojawia się impuls i potem już nie znika, tak? Jak go w takim razie wyłączyć? Jakieś sugestie? Znalazłem w nocie że ustawia się jeszcze chyba jakąś wartość MAX, która potem wyłącza impuls. Z tym, że co jeśli przed wyłączeniem nastąpi już kolejne zero z sieci? Licznik powinien znowu zacząć zliczać a on będzie czekał aż osiągnie wartość max, żeby zakończyć impuls. Chyba, że się mylę i szukam dziury w całym... brak mi wiedzy :/

    Sterować będę wentylatorem więc prostsze do zrealizowania sterowanie grupowe odpada. Testowałem do sterowania wentylatora wspomniany wyżej kit realizujący m.in. sterowanie grupowe - efekt był taki że wiatrakiem strasznie szarpało. Grupowe natomiast na pewno nadaje się do grzałek - jest tak jak mówiłem prostsze do zrealizowania i nie generuje takich zakłóceń do sieci (zwłaszcza harmonicznych)


    Skoro sugerujecie, że układ detekcji zera to przerost formy nad treścią może lepiej zastosować taki układ jak z załącznika (kit AVT861-1)?
    Zmieniłem schemat: dałem inny detektor zera + przepiąłem pin dający impuls na triaka na OC2. Tyle tylko, że jest to tez pin MOSI do programowania ISP. Nie muszę tam dać czasem jakiejś zworki, którą trzeba będzie przekładać przed i po programowaniu? (nowy schemat w załączniku regulator.pdf)
  • #16 11029489
    LordBlick
    VIP Zasłużony dla elektroda
    PJimi napisał:
    Z tego co rozumiem to w momencie zrównania licznika i OCR2 na pinie pojawia się impuls
    To niefortunne określenie. Pojawia się zmiana stanu. Jednocześnie można skorzystać z przerwania, aby ustawić odmierzenie czasu do zmiany stanu z powrotem. Potem w przerwaniu od przejścia przez zero zerujemy licznik i ustawiamy zabawki od nowa.
REKLAMA