Încerc să folosesc manipularea portului în întreruperi pentru a citi un codificator rotativ. Am găsit cod pentru un Uno, deci apelul de port pentru pinii 2 și 3 sunt diferite. Cred că pe Mega sunt PORTH3 și respectiv PORTH4. Codul meu nu funcționează. Am gresit porturile? Am încercat să citesc acest lucru și nu înțeleg pe deplin partea Bxxxxxxxx. Cred că ar putea fi ceea ce este incorect. Iată o parte din codul meu cu una dintre întreruperi.
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 }
Comentarii
- Ați reușit vreodată să funcționeze? Și eu am vrut să folosesc un Arduino Mega pentru a urmări poziția unghiulară a unui codificator Omron cu 3 întreruperi. Una dintre întreruperi pentru ca Indexul să se reseteze la 0 de fiecare dată se finalizează o revoluție. Vreau să-l folosesc pentru a urmări un catarg rotativ pentru găsirea direcției. Există bucăți de cod, dar nimic complet. Este al tău complet? [email protected]
Răspuns
Re „pinii 2 și 3 sunt diferiți. Cred că pe Mega sunt PORTH3 și respectiv PORTH4”, este adevărat că pinii digitali Arduino 2 și 3 aparțin porturilor diferite pe plăcile Uno vs Mega2560.
Mega2560 „are șase pini INTx, comparativ cu două astfel de pe Uno”. Pe Mega, INT0 … INT3 sunt PD0 … PD3 și INT4, INT5 sunt PE4, PE5. Pe Uno, INT0, INT1 sunt PD2, PD3. Rețineți, într-un răspuns la Pot fi întreruperile externe SAU „d împreună pe” 328 (Uno)? Arăt câteva rutine care vor afișa măști adecvate pentru pini pe diferite Arduino. Vedeți secțiunile „Utilizarea altor pini pentru PCI-uri” și „Schiță generatoare de cadru ISR”.
Iată câteva probleme cu codul prezentat în întrebare:
-
aFlag
este inițializat la zero și nu este setat niciodată diferit de zero în codul afișat. Deci, prima condițieif
dinPinA()
nu este îndeplinită niciodată. -
PinA()
este un gestionar de întreruperi, conectat la întreruperi prin apelurile dvs.attachInterrupt()
. Deoarece hardware-ul dezactivează întreruperile înainte de a intra într-un handler de întrerupere, nu este necesar ca handlerul de întrerupere să dezactiveze întreruperile. Adică, ștergețicli()
înPinA()
. În mod similar, ștergețisei()
la sfârșitulPinA()
deoarece hardware-ul restabilește starea de întrerupere atunci când se execută o instrucțiune RETI. -
Mediul software Arduino definește constante precum
B00001100
cu valori binare care se potrivesc cu numele. Adică, în mediul software Arduino, constantaB00001100
are valoarea0B00001100
. În opinia mea, acea „caracteristică stupidă și inutilă; vă sugerez ca în codul dvs. să utilizați notația C standard ca0B00001100
atunci când doriți să utilizați valori constante binare. -
Consider că scrierea
encoderPos --
în loc deencoderPos--
este o perversiune și sugerez ștergerea acelui spațiu inutil. -
Deoarece nu ați afișat
PinB()
handlerul de întreruperi, nu știu cum veți gestionaencoderPos++
. Judecând după codul afișat, utilizați o metodă care nu va gestiona corect erori de revenire și intermitente. Vă sugerez să utilizați întreruperi de modificare a pinului și o metodă stat-mașină, așa cum se ilustrează în răspunsurile la:
• Citirea dintr-un codor rotativ KY-040 cu Digispark
• Cum se citește RPS pentru rotație rapidă cu metoda de schimbare a stării în Arduino?
• Citiți canalele receptorului RC folosind Interrupt în loc de PulseIn
• Pot fi întreruperile externe SAU „d împreună pe” 328 (Uno)?
Răspuns
Pe mega, ai fi citit pinii cu PINE.
Deci, codul dvs. din PinA s-ar schimba în:
reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;
I am găsit o discuție excelentă vorbind despre mascarea necesară aici: https://forum.arduino.cc/index.php?topic=561741.0