Skocz do zawartości

Attiny1606 - przerwanie załącza się bez względu na stan przycisku.


JammyCrazy

Pomocna odpowiedź

Dzień Dobry,

Po nieudanym projekcie mini-konsoli postanowiłem wziąć się za coś prostszego - zegarek AVR, z 7-segmentowym wyświetlaczem. Tutaj wszystko poszło gładko. Niestety, trafiłem na dość poważny problem, którego nie potrafię sam rozwiązać. Otóż bez względu na to, czy przycisk jest wciśnięty, czy też nie, mikrokontroler wywołuje procedurę przerwania (PORTA_PORT_vect). Uniemożliwia to uśpienie mikrokontrolera, przez co całe urządzenie pobiera 1mA w spoczynku (zdecydowanie za dużo). Po wyłączeniu tego przerwania zegarek pobiera prąd rzędu 30-80uA, jednak nie mam możliwości jego wybudzenia, gdyż ten przycisk miał pełnić tę rolę. Obecnie planuję wersję V2.0, w której, jeśli to może pomóc, dorzucę do przycisku filtr RC - obecnie (wersja V1.0) posiada tylko rezystor pull-up. Chciałbym jednak wiedzieć, co dokładnie może powodować ten problem i czy ten filtr to nie za mało... 🤔

Wszystkie inne funkcje zegarka działają całkowicie poprawnie. Poniżej załączam schemat oraz kod programu testowego, dzięki któremu "odkryłem" źródło problemu (zmienna licznik po 1 sekundzie przekracza wartość kilku tysięcy). Efekt jest taki sam dla przerwania BOTHEDGES, jak i FALLING i LEVEL. W przypadku RISING mikrokontroler zachowuje się tak samo, jak dla wyłączonego przerwania (brak reakcji).

 

/* Program liczący ilość wywołań przerwania. */

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>	
#include <util/atomic.h>

#include "avr_watch.c"					// Zawiera nagłówki funkcji wyświetlających;

volatile uint32_t licznik = 0;

int main(void)
{
	// ... inicjacja wyświetlacza;
	
	PORTA.PIN1CTRL = PORT_ISC_BOTHEDGES_gc;		// Przerwanie dla pinu A1 (przycisk);
	sei();						// Globalne wł. przerwań;
	
	while(1)
	{
		// ... wyświetlanie zmiennej "licznik";
	}
}

ISR(PORTA_PORT_vect)
{
	ATOMIC_BLOCK(ATOMIC_FORCEON)
	{
		++licznik;
	}	
}

 

Schemat:

schemat.pdf

Link do komentarza
Share on other sites

Usuń funkcję atomic z przerwania. I  w procedurze musisz sprawdzić na którym pinie portu to przerwanie wystąpiło. 

EDIT: jeśli koniecznie chcesz użyć makra atomic to powinno się ono znajdować w pętli głównej. 

Edytowano przez _LM_
Link do komentarza
Share on other sites

(edytowany)
1 godzinę temu, _LM_ napisał:

Usuń funkcję atomic z przerwania. I  w procedurze musisz sprawdzić na którym pinie portu to przerwanie wystąpiło.

Myślałem, że przy zmiennych 16, 32 i 64-bitowych należy korzystać z atomiców.

Chodzi mi o to, że przerwanie wybudza mikrokontroler, nieważne czy przycisk jest naciśnięty, przez co nie mogę go uśpić. Co chwilę to przerwanie jest wywoływane.

Edytowano przez JammyCrazy
Link do komentarza
Share on other sites

3 minuty temu, JammyCrazy napisał:

Myślałem, że przy zmiennych 16, 32 i 64-bitowych należy korzystać z atomiców

Należy ale w sytuacjach gdzie może dojść do próby modyfikacji zmiennej w trakcie jej użycia....czyli np. masz kod główny, w nim chcesz wyświetlać jakąś zmienna która jest również używana w przerwaniu i może tam zostać zmodyfikowana...wtedy należy użyć atomic w przypadku wyświetlania tej zmiennej

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

9 minut temu, JammyCrazy napisał:

Myślałem, że przy zmiennych 16, 32 i 64-bitowych należy korzystać z atomiców.

No i dobrze kombinujesz, tylko że użyłeś tego atomica w złym miejscu https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html funkcja atomowa to nic innego (w uproszczeniu) jak zablokowanie przerwań w momencie odczytu zmiennej i przywrócenie ich statusu po tym. 

 

 

Edytowano przez _LM_
Link do komentarza
Share on other sites

10 minut temu, JammyCrazy napisał:

Chodzi mi o to, że przerwanie wybudza mikrokontroler

Musiałbym trochę przegrzebać manuala tego uP czy w pdfie niema przykładów jak usypiać?

Link do komentarza
Share on other sites

Jeśli usunę "linijkę kodu", gdzie włączam obsługę przerwania dla pinu A1 (PORT A, PIN 1), to wszystko działa jak należy. Mikrokontroler wtedy pobiera jakieś pojedyncze uA. Po prostu nie wiem dlaczego przerwanie dla tego portu jest co chwilę wywoływane, a nie tylko w przypadku wciśnięć przycisku.

A propos tego atomica. To samo przerwanie nie może zostać wywołane, dopóki jest ono jeszcze wykonywane. Dobrze myślę? Bodajże AVRy nie posiadają jako tako kolejki przerwań, tylko flagi na zasadzie przerwanie obsłużone/nieobsłużone.

Link do komentarza
Share on other sites

19 minut temu, JammyCrazy napisał:

A propos tego atomica

Powiem szczerze że nie zajmowałem się tymi nowymi AVR więc nie jestem pewien jak to w nich działa. W starych wersjach było jak mówisz, były flagi od ISR i kasowanie następowało automatycznie - też już nie pamiętam czy po wejściu, czy wyjściu z procedury. Dzięki takiemu mechanizmowi można było ręcznie obsługiwać przerwania na zasadzie pollingu czyli oczekiwania na ustawienie odpowiedniego bitu w rejestrze. Przeczytaj ten opis w linku wyżej - powinieneś wtedy załapać jak działa to makro. 

  • Lubię! 1
Link do komentarza
Share on other sites

(edytowany)

Ok. A co z tymi samoczynnymi przerwaniami? Nieważne, czy przycisk jest naciśnięty, czy też nie, jest ono wywoływane, wybudzając tym samym mikrokontroler. Jest to coś, co mnie strasznie irytuje. Zegarek zamiast działać na jednej baterii 30 dni, działa 3. 

 

Edytowano przez JammyCrazy
Link do komentarza
Share on other sites

1 minutę temu, JammyCrazy napisał:

Ok. A co z tymi samoczynnymi przerwaniami?

A jesteś pewien że masz poprawne podciąganie na GPIO? zmierz to multimetrem, a programowo ja zacząłbym od ustawienia przerwania tylko na zbocze opadające i włączenie wewnętrznego pullupa. Potem postępowanie zgodnie z manualem tego mikrokontrolera 

chrome_vq5B9D6AVd.thumb.png.37ef2383dbbcc83feac332dc3a71aa54.png

 

Link do komentarza
Share on other sites

Zmieniłem chwilowo na 5k, nic to nie dało. A wewnętrzny pull-up to ledwo 50k, czyli jakieś 36uA więcej, przy napięciu 1.8V.

3 minuty temu, _LM_ napisał:

zbiera wszelkie zakłócenia 

Dlatego planowałem/planuję dodać jakiś filtr... Tylko nie do końca wiem jaki.

Link do komentarza
Share on other sites

2 minuty temu, ethanak napisał:

Dziejszy dzień spondoruje słowo "debouncing"

Ten problem występuje nawet jak przycisk nie był dotykany przez x godzin. Zegarek po prostu "se" leży (tzn. jest umieszczony w trzeciej ręce), podłączony tylko kabelkami z Arduino, a zjawisko nadal występuje. 

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.