Skocz do zawartości
Saalin

Atmega328p - przerwanie licznika i przesunięcie migania w fazie

Pomocna odpowiedź

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

#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED0 PB0
#define LED2 PB1
#define LED1 PB2

ISR(TIMER1_COMPA_vect)
{
    LED_PORT ^= (1 << LED0);
}

int main(void)
{
    LED_DDR |= (1 << LED0) | (1 << LED1) | (1 << LED2); 
    
    TCCR1A = (1 << COM1A0); //toggle OC1A on compare match
    TCCR1B |= (1 << CS12) | (1 << CS10) | (1 << WGM12) | (1 << WGM13); //CTC, presacler 1024
    ICR1 = 15624; // 1Hz
    TIMSK1 |= (1 << OCIE1A);
    
    sei();
    while (1) 
    {
        _delay_ms(1000);
        LED_PORT ^= (1 << LED1);
    }
}

Działanie programu do pewnego momentu zgodne z oczekiwaniami - 3 diody LED zapalają się i gasną co sekundę. W pewnym momencie jednak następuje przesunięcie migania w fazie - dzieje się to nagle, nie jest tak, że coś tam niedokładności, miganie się rozjeżdża powoli itd - w pewnym momencie LED0 ma przestój nie 1s, tylko 2s (przynajmniej tak mi się wydaje po obserwacjach) i później diody migają na zmianę: raz LED0, raz LED1 wspólnie z LED2. Da się to jakoś logicznie wytłumaczyć? Nie zauważyłem, żeby zjawisko występowało okresowo. 

Udostępnij ten post


Link to post
Share on other sites

Tak zapytam z ciekawości, na jakiej częstotliwości działa ta atmega? Bo może coś z tym preskalerem jest nie tak. Taka luźna opcja bo jestem super początkujący 😀

Udostępnij ten post


Link to post
Share on other sites

Korzystam z Cytron Maker Uno, który taktowany jest kwarcem 16 MHz, kod kompiluję z opcją -D F_CPU 16000000. 

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
Dnia 24.02.2019 o 17:22, Saalin napisał:

W pewnym momencie jednak następuje przesunięcie migania w fazie - dzieje się to nagle, nie jest tak, że coś tam niedokładności, miganie się rozjeżdża powoli itd - w pewnym momencie LED0 ma przestój nie 1s, tylko 2s (przynajmniej tak mi się wydaje po obserwacjach)...

Da się to jakoś logicznie wytłumaczyć?

Najprawdopodobniej przyczyną jest brak atomowego dostępu do portu LED_PORT. Instrukcja języka C - LED_PORT ^= (1 << LED1); wymaga tak naprawdę wykonania przez mikrokontroler kilku instrukcji asemblera. Jeśli pomiędzy tymi instrukcjami wystąpi przerwanie i zmieni zawartość portu, to po powrocie z procedury obsługi przerwania ta zmiana zostanie cofnięta.

Rozwiązaniem może być wyłączenie przerwań na czas zmiany stanu portu:

    //   ...
    while (1) 
    {
        _delay_ms(1000);
        cli();
        LED_PORT ^= (1 << LED1);
        sei();
    }
    //   ...

Powinno pomóc, jednakże stosowanie funkcji _delay_ms() (szczególnie przy włączonej obsłudze przerwań) nie pozwala na jakieś precyzyjne odmierzanie czasu, więc miganie i tak się prędzej czy później rozjedzie 😐

Edytowano przez andrews
  • Pomogłeś! 1

Udostępnij ten post


Link to post
Share on other sites
Dnia 2.03.2019 o 19:57, andrews napisał:

stosowanie funkcji _delay_ms() (szczególnie przy włączonej obsłudze przerwań) nie pozwala na jakieś precyzyjne odmierzanie czasu, więc miganie i tak się prędzej czy później rozjedzie 😐

Dokładnie tak, dlatego do precyzyjnego odmierzania czasu należy korzystać z timerów i przerwań. W twoim programie czas wykonywania przerwania dodaje się do _delay_ms() i w rezultacie jedna dioda mruga wolniej. Proponuję też zajrzeć sobie do pliku *.lss po kompilacji i policzyć takty wykonywanych instrukcji w jednym i drugim przypadku wtedy będzie wszystko jasne zupełnie. Może okazać się również, że implementacja własnej wstawki asm będzie bardziej optymalnym rozwiązaniem niż kod wyprodukowany przez kompilator ale to kwestia wymagań dla konkretnego przypadku. Owocnej nauki.

  • Pomogłeś! 1

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...