Sto cercando di utilizzare la manipolazione delle porte negli interrupt per leggere un codificatore rotante. Ho trovato il codice per uno, quindi il port call per i pin 2 e 3 è diverso. Penso che sul Mega siano rispettivamente PORTH3 e PORTH4. Il mio codice non funziona. Ho sbagliato le mie porte? Ho provato a leggere su questo e non capisco appieno la parte Bxxxxxxxx. Penso che potrebbe essere ciò che non è corretto. Ecco parte del mio codice con uno degli interrupt.
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 }
Commenti
- Lhai mai fatto funzionare? Anchio volevo usare un Arduino Mega per tracciare la posizione angolare di un Encoder Omron con 3 interruzioni. Uno degli interrupt per lindice da reimpostare ogni volta a 0 completa una rivoluzione. Voglio usarlo per tracciare un albero rotante per la ricerca della direzione. Ci sono pezzi di codice ma niente di completo. Il tuo è completo? [email protected]
Risposta
I “pin 2 e 3 sono diversi. Penso che sul Mega siano rispettivamente PORTH3 e PORTH4”, è vero che i pin digitali 2 di Arduino e 3 appartengono a porte differenti sulle schede Uno e Mega2560.
Le Mega2560 hanno sei pin INTx, contro due di queste su Uno “. Sul Mega, INT0 … INT3 sono PD0 … PD3 e INT4, INT5 sono PE4, PE5. Su Uno, INT0, INT1 sono PD2, PD3. Nota, in una risposta a Gli interrupt esterni possono essere OR “d insieme sul” 328 (Uno)? mostro un paio di routine che mostreranno maschere appropriate per pin su diversi Arduino. Vedere le sezioni “Utilizzo di altri pin per i PCI” e “Schizzo che genera un framework ISR”.
Ecco alcuni problemi con il codice mostrato nella domanda:
-
aFlag
è inizializzato a zero e non è mai impostato su un valore diverso da zero nel codice mostrato. Quindi la prima condizioneif
inPinA()
non viene mai soddisfatta. -
PinA()
è un gestore di interrupt, connesso alle interruzioni dalle tue chiamateattachInterrupt()
. Poiché lhardware disabilita gli interrupt prima di entrare in un gestore di interrupt, non è necessario che il gestore di interrupt disattivi gli interrupt. Ovvero, eliminacli()
inPinA()
. Allo stesso modo, eliminasei()
alla fine diPinA()
perché lhardware ripristina lo stato di interrupt quando viene eseguita unistruzione RETI. -
Lambiente software Arduino definisce costanti come
B00001100
con valori binari che corrispondono al nome. Cioè, nellambiente software Arduino, la costanteB00001100
ha il valore0B00001100
. A mio parere, questa “è una funzionalità stupida e non necessaria; suggerisco di utilizzare nel codice la notazione C standard come0B00001100
quando si desidera utilizzare valori di costanti binarie. -
Considero la scrittura di
encoderPos --
invece diencoderPos--
una perversione e suggerisco di eliminare quello spazio non necessario. -
Dato che non hai mostrato il
PinB()
gestore di interrupt, non so come gestirestiencoderPos++
caso. A giudicare dal codice mostrato, stai utilizzando un metodo che non gestisce correttamente i rimbalzi e gli errori intermittenti. Suggerisco di utilizzare interrupt di cambio pin e un metodo macchina a stati, come illustrato nelle risposte a:
• Lettura da un codificatore rotante KY-040 con Digispark
• Come leggere RPS per una rotazione rapida con il metodo di modifica dello stato in Arduino?
• Leggere i canali del ricevitore RC utilizzando Interrupt invece di PulseIn
• Gli interrupt esterni possono essere OR “d insieme sul” 328 (Uno)?
Risposta
Sul mega, avresti “letto i pin con PINE.
Quindi il tuo codice in PinA cambierebbe in:
reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;
I ho trovato unottima discussione parlando del mascheramento richiesto qui: https://forum.arduino.cc/index.php?topic=561741.0