Arduino Mega 2560 interrupt pins og port mapping med roterende encoder

Jeg prøver at bruge portmanipulation i afbrydelser for at læse en roterende encoder. Jeg fandt kode til en Uno, så portopkaldet til ben 2 og 3 er forskellige. Jeg tror på Mega, at de er henholdsvis PORTH3 og PORTH4. Min kode fungerer ikke. Har jeg mine porte forkert? Jeg har prøvet at læse om dette, og jeg forstår ikke Bxxxxxxxx-delen fuldt ud. Jeg tror, det kan være, hvad der er forkert. Her er en del af min kode med en af afbrydelserne.

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 } 

Kommentarer

  • Har du nogensinde fået dette til at fungere? Jeg har også ønsket at bruge en Arduino Mega til at spore vinkelpositionen på en Omron Encoder med 3 afbrydelser. En af afbrydelserne, som han indekserer for at nulstille til 0 hver gang den fuldender en revolution. Jeg vil bruge den til at spore en roterende mast til at finde retning. Der er stykker kode, men intet er komplet. Er din komplet? [email protected]

Svar

Re “ben 2 og 3 er forskellige. Jeg tror på Mega, at de er henholdsvis PORTH3 og PORTH4”, det er rigtigt, at Arduino digitale pins 2 og 3 hører til forskellige porte på Uno vs Mega2560-kort.

Mega2560 “har seks INTx-ben, mod to sådanne på Uno”. På Mega er INT0 … INT3 PD0 … PD3, og INT4, INT5 er PE4, PE5. På Uno er INT0, INT1 PD2, PD3. Bemærk, i et svar på Kan eksterne afbrydelser ELLER “d sammen på” 328 (Uno)? Jeg viser et par rutiner, der viser passende masker til stifter på forskellige Arduinos. Se afsnittene “Brug af andre ben til PCIer” og “ISR-framework-genererende skitse”.


Her er et par problemer med koden vist i spørgsmålet:

  1. aFlag initialiseres til nul og er aldrig sat nul i den viste kode. Så den første if betingelse i PinA() er aldrig opfyldt.

  2. PinA() er en afbrydningshåndterer, der er forbundet til afbrydelser ved hjælp af dine attachInterrupt() -opkald. Da hardware deaktiverer afbrydelser, før den går ind i en afbrydelsesbehandler, er der ikke behov for afbrydelsesadministratoren for at deaktivere afbrydelser. Slet cli() i PinA(). Slet på samme måde sei() i slutningen af PinA(), fordi hardware gendanner afbrydelsesstatus, når en RETI-instruktion udføres.

  3. Arduino-softwaremiljøet definerer konstanter som B00001100 med binære værdier, der matcher navnet. Det vil sige, i Arduino-softwaremiljøet har konstant B00001100 værdien 0B00001100. Efter min mening er den “en dum og unødvendig funktion. Jeg foreslår, at du i din kode bruger standard C-notation som 0B00001100, når du vil bruge binære konstante værdier.

  4. Jeg betragter skrivning af encoderPos -- i stedet for encoderPos-- som en perversion og foreslår at slette det unødvendige mellemrum.

  5. Da du ikke har vist PinB() interrupt handler, ved jeg ikke, hvordan du skulle håndtere encoderPos++ sag. At dømme ud fra den viste kode bruger du en metode, der ikke håndterer afvisnings- og intermitterende fejl korrekt. Jeg foreslår at bruge pin-change interrupts og en state-machine metode, som illustreret i svar på:
    Læsning fra en KY-040 roterende encoder med Digispark
    Hvordan læses RPS til hurtig rotation med statusændringsmetode i Arduino?
    Læs RC-modtagerkanaler ved hjælp af Interrupt i stedet for PulseIn
    Kan eksterne afbrydelser ELLER “d” sammen på “328 (Uno)?

Svar

På mega læste du pinene med PINE.

Så din kode i PinA ville ændre sig til:

 reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;  

I fandt en god diskussion, der talte om maskeringen, der kræves her: https://forum.arduino.cc/index.php?topic=561741.0

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *