Skocz do zawartości

Atmega328p - przerwanie licznika i przesunięcie migania w fazie


Saalin

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. 

Link do komentarza
Share on other sites

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
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

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.

Link do komentarza
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!

Anonim
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...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.