Arduino Mega 2560 interrupción de pines y mapeo de puertos con codificador rotatorio

Estoy tratando de usar la manipulación de puertos en interrupciones para leer un codificador rotatorio. Encontré el código para un Uno, por lo que la llamada de puerto para los pines 2 y 3 es diferente. Creo que en Mega son PORTH3 y PORTH4 respectivamente. Mi código no funciona. ¿Tengo mis puertos mal? He intentado leer sobre esto y no entiendo completamente la parte Bxxxxxxxx. Creo que eso podría ser lo incorrecto. Aquí está parte de mi código con una de las interrupciones.

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 } 

Comentarios

  • ¿Alguna vez consiguió que esto funcione? Yo también he querido usar un Arduino Mega para rastrear la posición angular de un codificador Omron con 3 interrupciones. Una de las interrupciones para que el índice se restablezca a 0 cada vez completa una revolución. Quiero usarlo para rastrear un mástil giratorio para buscar direcciones. Hay fragmentos de código pero nada completo. ¿Está completo el tuyo? [email protected]

Respuesta

Re «Los pines 2 y 3 son diferentes. Creo que en el Mega son PORTH3 y PORTH4 respectivamente», es cierto que los pines digitales 2 de Arduino y 3 pertenecen a diferentes puertos en las placas Uno vs Mega2560.

Los Mega2560 «tienen seis pines INTx, en comparación con dos de estos en Uno». En el Mega, INT0 … INT3 son PD0 … PD3, e INT4, INT5 son PE4, PE5. En el Uno, INT0, INT1 son PD2, PD3. Tenga en cuenta que en una respuesta en ¿Las interrupciones externas se pueden combinar en el «328 (Uno)»? Muestro un par de rutinas que mostrarán máscaras apropiadas para pines en diferentes Arduinos. Consulte las secciones «Uso de otros pines para PCI» y «Sketch de generación de marco ISR».


Aquí hay algunos problemas con el código que se muestra en la pregunta:

  1. aFlag se inicializa en cero y nunca se establece en un valor distinto de cero en el código que se muestra. Por lo tanto, la primera if condición en PinA() nunca se cumple.

  2. PinA() es un controlador de interrupciones, conectado a las interrupciones por sus llamadas attachInterrupt(). Debido a que el hardware deshabilita las interrupciones antes de ingresar a un controlador de interrupciones, no es necesario que el controlador de interrupciones desactive las interrupciones. Es decir, elimine cli() en PinA(). De manera similar, elimine sei() al final de PinA() porque el hardware restaura el estado de interrupción cuando se ejecuta una instrucción RETI.

  3. El entorno del software Arduino define constantes como B00001100 con valores binarios que coinciden con el nombre. Es decir, en el entorno de software Arduino, la constante B00001100 tiene el valor 0B00001100. En mi opinión, esa «es una característica estúpida e innecesaria; sugiero que en su código use la notación C estándar como 0B00001100 cuando quiera usar valores constantes binarios.

  4. Considero que escribir encoderPos -- en lugar de encoderPos-- es una perversión y sugiero eliminar ese espacio innecesario.

  5. Como no ha mostrado el PinB() controlador de interrupciones, no sé cómo iba a manejar el encoderPos++. A juzgar por el código que se muestra, está utilizando un método que no maneja correctamente el rebote y los errores intermitentes. Sugiero usar interrupciones de cambio de pin y un método de máquina de estado, como se ilustra en las respuestas a:
    Lectura de un codificador rotatorio KY-040 con Digispark
    ¿Cómo leer RPS para una rotación rápida con el método de cambio de estado en Arduino?
    Leer los canales del receptor RC usando Interrupt en lugar de PulseIn
    ¿Pueden las interrupciones externas ser OR «d juntas en» 328 (Uno)?

Responder

En el mega, leerías los pines con PINE.

Entonces, su código en PinA cambiaría a:

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

I encontré una excelente discusión sobre el enmascaramiento requerido aquí: https://forum.arduino.cc/index.php?topic=561741.0

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *