Ik probeer poortmanipulatie te gebruiken in interrupts om een roterende encoder te lezen. Ik heb code gevonden voor een Uno, dus de poortoproep voor pinnen 2 en 3 is anders. Ik denk dat ze op de Mega respectievelijk PORTH3 en PORTH4 zijn. Mijn code werkt niet. Heb ik mijn poorten verkeerd? Ik heb geprobeerd hierover te lezen en ik begrijp het Bxxxxxxxx-gedeelte niet helemaal. Ik denk dat dat onjuist is. Hier is een deel van mijn code met een van de interrupts.
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 }
Reacties
- Heb je dit ooit aan de praat gekregen? Ik heb ook een Arduino Mega willen gebruiken om de hoekpositie van een Omron Encoder te volgen met 3 interrupts. Een van de interrupts om de Index elke keer weer op 0 te zetten het voltooit één revolutie. Ik wil het gebruiken om een roterende mast te volgen om de richting te bepalen. Er zijn stukjes code maar niets compleet. Is die van jou compleet? [email protected]
Antwoord
Re “pinnen 2 en 3 zijn verschillend. Ik denk dat ze op de Mega respectievelijk PORTH3 en PORTH4 zijn”, het is waar dat Arduino digitale pinnen 2 en 3 behoren tot verschillende poorten op Uno vs Mega2560 boards.
Mega2560 “s hebben zes INTx pinnen, versus twee op Uno” s. Op de Mega zijn INT0 … INT3 PD0 … PD3 en INT4, INT5 zijn PE4, PE5. Op de Uno, INT0, INT1 zijn PD2, PD3. Let op: in een antwoord op Kunnen externe interrupts OR “d samen zijn op de” 328 (Uno)? Ik laat een aantal routines zien die geschikte maskers weergeven voor pinnen op verschillende Arduinos. Zie de secties “Andere pinnen gebruiken voor PCIs” en “ISR-framework-genererende Sketch”.
Hier zijn een paar problemen met de code die in de vraag wordt getoond:
-
aFlag
wordt op nul geïnitialiseerd en wordt nooit op nul gezet in de getoonde code. Aan de eersteif
voorwaarde inPinA()
wordt dus nooit voldaan. -
PinA()
is een interrupt-handler, verbonden met interrupts door uwattachInterrupt()
-oproepen. Omdat hardware interrupts uitschakelt voordat deze een interrupthandler binnengaat, is het niet nodig dat de interrupthandler interrupts uitschakelt. Dat wil zeggen, verwijdercli()
inPinA()
. Verwijder op dezelfde manier desei()
aan het einde vanPinA()
omdat hardware de interruptstatus herstelt wanneer een RETI-instructie wordt uitgevoerd. -
De Arduino-softwareomgeving definieert constanten zoals
B00001100
met binaire waarden die overeenkomen met de naam. Dat wil zeggen, in de Arduino-softwareomgeving heeft constanteB00001100
de waarde0B00001100
. Naar mijn mening “is dat een stom en onnodig kenmerk; ik stel voor dat je in je code de standaard C-notatie gebruikt, zoals0B00001100
wanneer je binaire constante waarden wilt gebruiken. -
Ik beschouw het schrijven van
encoderPos --
in plaats vanencoderPos--
als een perversie en stel voor om die onnodige ruimte te verwijderen. -
Aangezien je de
PinB()
interrupt-handler niet hebt getoond, weet ik niet hoe je deencoderPos++
case. Te oordelen naar de getoonde code, gebruikt u een methode die “bounce” en intermitterende fouten niet correct afhandelt. Ik stel voor om pin-change interrupts en een state-machine-methode te gebruiken, zoals geïllustreerd in de antwoorden op:
• Lezen van een KY-040 roterende encoder met Digispark
• Hoe lees ik RPS voor snelle rotatie met statuswijzigingsmethode in Arduino?
• Lezen van RC-ontvangerkanalen met Interrupt in plaats van PulseIn
• Kunnen externe interrupts OF “d samen worden op de” 328 (Uno)?
Answer
Op de mega had je “de pinnen gelezen met PINE.
Dus je code in PinA zou veranderen in:
reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;
I vond een geweldige discussie over de vereiste maskering hier: https://forum.arduino.cc/index.php?topic=561741.0