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

[C] Sterowanie częstotliwością migania diody przyciskami.

title 10 Maj 2015 12:50 1212 8
  • #1 10 Maj 2015 12:50
    title
    Poziom 9  

    Cześć,
    staram się napisać program który, po naciśnięciu 1 przycisku włącza diodę, która zaczyna migać, naciśnięcie 2 przycisku przyspiesza miganie diody, naciśnięcie 3 przycisku zwalnia miganie diody. Ponowne naciśnięcie 1 przycisku wraca do początkowej częstotliwości migania.

    Oraz program działający identycznie, zrealizowany na 1 przycisku (4 fazy), 1 włączenie, 2 przyspieszenie, 3 zwolnienie, 4 powrót do początkowej częstotliwości.

    Dioda podłączona anodą do portu PORTB 0x02
    Przyciski podłączone do portu PORTD 0x02, PORTD 0x04 i PORTD 0x08 zwarte do masy.

    Uc to Atmega8.

    Początek programu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dalej nie wiem jak to ugryźć. Proszę o pomoc.

    0 8
  • #2 10 Maj 2015 12:55
    p.kaczmarek2
    Poziom 23  
  • #3 11 Maj 2015 12:52
    BlueDraco
    Specjalista - Mikrokontrolery

    Zacząć od przerwania timera... Cały kod w C to po 2 linie kodu na wykrycie naciśnięcia każdego przycisku przerwania, 2..4 linie do sterowania diodą i z 8 linii inicjowania w main().

    0
  • #4 11 Maj 2015 17:16
    title
    Poziom 9  

    Nie mam pojęcia o czym piszecie, jako osoba początkująca znam funkcje if oraz switch i to tak wyłącznie poglądowo z poradników.

    Miałem pomysł, aby zrobić to w ten sposób, ale nadal nie spełnia swojej funkcji:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #5 11 Maj 2015 20:18
    dondu
    Moderator Mikrokontrolery Projektowanie

    title napisał:
    Nie mam pojęcia o czym piszecie, ...

    Skoro nie masz pojęcia, to kolejne materiały do nauki: http://mikrokontrolery.blogspot.com/2011/03/drzaskowy-pamietnik-wstep.html

    Odnośnie _delay_ms(t): http://mikrokontrolery.blogspot.com/2011/04/gcc-avr-funkcje-opoznienia-delay.html

    To Twój program po poprawnym formatowaniu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Czy na pewno tak chciałeś go napisać?
    Komentuj każdą linię kodu, byśmy wiedzieli co chcesz osiągnąć. W ten sposób także sam szybciej wyłapiesz swoje błędy.

    0
  • #6 30 Maj 2015 12:21
    title
    Poziom 9  

    Nadal nie wiem jak to zrobić.

    Mój algorytm myślenia:

    1) program oczekuję na przycisk 1/2/3/4
    2) sprawdza czy przycisk jest wciśnięty, jeśli nie przechodzi do sprawdzania kolejnego...
    3) po wykryciu zmiany stanu przycisku, przechodzi do przypisanego mu podprogramu, który wykonuję się w pętli do czasu pojawienia się zmiany stanu innego przycisku

    Drugi program:

    taka sama zasada działania tyle, że program zapamiętuję ilość zmian stanu przycisku:

    1 = podprogram 1
    1 + 1 = podprogram 2
    .
    .
    .

    0
  • #7 31 Maj 2015 11:52
    dondu
    Moderator Mikrokontrolery Projektowanie

    title napisał:
    2) ... jeśli nie przechodzi do sprawdzania kolejnego....

    Jeśli masz prawidłowo podłączone przyciski bezpośrednio do pinu mikrokontrolera, to tak Twój program nie działa. Działa dokładnie odwrotnie. Dlatego też prawidłowo sformatowałem Twój kod, byś sam to zobaczył.

    Wskazałem Ci kurs AVR, przerób więc znajdujące się w nim artykuły w szczególności dot. użycia przycisków i timerów, i wtedy dopiero powinieneś zabrać się za swój projekt, bo bez podstaw trudno będzie Ci rozwiązać problem tym bardziej, że to co chcesz zrobić można rozwiązać na tysiące sposobów.

    0
  • #8 07 Cze 2015 10:44
    title
    Poziom 9  

    Kod: csharp
    Zaloguj się, aby zobaczyć kod





    Poczytałem o timerach z poradnika, który już czytałem wcześniej ale od samego czytania wiedzy nie przybyło.

    Analizując powyższy kod natykam się na niejasności i rozwiązania, które chce dostosować do siebie.

    //definicja początkowej wartości timera
    #define timer_start 6

    Rozumiem, że zależnie jaką wartość wpiszę timer będzie liczył od tej wartości tutaj od 6 do 255? czy definicja "timer_start" jest zawsze tak zapisana?

    //zmienna pomocnicza-licznik używana w przerwaniu
    volatile uint8_t cnt=0;

    Czym jest ta linijka, jak to rozumieć, czym jest volatile czym uint8_t czym cnt i dlaczego =0?

    //########### I/O ###########
    DDRB |= (1<<LED1) | (1<<LED2); //Ustawienie pinów sterujących diodami
    // jako wyjścia

    Początek programu potrafię napisać jednak wolę to zapisywać szesnastkowo.
    Jak zamienić tą linijkę?

    DDRB = 0x01 | 0x02 (w tym przypadku bez definiowania LED1 i LED2) ?

    //######## konfiguracja timera ##############
    TIMSK |= (1<<TOIE0); //Przerwanie overflow (przepełnienie timera)
    TCCR0 |= (1<<CS02) | (1<<CS00); // źródłem CLK, preskaler 1024
    TCNT0 = timer_start;// //Początkowa wartość licznika

    Takie samo pytanie o przekształcenie jak powyżej.

    TIMSK |= (1<<TOIE0) oznacza włączenie przerwania od przepełnienia Timer0, zawsze zapisywana w taki sposób?

    TCCR0 |= (1<<CS02) | (1<<CS00) mój preskaler 8, zostawiam taką samą wartość CS02 i CS00 dlaczego nie ma CS01

    Czyli wybieram Timer0 jest on 8-bitowy

    Za pomocą fusebitów ustawiłem wewnętrzny generator na 8 MHz czyli jest to sygnał click/o.

    8 MHz/8 = 1 MHz

    Jeden impuls trwa:

    1/ f = t
    1/ 1 000 000 Hz = 0,000001 s = 1 us

    Timer0 generuje przerwanie w przypadku przepełnienia:

    256 * 1 us = 256 us


    sei(); //Globalne uruchomienie przerwań

    Jak zostało to opisane: "Zmienne globalne, to zmienne dostępne w dowolnym miejscu Twojego programu. "

    Przykład pokazywał:

    char ilosc_koni = 5;

    Tutaj mamy:

    sei(); dlaczego użyto sei i nie ma nic w nawiasach?

    //############ Procedura obsługi przerwania od przepełnienia timera ############
    ISR(TIMER0_OVF_vect)

    Do czego służy ta linijka?

    cnt++; //zwiększa zmienną licznik
    if(cnt>3) //jeśli 4 przerwania (czyli ok 1 s)

    Jak działa cnt++, rozumiem, zę odnosi się do cnt=0 użytej na początku programu?

    Rozumiem, że dopiero tutaj ustawiamy timer, czyli 4 przerwania po ok 250 ms co daje 1 s i następuje zmiana stanu?

    Przerwanie to sygnał przerywający program.

    -przerywa program -> przechodzi do obsługi przerwania -> powraca do przerwanego programu.

    Jak to zatem działa?

    250ms + 250ms + 250ms +250ms -> zmiana stanu -> 250ms + 250ms + 250ms +250ms -> zmiana stanu....

    Czy 250ms trwa od 6 do 255 i kolejne liczenie (łącznie 4 cykle) czy podczas tego liczenia 6-255 odbywają się 4 przerwania?

    Jak zatem ustawić zmienne w różnych odstępach czasu, np. 2s; 4s; 2s; 4s... ?

    Pozdrawiam.

    0
  • #9 07 Cze 2015 16:50
    dondu
    Moderator Mikrokontrolery Projektowanie

    title napisał:
    //definicja początkowej wartości timera
    #define timer_start 6

    Rozumiem, że zależnie jaką wartość wpiszę timer będzie liczył od tej wartości tutaj od 6 do 255? czy definicja "timer_start" jest zawsze tak zapisana?

    etykiecie timer_start przypisano na stałe liczbę. W zależności gdzie tę etykietę użyjesz, będzie ona miała wartość 6. Jeśli więc używamy ją w tym miejscu:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    czyli przypisania wartośći do licznika timer0, to już wiesz co ta linia programu wykonuje.
    Jeśli ta linia jest w funkcji przerwania, to znaczy że wykona się po każdym przerwaniu.


    title napisał:
    //zmienna pomocnicza-licznik używana w przerwaniu
    volatile uint8_t cnt=0;

    Czym jest ta linijka, jak to rozumieć, czym jest volatile czym uint8_t czym cnt i dlaczego =0?

    Jak działa cnt++, rozumiem, zę odnosi się do cnt=0 użytej na początku programu?

    Musisz poznać podstawy programowania w języku C: http://mikrokontrolery.blogspot.com/2011/02/kurs-jezyka-c-spis-tresci.html
    a volatile: http://mikrokontrolery.blogspot.com/2011/02/kurs-jezyka-c-spis-tresci.html

    cnt to nazwa zmiennej.
    uint8_t to typ zmiennej całkowitej (8 bitów czyli char) bez znaku, czyli unsigned char.



    title napisał:
    //########### I/O ###########
    DDRB |= (1<<LED1) | (1<<LED2); //Ustawienie pinów sterujących diodami
    // jako wyjścia

    Początek programu potrafię napisać jednak wolę to zapisywać szesnastkowo.
    Jak zamienić tą linijkę?

    DDRB = 0x01 | 0x02 (w tym przypadku bez definiowania LED1 i LED2) ?

    Możesz, ale nie rób tego - posługuj się etykietami przypisanymi do pinów i rejestrów, bo to ułatwia rozumienie analizowanie (Tobie i nam) programu.


    title napisał:
    TIMSK |= (1<<TOIE0) oznacza włączenie przerwania od przepełnienia Timer0, zawsze zapisywana w taki sposób?

    Jesli masz wątpliwości to na takie pytania odpowiada dokumentacja mikrokontrolera:

    Cytat:
    • Bit 0 – TOIE0: Timer/Counter0 Overflow Interrupt Enable
    When the TOIE0 bit is written to one, and the I-bit in the Status Register is set (one), the
    Timer/Counter0 Overflow interrupt is enabled
    . The corresponding interrupt is executed if an




    overflow in Timer/Counter0 occurs, i.e., when the TOV0 bit is set in the Timer/Counter Interrupt
    Flag Register – TIFR.



    title napisał:
    TCCR0 |= (1<<CS02) | (1<<CS00) mój preskaler 8, zostawiam taką samą wartość CS02 i CS00 dlaczego nie ma CS01

    Bo po resecie te bity mają wartość zera, więc wystarczy ustawić na 1 te które chcesz. To pewne uproszczenie, które można stosować w większości przypadków. Jeśli natomiast chcesz mieć 100% pewności (projekty krytyczne), zawsze ustawiaj zero na bitach w których chcesz by zero było :)

    Co do tego, jaki preskaler ustawiasz zobacz "Table 34. Clock Select Bit Description" w dokumentacji.

    title napisał:
    Czyli wybieram Timer0 jest on 8-bitowy

    Tak i na to także znajdziesz odpowiedź w dokumentacji:

    Cytat:
    Timer/Counter0 is a general purpose, single channel, 8-bit Timer/Counter module


    title napisał:
    Za pomocą fusebitów ustawiłem wewnętrzny generator na 8 MHz czyli jest to sygnał click/o.

    8 MHz/8 = 1 MHz

    Jeden impuls trwa:

    1/ f = t
    1/ 1 000 000 Hz = 0,000001 s = 1 us

    Timer0 generuje przerwanie w przypadku przepełnienia:

    256 * 1 us = 256 us

    Tak, ale w funkcji przerwania ustawiany jest na początkową wartość 6 więc nie liczy od zera, czyli liczy około 250us.


    title napisał:

    sei(); //Globalne uruchomienie przerwań

    Jak zostało to opisane: "Zmienne globalne, to zmienne dostępne w dowolnym miejscu Twojego programu. "

    Przykład pokazywał:

    char ilosc_koni = 5;

    Tutaj mamy:

    sei(); dlaczego użyto sei i nie ma nic w nawiasach?

    Sei() to nie zmienna tylko funkcja która włącza przerwania globalnie (flaga I w rejestrze SREG) - i znowu dokumentacja:


    Cytat:
    • Bit 7 – I: Global Interrupt Enable
    The Global Interrupt Enable bit must be set for the interrupts to be enabled. The individual interrupt
    enable control is then performed in separate control registers. If the Global Interrupt Enable
    Register is cleared, none of the interrupts are enabled independent of the individual interrupt
    enable settings. The I-bit is cleared by hardware after an interrupt has occurred, and is set by
    the RETI instruction to enable subsequent interrupts. The I-bit can also be set and cleared by
    the application with the SEI and CLI instructions, as described in the Instruction Set Reference.


    Innymi słowy jest to nadrzędny włącznik przerwań. Jeżeli poszczególne przerwania z timerów, przetwornika ADC są włączone a I jest wyłączone, to żadne przerwanie nie zostanie uruchomione.


    title napisał:

    //############ Procedura obsługi przerwania od przepełnienia timera ############
    ISR(TIMER0_OVF_vect)

    Do czego służy ta linijka?

    Jest napisane w komentarzu.


    title napisał:

    if(cnt>3) //jeśli 4 przerwania (czyli ok 1 s)

    Rozumiem, że dopiero tutaj ustawiamy timer, czyli 4 przerwania po ok 250 ms co daje 1 s i następuje zmiana stanu?

    Tak.

    title napisał:
    Przerwanie to sygnał przerywający program.
    -przerywa program -> przechodzi do obsługi przerwania -> powraca do przerwanego programu.

    Tak.


    title napisał:
    250ms + 250ms + 250ms +250ms -> zmiana stanu -> 250ms + 250ms + 250ms +250ms -> zmiana stanu....

    Czy 250ms trwa od 6 do 255 i kolejne liczenie (łącznie 4 cykle) czy podczas tego liczenia 6-255 odbywają się 4 przerwania?

    Przy tak ustawionym timerze przerwanie następuje po przepełnieniu licznika, czyli gdy przekroczy wartość 255. Resztę już wywnioskujesz sam :)

    title napisał:
    Jak zatem ustawić zmienne w różnych odstępach czasu, np. 2s; 4s; 2s; 4s... ?

    Zliczając w przerwaniu wystąpienie przerwań i wiedząc, że przerwanie następuje co 250ms.

    title napisał:
    Pozdrawiam.

    Ja również, ale zadawaj pytania w mniejszych ilościach w jednym poście, bo trudno jest odpowiadać hurtem.

    0