Obecnie mój szkic sprawdza pin wejściowy za każdym razem wokół głównej pętli. Jeśli wykryje zmianę, wywołuje niestandardową funkcję, aby na nią zareagować. Oto kod (skrócony do najważniejszych):
int pinValue = LOW;
void pinChanged()
{
//...
}
void setup()
{
pinMode(2, INPUT);
}
void loop()
{
// Read current input
int newValue = digitalRead(2);
// Has the input changed?
if (newValue != pinValue) {
pinValue = newValue;
pinChanged();
}
}
Niestety, nie zawsze działa to poprawnie w przypadku bardzo krótkich zmian na wejściu (np. Krótkich impulsów), szczególnie jeśli loop()
działa nieco wolniej.
Czy istnieje sposób, aby Arduino wykrył zmianę wejścia i automatycznie wywołał moją funkcję?
Odpowiedzi:
Możesz to zrobić za pomocą zewnętrznych przerwań. Większość Arduinos obsługuje to jednak tylko na ograniczonej liczbie pinów. Aby uzyskać szczegółowe informacje, zobacz dokumentację na
attachInterrupt()
.Zakładając, że używasz Uno, możesz to zrobić w następujący sposób:
Wywoła się
pinChanged()
za każdym razem, gdy zostanie wykryta zmiana w zewnętrznym przerwaniu 0. Na Uno, które odpowiada pinowi GPIO 2. Numeracja zewnętrznych przerwań jest inna na innych płytach, dlatego ważne jest sprawdzenie odpowiedniej dokumentacji.Istnieją jednak ograniczenia tego podejścia. Funkcja niestandardowa
pinChanged()
jest używana jako procedura obsługi przerwań (ISR). Oznacza to, że reszta kodu (wszystko w środkuloop()
) jest tymczasowo zatrzymywana podczas wykonywania połączenia. Aby zapobiec zakłóceniu ważnych terminów, powinieneś dążyć do jak najszybszego uzyskania ISR.Ważne jest również, aby pamiętać, że żadne inne zakłócenia nie będą działać podczas twojego ISR. Oznacza to, że wszystko zależne od przerwań (takie jak rdzeń
delay()
imillis()
funkcje) może nie działać poprawnie w nim.Na koniec, jeśli twój ISR musi zmienić dowolne zmienne globalne w szkicu, zwykle powinny być zadeklarowane jako
volatile
, np .:Jest to ważne, ponieważ informuje kompilator, że wartość może się nieoczekiwanie zmienić, dlatego należy uważać, aby nie używać żadnych nieaktualnych kopii / pamięci podręcznych.
źródło
pinChanged()
powinien być jak najkrótszy. Stąd zwykle minimalny czas powinien być czasem wykonaniapinChanged()
samej funkcji.volatile
, jeśli zmienna globalna jest szersza niż 1 bajt, tak jak niektóreNumer, musisz zabezpieczyć się przed przerwaniem zmiany pinów występującym między programami przez dostęp do bajtów. Instrukcja typusomeNumber +=5;
obejmuje dodawanie niskich bajtów i dodawanie wysokich bajtów z dołączonym przeniesieniem. Te dwa (więcej, w przypadku szerszych zmiennych) nie mogą być dzielone przez przerwanie. Wystarczy wyłączyć przerwania i przywrócić je odpowiednio przed i po operacji.Każdy stan zmiany dowolnego pinu skonfigurowanego jako wejście cyfrowe może spowodować przerwanie. W przeciwieństwie do unikalnych wektorów dla przerwań spowodowanych przez INT1 lub INT2, funkcja PinChangeInt wykorzystuje wspólny wektor, a następnie Procedura Przerwania Usługi (inaczej ISR) dla tego wektora musi następnie ustalić, który pin został zmieniony.
Na szczęście biblioteka PinChangeInt ułatwia to.
źródło
W przypadku, gdy chcesz wykryć napięcie przekraczające próg , zamiast być WYSOKIM lub NISKIM, możesz użyć komparatora analogowego. Przykładowy szkic:
Może to być przydatne w przypadku detektorów światła, w których może być konieczne wykrycie zmiany z (powiedzmy) 1V na 2V na wejściu.
Przykładowy obwód:
Możesz także użyć Input Capture Unit na procesorze, który zapamięta dokładny czas niektórych wejść, zapisując bieżącą liczbę Timer / Counter 1. Pozwala to zachować dokładny (dobrze, prawie dokładny) moment, w którym zdarzenie pojawiło się zainteresowanie, zamiast wprowadzać opóźnienie (prawdopodobnie kilka mikrosekund), zanim ISR będzie można wykorzystać do uchwycenia bieżącego czasu.
W przypadku aplikacji o krytycznym czasie może to dać nieco większą dokładność.
Przykład zastosowania: Zamień Arduino w tester kondensatorów
źródło