Arduino Mega 2560 Interrupt-Pins und Port-Mapping mit Drehgeber

Ich versuche, die Port-Manipulation in Interrupts zum Lesen eines Drehgebers zu verwenden. Ich habe Code für ein Uno gefunden, daher sind die Portaufrufe für die Pins 2 und 3 unterschiedlich. Ich denke auf der Mega sind sie PORTH3 bzw. PORTH4. Mein Code funktioniert nicht. Habe ich meine Ports falsch? Ich habe versucht, dies nachzulesen, und ich verstehe den Bxxxxxxxx-Teil nicht vollständig. Ich denke, das könnte falsch sein. Hier ist ein Teil meines Codes mit einem der 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 } 

Kommentare

  • Haben Sie das jemals zum Laufen gebracht? Ich wollte auch einen Arduino Mega verwenden, um die Winkelposition eines Omron-Encoders mit 3 Interrupts zu verfolgen. Einer der Interrupts, damit der Index jedes Mal auf 0 zurückgesetzt wird Es vollendet eine Umdrehung. Ich möchte damit einen rotierenden Mast für die Peilung verfolgen. Es gibt Codeteile, aber nichts Vollständiges. Ist Ihr Code vollständig? [email protected]

Antwort

Zu „Pins 2 und 3 sind unterschiedlich. Ich denke, auf dem Mega sind sie PORTH3 bzw. PORTH4“, es ist wahr, dass Arduino Digital Pins 2 und 3 gehören zu verschiedenen Ports auf Uno vs Mega2560-Karten.

Mega2560 haben sechs INTx-Pins, gegenüber zwei solchen auf Uno-Karten. Auf dem Mega sind INT0 … INT3 PD0 … PD3 und INT4, INT5 sind PE4, PE5. Auf dem Uno sind INT0, INT1 PD2, PD3. Beachten Sie, dass in einer Antwort unter externe Interrupts auf dem „328 (Uno) ODER“ d zusammen sein können? Ich zeige einige Routinen, für die geeignete Masken angezeigt werden Stifte auf verschiedenen Arduinos. Weitere Informationen finden Sie in den Abschnitten „Verwenden anderer Pins für PCIs“ und „Skizze zum Generieren von ISR-Frameworks“.


Hier einige Probleme mit dem in der Frage gezeigten Code:

  1. aFlag wird auf Null initialisiert und im angezeigten Code niemals ungleich Null gesetzt. Die erste if Bedingung in PinA() wird also nie erfüllt.

  2. PinA() ist ein Interrupt-Handler, der durch Ihre attachInterrupt() -Aufrufe mit Interrupts verbunden ist. Da die Hardware Interrupts deaktiviert, bevor sie in einen Interrupt-Handler eingegeben wird, muss der Interrupt-Handler keine Interrupts ausschalten. Löschen Sie also cli() in PinA(). Löschen Sie in ähnlicher Weise die sei() am Ende von PinA(), da die Hardware den Interrupt-Status wiederherstellt, wenn ein RETI-Befehl ausgeführt wird.

  3. Die Arduino-Softwareumgebung definiert Konstanten wie B00001100 mit Binärwerten, die dem Namen entsprechen. Das heißt, in der Arduino-Softwareumgebung hat die Konstante B00001100 den Wert 0B00001100. Meiner Meinung nach ist dies eine dumme und unnötige Funktion. Ich schlage vor, dass Sie in Ihrem Code die Standard-C-Notation wie 0B00001100 verwenden, wenn Sie binäre Konstantenwerte verwenden möchten.

  4. Ich betrachte das Schreiben von encoderPos -- anstelle von encoderPos-- als Perversion und schlage vor, diesen unnötigen Speicherplatz zu löschen.

  5. Da Sie den Interrupt-Handler PinB() nicht angezeigt haben, weiß ich nicht, wie Sie mit der encoderPos++ case. Nach dem angezeigten Code zu urteilen, verwenden Sie eine Methode, die Bounce- und intermittierende Fehler nicht korrekt behandelt. Ich schlage vor, Pin-Change-Interrupts und eine State-Machine-Methode zu verwenden, wie in den Antworten auf Folgendes dargestellt:
    Lesen von einem KY-040-Drehgeber mit Digispark
    Wie lese ich RPS für eine schnelle Rotation mit der Statusänderungsmethode in Arduino?
    Lesen Sie RC-Empfängerkanäle mit Interrupt anstelle von PulseIn
    Können externe Interrupts auf dem „328 (Uno) zusammen ODER“ d „sein?

Antwort

Auf dem Mega haben Sie die Pins mit PINE gelesen.

Ihr Code in PinA würde sich also ändern zu:

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

I. Ich habe eine großartige Diskussion über die hier erforderliche Maskierung gefunden: https://forum.arduino.cc/index.php?topic=561741.0

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.