Measure position
To implement the encoder position tracking using interrupts on the RP2040 (e.g., on a Raspberry Pi Pico), you can follow the approach you described. This involves:
Using interrupts: To trigger a function when output A of the encoder rises.
Volatile variable: To ensure the
posi
variable is properly shared between the loop and interrupt service routines (ISRs).Atomic operations: To safely read and modify the
posi
variable without interference from interrupts.
The volatile
keyword ensures that the compiler doesn’t optimize away accesses to posi
, and an atomic block (or its equivalent in RP2040) is used to prevent race conditions when reading or writing posi
during an interrupt.
#define ENCA 4 // GPIO pin for encoder output A (Yellow wire)
#define ENCB 5 // GPIO pin for encoder output B (White wire)
volatile int posi = 0; // Position variable (shared between ISR and loop)
void readEncoder(); // Function prototype for the ISR
void setup() {
Serial.begin(9600); // Begin serial communication
pinMode(ENCA, INPUT); // Set encoder A pin as input
pinMode(ENCB, INPUT); // Set encoder B pin as input
attachInterrupt(digitalPinToInterrupt(ENCA), readEncoder, RISING); // Attach interrupt to ENCA rising edge
}
void loop() {
// Safely read the position variable with atomic block to prevent interrupts during read
noInterrupts(); // Disable interrupts
int posiCopy = posi; // Copy the volatile variable
interrupts(); // Re-enable interrupts
Serial.println(posiCopy); // Print the current position
delay(100); // Small delay to avoid spamming the serial output
}
// Interrupt Service Routine (ISR) that triggers when ENCA rises
void readEncoder() {
// Read ENCB to determine the direction
if (digitalRead(ENCB) == HIGH) {
posi++; // If ENCB is HIGH, increment position
} else {
posi--; // If ENCB is LOW, decrement position
}
}
with classes
#define ENCA 4 // GPIO pin for encoder output A (Yellow wire)
#define ENCB 5 // GPIO pin for encoder output B (White wire)
// Encoder class to encapsulate encoder functionality
class Encoder {
private:
int pinA; // Pin for ENCA
int pinB; // Pin for ENCB
volatile int position; // Position variable to track the encoder's position
public:
// Constructor to initialize pins
Encoder(int encoderPinA, int encoderPinB) {
pinA = encoderPinA;
pinB = encoderPinB;
position = 0; // Initialize position to 0
// Set encoder pins as input
pinMode(pinA, INPUT);
pinMode(pinB, INPUT);
}
// Attach the interrupt to the encoder pin
void attachInterrupts(void (*isr)()) {
attachInterrupt(digitalPinToInterrupt(pinA), isr, RISING); // Interrupt on rising edge of ENCA
}
// Function to update the position (called in the ISR)
void updatePosition() {
if (digitalRead(pinB) == HIGH) {
position++; // Increment position if ENCB is HIGH
} else {
position--; // Decrement position if ENCB is LOW
}
}
// Safely read the position value
int getPosition() {
noInterrupts(); // Disable interrupts to safely read the volatile variable
int posCopy = position; // Copy the current position
interrupts(); // Re-enable interrupts
return posCopy; // Return the copied position
}
};
// Global instance of Encoder class
Encoder encoder(ENCA, ENCB);
// Interrupt Service Routine (ISR)
void readEncoderISR() {
encoder.updatePosition(); // Call the encoder's position update method
}
void setup() {
Serial.begin(9600); // Initialize serial communication
encoder.attachInterrupts(readEncoderISR); // Attach the interrupt for the encoder
}
void loop() {
// Read and print the encoder position
int currentPosition = encoder.getPosition(); // Safely read the encoder's position
Serial.println(currentPosition); // Print the current position to the serial monitor
delay(100); // Delay to avoid spamming the serial monitor
}
```
Last updated