Skocz do zawartości
jasiekk913

Arduino - pomoc z programem do buttonbox'a

Pomocna odpowiedź

Owszem - chociaż jak sam zauważyłeś, można użyć szybszych konstrukcji niż digitalRead/digitalWrite. Tu akurat idealnie pasuje rodzinka digitalReadFast/digitalWriteFast.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Tak wygląda implementacja digitalWrite w Arduino. Ciekawe że jest tu użyta funkcja cli (funkcja nie funkcja, ponoć po przekompilownaiu jest to jedna linia asemblera). Ale ustawia flagę wyłączająca wszystkie przerwania. Czy mimo to działa trzeba by sprawdzić.

void digitalWrite(uint8_t pin, uint8_t val)
{
	uint8_t timer = digitalPinToTimer(pin);
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);
	volatile uint8_t *out;

	if (port == NOT_A_PIN) return;

	// If the pin that support PWM output, we need to turn it off
	// before doing a digital write.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	out = portOutputRegister(port);

	uint8_t oldSREG = SREG;
	cli();

	if (val == LOW) {
		*out &= ~bit;
	} else {
		*out |= bit;
	}

	SREG = oldSREG;
}

Ciekawe jest to, że w przykładzie od Arduino, w funkcji przerwania specjalnie nie jest używany zapis digitalWrite:

const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
  digitalWrite(ledPin, state);
}

void blink() {
  state = !state;
}

Możliwe że jest to zabezpieczenie przed kolizją w zapisie/odczycie gdyby operacja odczytu została wyprzedzona zapisem.

Udostępnij ten post


Link to post
Share on other sites
7 minut temu, Gieneq napisał:

Ale ustawia flagę wyłączająca wszystkie przerwania.

I za chwilę przywraca stan sprzed ustawienia.

Pewnie dlatego, że zapis typu

PORTx |= BIT

to w rzeczywistości trochę więcej niż jedna instrukcja, odpowiednik mniej więcej:
 

register uint8_t a = PORTx;
a |= BIT;
PORTx = a;

i między odczytem a zapisem PORTx istnieje możliwość zmiany stanu jakiegoś pinu.

Udostępnij ten post


Link to post
Share on other sites
5 godzin temu, slon napisał:

Dziękuje za odpowiedzi.  Czy taki zapis z punktu widzenia istoty przerwania będzie poprawny ? (pomijając, że można by użyć bitSet() lub PORTB)


ISR(PCINT0_vect) {
if(digitalRead(12) == HIGH) {
  liczynik=1;
  digitalWrite(13, HIGH);
} else {
  digitalWrite(13, LOW);
 }
}

 

Cześć,

niezbyt poprawny bo digitalRead i digital Write są same wykonywane za pomocą przerwań. Lepiej ustaw sobie jakąś zmienną typu bool na true i na jej podstawie rób digitalWrite w pętli głównej.

Pozdrawiam

Udostępnij ten post


Link to post
Share on other sites
1 minutę temu, FlyingDutch napisał:

digitalRead i digital Write są

Powiedz mi, co przegapiłem?

Udostępnij ten post


Link to post
Share on other sites

Nie spodziewałem się , że temat tak się rozwinie aczkolwiek bardzo jestem z tego zadowolony. Więc wracając do przerwań.  

ISR(PCINT0_vect)

 Ja cały czas myślę o tych przerwaniach i tu jak widać digitalWrite występuję. Jaka jest różnica między Pin- change Interrupt a External Interrupt od strony programowej ? Nie chodzi mi o to , że jedne są na wszystkich pinach arduino a pozostałe na dwóch.

Udostępnij ten post


Link to post
Share on other sites

@slon Nie ma żadnej. Przerwanie to przerwanie - a w jaki sposób zostało wywołane to dla programu nieistotne (nawet, jeśli sam program wywołał przerwanie).

digitalWrite może wystąpić - nie ma nic wspólnego z przerwaniami (poza tym, że blokuje na chwilę przerwania co w tym przypadku nie ma żadnego wpływu na działanie, ponieważ w trakcie wywołania procedury ISR przerwania i tak są zablokowane). Pisałem o digitalWriteFast dlatego, że wykonuje się dużo szybciej - argumenty są znane w czasie kompilacji czyli nie trzeba wywoływać funkcji w stylu "a jaki to port i jaki bit i czy mam zrobić or czy and", a ewentualnym blokowaniem przerwań ma się interesować programista (do tego jest makro ATOMIC_BLOCK w util/atomic.h w bibliotece avr-libc).

Oczywiście to co piszę to pewne uproszczenie (mogę w procedurze ISR ręcznie odblokować przerwania jeśli z jakichś powodów jest mi to potrzebne) - ale możemy założyć, że o ile nie stosujemy jakichś tricków to wszystko się odbywa w najprostszy sposób:

a) na stosie zapamiętywane są wartości najważniejszych rejestrów z licznikiem instrukcji na czele oraz blokowane są przerwania

b) procesor wykonuje procedurę ISR

c) wartości rejestrów odtwarzane są ze stosu w ten sposób, że program nawet nie wie że coś go przerwało

Problem zaczyna się pojawiać, gdy następne przerwanie przychodzi w czasie wykonywania pierwszego. Co prawda przerwania są zablokowane, ale w przypadku AVR-ów zapamiętywane jest przyjście przerwania i po wyjściu z pierwszego procesor natychmiast (no, prawie...) wchodzi w obsługę drugiego. Niestety - zapamiętywane jest tylko jedno przerwanie; jeśli w czasie obsługi przerwania przyjdzie więcej niż jedno - pozostałe zostaną zignorowane.

Czy to wyjaśnienie wystarczy?

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Jak dla mnie w zupełności wystarczy. Dzięki.

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ść
Napisz odpowiedź...

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