Arduino Mega 2560 interruptpinnen en poorttoewijzing met roterende encoder

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:

  1. aFlag wordt op nul geïnitialiseerd en wordt nooit op nul gezet in de getoonde code. Aan de eerste if voorwaarde in PinA() wordt dus nooit voldaan.

  2. PinA() is een interrupt-handler, verbonden met interrupts door uw attachInterrupt() -oproepen. Omdat hardware interrupts uitschakelt voordat deze een interrupthandler binnengaat, is het niet nodig dat de interrupthandler interrupts uitschakelt. Dat wil zeggen, verwijder cli() in PinA(). Verwijder op dezelfde manier de sei() aan het einde van PinA() omdat hardware de interruptstatus herstelt wanneer een RETI-instructie wordt uitgevoerd.

  3. De Arduino-softwareomgeving definieert constanten zoals B00001100 met binaire waarden die overeenkomen met de naam. Dat wil zeggen, in de Arduino-softwareomgeving heeft constante B00001100 de waarde 0B00001100. Naar mijn mening “is dat een stom en onnodig kenmerk; ik stel voor dat je in je code de standaard C-notatie gebruikt, zoals 0B00001100 wanneer je binaire constante waarden wilt gebruiken.

  4. Ik beschouw het schrijven van encoderPos -- in plaats van encoderPos-- als een perversie en stel voor om die onnodige ruimte te verwijderen.

  5. Aangezien je de PinB() interrupt-handler niet hebt getoond, weet ik niet hoe je de encoderPos++ 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

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *