Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATMEGA8][avr-gcc] - Różne poziomy jasności diody LED -PWM

mnowator 03 Wrz 2012 22:41 3306 12
  • #1 03 Wrz 2012 22:41
    mnowator
    Poziom 7  

    Proszę na przyszłość używać tagu [syntax=C] do wklejania kodu...[/syntax].
    Ponadto proszę się zapoznać z zasadami korzystania z działu:
    https://www.elektroda.pl/rtvforum/topic349089.html
    Poprawiłem, LordBlick


    Witam.

    Otóż zrobiłem sobie proty układ z diodą LED i dwoma przyciskami do regulacji jej jasności. Postanowiłem użyć PWM. Instruując się przykładami udało mi się osiągnąć cel. Jednak nurtuje mnie jedna sprawa.

    Oto kod programu

    Kod: C
    Zaloguj się, aby zobaczyć kod


    Po wgraniu programu, mogę zmieniać poziom jasności ale mam ich tylko 5 a nie 10 jak sam wnioskuje po kodzie. Mógłby mi ktoś wyjaśnić czemu tak się dzieje ? Z góry dziękuje.

    0 12
  • #2 03 Wrz 2012 23:31
    dondu
    Moderator Mikrokontrolery Projektowanie

    Jaki według Ciebie tryb pracy ustawiłeś?
    Gdy już to ustalisz sprawdź jaka jest wartość TOP dla tego trybu.

    Poza tym nie masz zabezpieczeń w programie dla przekroczenia nastaw za pomocą przycisków. Rozumie, że to na razie tylko wersja testowa.

    0
  • #3 01 Sie 2017 13:22
    DRAZEK87
    Poziom 12  

    witam postanowiłem kolejny raz przećwiczyć PWM i nawiązując do tematu o to napisany prze zemnie kod na świecenie diodą sterowaną za pomocą dwóch klawiszy; sprawdzałem działa, po resecie dioda świeci na 50% wypełnienia a następnie można je regulować dodając lub odejmując; ewentualnie osoby które lepiej są zapoznane w temacie niech się wypowiedzą co wypadało by zmienić aby kod by bardziej czytelny ewentualnie zaproponujcie inny kawałek kodu na sprawdzanie klawiszy, ich sterowanie ja akurat tak to sobie wymyśliłem na szybko; pozdrawiam

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #4 01 Sie 2017 14:41
    dondu
    Moderator Mikrokontrolery Projektowanie

    Każdy program można napisać na wiele sposobów.
    W Twoim przypadku:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    należałoby wykonywać tylko wtedy, gdy i ulega zmianie, a nie za każdym obiegiem pętli głównej.
    Poza tym, zmienna "i" właściwie nie jest potrzebna, gdyż możesz operować od razu na OCR1A.

    Niemniej jednak warto byłoby zrobić to na przerwaniach timera1 (skoro go używasz) wraz z eliminacją drgań styków.

    Przy okazji zapoznaj się z: http://mikrokontrolery.blogspot.com/2011/03/epp-rozgrzewka.html

    0
  • #5 01 Sie 2017 22:57
    DRAZEK87
    Poziom 12  

    ... zgadza sie "Sparrowhawk", sprawdzałem na oscyloskopie i przy UP mamy 1 przy DOWN 0...
    co do wypowiedzi "dondu" widziałem już wcześniej powyższy link i faktycznie aby to było poprawnie wykonane wypadało by sterować tę diodę uwzględniając korekcję jasności... zajmę się tym i poćwiczę... a co w przypadku jeśli chciałbym sterować diodę nie za pomocą klawiszy lecz potencjometrem... ale żeby sobie utrudnić potencjometrem od testera serw gdzie impulsy są generowane od 1 do 2ms co okres 20ms z częstotliwością 50Hz... np załózmy że sygnał bedę zapodawał na pin PD2...domyślam się że należało by zliczać ich długośc oraz wartość przełożyć ze 1ms to 0% wypełnienia; 1,5ms to 50%; zaś 2ms to 100%...czy dobrze kombinuję? zakładając że pierwszy timer wykorzystałem na regulacje jasności diody to kolejny drugi muszę poświęcić na odczyt szerokości impulsu czy też mozna, a nawet trzeba to zrobić na wspólnym.....
    biorąc timer2 8bit nie do konca wiem czy lepiej w przerwaniu inkrementować jakąś zmienna która co przerwanie wzrasta o jeden, a następnie w pętli głównej ją obrabiać jesli tak to jak? czy też wszystko ma byc wykonywane w przerwaniu, a wowczas co w petli głównej?
    biorąc pod uwagę pierwszy warunek mozna by było ustawic przerwanie co 10us poprzez preskaler 8 i i tryb ctc wpisywać do rejestru OCR2 = 10 ,czy dobrze przeliczam nastepnie stworzyć zmienna volatile np "licznik" i przerwaniu go inkrementowac zakładając ze 100 takich impulsów to 1ms... a w pętli głównej obliczenia....czy też lepszym sposobem jest wykorzystanie w przerwaniu zboczy narastajacych czy opadajacych? jak wygląda poprawnie takie przerwanie od zliczania szerokości impulsu, aby nie zamulać procka?

    0
  • #7 02 Sie 2017 11:11
    squelch
    Poziom 11  

    Cytat:

    a w pętli głównej obliczenia....czy też lepszym sposobem jest wykorzystanie w przerwaniu zboczy narastajacych czy opadajacych? jak wygląda poprawnie takie przerwanie od zliczania szerokości impulsu, aby nie zamulać procka?


    Jak masz jakieś przerwanie co występuje np co 1ms to wykonanie przez program tego przerwania trochę zabiera czas bo sprawdzamy czy np. zmienna ma tyle a tyle. Według mnie jak jakiś impuls może nadejść w bliżej nieokreślonym czasie np. za 1h czy dłużej to po co zabierać czas na wykonanie main co 1ms albo gorzej co 1us po prostu ustawiamy reakcję na zboczę i wtedy najmniej zamulamy procek.


    Pozdrawiam

    0
  • #8 24 Lut 2018 19:00
    DRAZEK87
    Poziom 12  

    nawiązując do powyższych wypowiedzi, postanowiłem kontynuować temat;
    lecz tym razem wesprze się prostym schematem przedstawiającym sposób w jaki są podłączone trzy diody
    [ATMEGA8][avr-gcc] - Różne poziomy jasności diody LED -PWM
    i wcześniej nadmieniony tester serw;
    [ATMEGA8][avr-gcc] - Różne poziomy jasności diody LED -PWM
    do analizy zagadnienia wykorzystam już gotową z innego projektu płytkę drukowana "na pokładzie" której jest umieszczony procesor Atmega88pa-au w obudowie TQFP32 oraz rząd kilkunastu diód w przypadku tego planu wykorzystam tylko trzy; za to ich sposób świecenia jest następujący; w zależności od położenia potencjometru zaświeca się konkretna dioda; czyli w pozycji:
    0 >> LED1 sygnał PWM generowany przez tester 1ms;

    2,25 >> LED1 oraz 2 >> 1,25ms;

    4,5 >> LED2 >> 1,5ms;

    6,75 >> LED2 oraz 3 >> 1,75ms;

    9 >> LED3 >> 2ms;

    pomożecie ? kod w C, środowisko eclipse; zegar max 8MHz zewnętrzny lub wewnętrzny jaki daje producent do wyboru...interesują mnie jak powinno poprawnie wyglądać zewnętrzne przerwanie INT1 wyzwalane na zbocze narastające oraz przerwanie timera do odliczania czasu... chętnie przeanalizuje każdą podpowiedz...

    0
  • #9 25 Lut 2018 12:00
    ex-or
    Poziom 18  

    DRAZEK87 napisał:
    nawiązując do powyższych wypowiedzi, postanowiłem kontynuować temat

    Bardzo szeroko rozumiana ta "kontynuacja"

    Najbardziej oczywiste bylo by wykorzystanie wejścia ICP wtedy Timer1 i przerwanie od ICP wykonuje całość roboty i dodatkowo można skorzystać z filtru zakłóceń przebiegu wejściowego. Ale w podanej konfiguracji też się da. Ogólny schemat:
    1. Skonfigurować którykolwiek timer tak by czas przepełnienia był nieco dłuższy niż 2ms. Timer pracuje sobie cały czas.
    2. Skonfigurować przerwanie INT1 na odpowiednie zbocze: rosnące jeśli impulsy są dodatnie lub opadające w przeciwnym wypadku
    3. W procedurze obsługi przerwania INT1 zrobić dwustanowy automat, niech to będą stany IDLE i RUN
    3a. Stan IDLE oczekuje na wystąpienie zbocza początkowego, po wystąpieniu zbocza procedura obsługi przerwania
    - notuje stan licznika timera w statycznej zmiennej lokalnej,
    - resetuje flagę przepełnienia timera,
    - zmienia swoją konfigurację na zbocze przeciwne
    - przechodzi do stanu RUN
    3b. Stan RUN oczekuje na wystąpienie drugiego zbocza, po jego wystąpieniu procedura obsługi przerwania:
    - odczytuje stan licznika timera i wylicza długość impulsu przez odjęcie wartości licznika zachowanej w p. 3a, jeśli flaga przepełnienia licznika jest ustawiona wynik należy odpowiednio skorygować,
    -zmienia konfigurację na zbocze przeciwne
    -przechodzi do stanu IDLE
    -zapala odpowiednie diody przez zapodanie na port diod odpowiedniej maski bitowej

    Wszystko, za wyjątkiem początkowych konfiguracji odbywa się w przerwaniach.

    1
  • #10 25 Lut 2018 14:40
    DRAZEK87
    Poziom 12  

    EX-OR super! jesteś inspiracja do dalszych badan nad projektem który wiem utkwił gdzieś z braku czasu ale dzięki Wam to i ja się czegoś nauczę programować ...do setna;

    zagadnienie pierwsze schematu wyliczyłem następująco; na wstępie przyjąłem równe 2ms czyli to 0,002s więc przerwanie musiało by nastąpić z częstotliwością 500Hz (1/0,002s=500); przyjmując taktowanie zegara 8 MHz i timer0 8-bit'owy najbliższy mi preskaler to 64 który daje ~488 sygnałów w czasie 1 sekundy (8000000/64/256=488,28125) więc 1/488=0,002049s =2,049ms i tu pada pytanie czy taki czas jest wystarczający w końcu nieco dłuższy od pełnych 2ms :P

    zagadnienie drugie przerwanie INT1 ustawione na zbocze narastające ze względu na sygnał dodatni z testera (sprawdzałem na oscyloskopie);

    po tych zabiegach, określeniu pinów, kierunków kod wygląda następująco czy dotychczas jest napisane poprawnie?

    przerwanie INT1 widać że działa bo dotykając pinPD3 zapala się testowo dioda pierwsza; proszę o ocenę i myślimy dalej

    Code:

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/pgmspace.h>
    #include <avr/eeprom.h>
    #include <avr/interrupt.h>

    #define LED_PIN_1 (1<<PB0)            // dioda sygnalizująca 1
    #define LED_OFF_1 PORTB &= ~LED_PIN_1   // makrodefinicja – wyłączenie diody
    #define LED_ON_1 PORTB |= LED_PIN_1      // makrodefinicja – załączenie diody
    #define LED_TOG_1 PORTB ^= LED_PIN_1   // makrodefinicja – zmiana stanu diody

    #define LED_PIN_2 (1<<PB1)            // dioda sygnalizująca 2
    #define LED_OFF_2 PORTB &= ~LED_PIN_2   // makrodefinicja – wyłączenie diody
    #define LED_ON_2 PORTB |= LED_PIN_2      // makrodefinicja – załączenie diody
    #define LED_TOG_2 PORTB ^= LED_PIN_2   // makrodefinicja – zmiana stanu diody

    #define LED_PIN_3 (1<<PB2)            // dioda sygnalizująca 3
    #define LED_OFF_3 PORTB &= ~LED_PIN_3   // makrodefinicja – wyłączenie diody
    #define LED_ON_3 PORTB |= LED_PIN_3      // makrodefinicja – załączenie diody
    #define LED_TOG_3 PORTB ^= LED_PIN_3   // makrodefinicja – zmiana stanu diody


    #define PWM_IN (1<<PD3)             //przypisanie wejscia PWM do portu PD3

    volatile uint8_t licznik=0;            //zmienna timera


    int main(void)
    {

       DDRB |= LED_PIN_1;      // kierunek wyjściowy
       DDRB |= LED_PIN_2;      // kierunek wyjściowy
       DDRB |= LED_PIN_3;      // kierunek wyjściowy

       DDRD &= ~PWM_IN;      // kierunek pinu PD3 – wejściowy

       TCCR0B |= (1<<CS01) | (1<<CS00); // preskaler 64
    TIMSK0 |= (1<<TOIE0); // przepełnienie timera

       EICRA |= 1<<ISC11 | 1<<ISC10; // zbocze narastające
       EIMSK |= 1<<INT1;

    sei();

    while (1)
    {

    }
    }


    ISR(INT1_vect)
    {LED_ON_1;
    }

    ISR(TIMER0_OVF_vect){
       licznik++;
    }



    a i na koniec "dwustanowy automat" co to jest? czy chodzi o to:
    Code:

    enum state {idle, run};
    enum state stan = idle;

    ISR(INT1_vect){
    if (stan == idle)
    {
    /* ... */
    }
    if (stan == run){
        /* ... */
    }
    }

    czy też bardziej z skorzystania z instrukcji wyboru typu "switch" która ma postać:
    Code:

    switch(wyrażenie)
    {
    case wyrażenie_stałe_1:
    /* Instrukcje - wariant 1*/
    break;

    case wyrażenie_stałe_2:
    /* Instrukcje - wariant 2 */
    break;

    case wyrażenie_stałe_3:
    /* Instrukcje - wariant 3 */
    break;
    ....................
    case wyrażenie_stałe_n:
    /* Instrukcje - wariant n */
    break;

    default:
    /* Instrukcje - jeśli żaden z wcześniejszych wariantów */
    }

    0
  • #11 01 Mar 2018 21:49
    DRAZEK87
    Poziom 12  

    ex-or napisał:
    jeśli flaga przepełnienia licznika jest ustawiona wynik należy odpowiednio skorygować


    nio właśnie ale jak ... bo prawdopodobnie na tym etapie się wyłożyłem :/ gdyż przy maksymalnym wychyleniu potencjometru tuż przed końcem zakresu zapala się led1 gasząc diodę 3 :P

    ale mimo tego małymi krokami udało się uruchomić timer, przerwanie INT1 wyzwalane zboczem narastającym z przejściem na opadające; zastosować sprawdzające stan komendy: idle/run, a wygląda to następująco:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #12 02 Mar 2018 18:13
    ex-or
    Poziom 18  

    Bardzo dobrze.
    Kilka uwag:

    DRAZEK87 napisał:
    2,049ms i tu pada pytanie czy taki czas jest wystarczający w końcu nieco dłuższy od pełnych 2ms

    Idea jest taka że licznik ma się przekręcić co najwyżej raz w czasie impulsu o najdłuższym możliwym czasie trwania. 2.049 ms teoretycznie powinno wystarczyć nawet biorąc pod uwagę fakt, żę wewnętrzny oscylator jest fabrycznie skalibrowany z kilkuprocentową dokładnością.
    No to teraz o fladze przepełnienia i korekcie wyniku. Dajmy na to że zbocze narastające wystąpiło przy TCNT==250, impuls trwał tak długo, że wystąpiło przekręcenie  licznika i zbocze opadające wystąpiło przy wartości licznika TCNT==120. Odejmujemy liczbę pierwszą od drugiej i otrzymujemy -130, trzeba to skorygować przez dodanie "pojemności" licznika timera czyli 256 i w ten sposób otrzymujemy że długość impulsu to 126 tików licznika. Inny przypadek: ta sama długość impulsu ale zbocze narastające wystąpiło przy TCNT==90, a więc zbocze opadające wystąpi przy TCNT==216, pomiędzy odczytami licznika nie wystąpiło przepełnienie, wyniku nie trzeba korygować.
    Sugerowałem wcześniej, żeby do wykrywania przepełnienia wykorzystać flagę TOV, ale to nie jest dobry pomysł ponieważ pomiędzy odczytem stanu rejestru TCNT a testem flagi może wystąpić przepełnienie, zafałszowując wynik. W tej chwili lepszym rozwiązaniem wydaje mi się sprawdzanie czy wartość licznika przy pierwszym zboczu była większa czy mniejsza od jego wartości przy drugim zboczu. Korekty trzeba dokonać w pierwszym przypadku.
    Alternatywnym (i chyba najlepszym) sposobem jest zerowanie licznika oraz preskalera timera w momencie wystąpienia zbocza narastającego. Wtedy przy zboczu opadającym otrzymuje się już gotową wartość bez potrzeby przeprowadzania jakichkolwiek działań matematycznych.

    Switch czy if? W tym przypadku to nie ma znaczenia, kompilator prawdopodobnie skompiluje obie wersje identycznie.

    Taką drabinkę ifów...
    Kod: c
    Zaloguj się, aby zobaczyć kod

    ...lepiej zrobić jako if....else if.... wtedy sprawdzanie skończy się na pierwszym spełnionym warunku. W konstrukcji powyższej sprawdzane będą wszystkie instrukcje (oprócz tego są chyba błędne)

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #13 02 Mar 2018 20:10
    DRAZEK87
    Poziom 12  

    Teraz rozumiem w czym tkwi problem i faktycznie w wariancie A) dochodzi do przepełnienia licznika i z czytany impuls będzie błędnie interpretowany, a dla wizualnego wglądu narysowałem to tak:
    [ATMEGA8][avr-gcc] - Różne poziomy jasności diody LED -PWM

    ex-or napisał:
    Alternatywnym (i chyba najlepszym) sposobem jest zerowanie licznika oraz preskalera timera w momencie wystąpienia zbocza narastającego. Wtedy przy zboczu opadającym otrzymuje się już gotową wartość bez potrzeby przeprowadzania jakichkolwiek działań matematycznych.

    Ok zastosuje się do powyższych zaleceń i zobaczymy co z tego wyjdzie :P poprawie też if'y ...

    0