Próbuję użyć manipulacji portami w przerwaniach, aby odczytać enkoder obrotowy. Znalazłem kod dla Uno, więc wywołanie portu dla pinów 2 i 3 są różne. Myślę, że na Mega są odpowiednio PORTH3 i PORTH4. Mój kod nie działa. Czy mam złe porty? Próbowałem przeczytać więcej na ten temat i nie rozumiem w pełni części Bxxxxxxxx. Myślę, że to może być błąd. Oto część mojego kodu z jednym z przerwań.
static int pinA = 2; // Our first hardware interrupt pin is digital pin 2 static int pinB = 3; // Our second hardware interrupt pin is digital pin 3 volatile byte aFlag = 0; // let us know when we"re expecting a rising edge on pinA to signal that the encoder has arrived at a detent volatile byte bFlag = 0; // let us know when we"re expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set) volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255 volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor) volatile byte reading = 0; void setup () { pinMode(pinA, INPUT); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases) pinMode(pinB, INPUT); attachInterrupt(0, PinA, RISING); // set an interrupt on PinA, //looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below) attachInterrupt(1, PinB, RISING); // set an interrupt on PinB, //looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below) } void PinA() { //CCW cli(); //stop interrupts happening before we read pin values reading = PORTH & 0xC; // read all eight pin values then strip away all but pinA and pinB"s values if (reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin"s rising edge encoderPos --; //decrement the encoder"s position count bFlag = 0; //reset flags for the next turn aFlag = 0; //reset flags for the next turn } else if (reading == B00000100) bFlag = 1; //signal that we"re expecting pinB to signal the transition to detent from free rotation sei(); //restart interrupts }
Komentarze
- Czy kiedykolwiek to działało? Ja również chciałem użyć Arduino Mega do śledzenia położenia kątowego enkodera Omron z 3 przerwaniami. Jedno z przerwań dla indeksu resetującego się do 0 za każdym razem kończy jedną rewolucję. Chcę go użyć do śledzenia obracającego się masztu w celu znalezienia kierunku. Są fragmenty kodu, ale nic nie jest kompletne. Czy Twój jest kompletny? [email protected]
Odpowiedź
Re „piny 2 i 3 są różne. Myślę, że na Mega są odpowiednio PORTH3 i PORTH4”, to prawda, że cyfrowe piny Arduino 2 a 3 należą do różnych portów na płytach Uno i Mega2560.
Mega2560 ma sześć pinów INTx, w porównaniu z dwoma takimi na Uno. W Mega INT0 … INT3 to PD0 … PD3, a INT4, INT5 to PE4 i PE5. W Uno, INT0, INT1 to PD2, PD3. Zauważ, że w odpowiedzi na Czy zewnętrzne przerwania mogą być LUB „d razem na” 328 (Uno)? Pokazuję kilka procedur, które wyświetlą odpowiednie maski dla piny na różnych Arduino. Zobacz sekcje „Używanie innych pinów dla PCI” i „Szkic generujący ramy ISR”.
Oto kilka problemów z kodem przedstawionym w pytaniu:
-
aFlag
jest inicjowane na zero i nigdy nie jest ustawiane na wartość niezerową w wyświetlanym kodzie. Zatem pierwszy warunekif
wPinA()
nigdy nie jest spełniony. -
PinA()
to moduł obsługi przerwań, połączony z przerwaniami przez wywołaniaattachInterrupt()
. Ponieważ sprzęt wyłącza przerwania przed wejściem do obsługi przerwań, nie ma potrzeby, aby program obsługi przerwań wyłączał przerwania. Oznacza to, że usuńcli()
wPinA()
. Podobnie, usuńsei()
na końcuPinA()
, ponieważ sprzęt przywraca stan przerwania, gdy wykonywana jest instrukcja RETI. -
Środowisko oprogramowania Arduino definiuje stałe, takie jak
B00001100
, z wartościami binarnymi pasującymi do nazwy. Oznacza to, że w środowisku oprogramowania Arduino stałaB00001100
ma wartość0B00001100
. Moim zdaniem to „głupia i niepotrzebna funkcja; sugeruję, abyś w swoim kodzie używał standardowej notacji C, takiej jak0B00001100
, gdy chcesz używać stałych binarnych. -
Uważam pisanie
encoderPos --
zamiastencoderPos--
za perwersję i sugeruję usunięcie tego niepotrzebnego spacji. -
Ponieważ nie pokazałeś obsługi przerwań
PinB()
, nie wiem, jak zamierzasz obsłużyć . Sądząc po przedstawionym kodzie, używasz metody, która „nie obsługuje poprawnie odrzuceń i sporadycznych błędów. Sugeruję użycie przerwań ze zmianą pinów i metody maszyny stanu, jak zilustrowano w odpowiedziach do:
• Czytanie z enkodera obrotowego KY-040 z Digispark
• Jak czytać RPS w celu szybkiego obracania z metodą zmiany stanu w Arduino?
• Czytaj kanały odbiornika RC za pomocą Interrupt zamiast PulseIn
• Czy zewnętrzne przerwania mogą być LUB „d razem na” 328 (Uno)?
Odpowiedź
Na mega, byś przeczytał szpilki z SOSNĄ.
Twój kod w PinA zmieniłby się na:
reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;
I znalazłem świetną dyskusję dotyczącą wymaganego maskowania: https://forum.arduino.cc/index.php?topic=561741.0