/****************************************************************
Project Title: Wheel Speed Measurement with LED Indicators
Target Hardware: ESP32
Summary: This project emulates two motor encoders using clock generators and logic gates. The ESP32 calculates RPM from encoder signals and uses LEDs to represent motor activity by blinking at rates corresponding to RPM.
****************************************************************/
// Define constants
#define ENC1A 34
#define ENC1B 35
#define ENC2A 32
#define ENC2B 33
#define LED1_PIN 13 // Green LED
#define LED2_PIN 12 // Red LED
#define PULSE_PER_REV 80
#define MILLI_PER_SEC 1000
#define SEC_PER_MIN 60
// Declare global variables for encoder 1 and encoder 2 calculations
volatile long count1 = 0;
volatile long count2 = 0;
float rpm1 = 0.0;
float rpm2 = 0.0;
unsigned long prevTime1 = 0;
unsigned long prevTime2 = 0;
// Variables for LED blinking
unsigned long lastBlinkTime1 = 0;
unsigned long blinkInterval1 = 1000; // Default blink interval when RPM is zero
bool ledState1 = false;
unsigned long lastBlinkTime2 = 0;
unsigned long blinkInterval2 = 1000; // Default blink interval when RPM is zero
bool ledState2 = false;
// Encoder 1 RPM ISR
void IRAM_ATTR ISR_Encoder1() {
// Determine direction and update count
if (digitalRead(ENC1B)) {
count1++;
} else {
count1--;
}
unsigned long currentTime = millis();
if (currentTime - prevTime1 >= 100) { // Update every 100 ms
float deltaTime = float(currentTime - prevTime1); // in ms
float deltaCount = float(count1);
rpm1 = (deltaCount / deltaTime) * (MILLI_PER_SEC * SEC_PER_MIN / PULSE_PER_REV);
count1 = 0;
prevTime1 = currentTime;
}
}
// Encoder 2 RPM ISR
void IRAM_ATTR ISR_Encoder2() {
// Determine direction and update count
if (digitalRead(ENC2B)) {
count2++;
} else {
count2--;
}
unsigned long currentTime = millis();
if (currentTime - prevTime2 >= 100) { // Update every 100 ms
float deltaTime = float(currentTime - prevTime2); // in ms
float deltaCount = float(count2);
rpm2 = (deltaCount / deltaTime) * (MILLI_PER_SEC * SEC_PER_MIN / PULSE_PER_REV);
count2 = 0;
prevTime2 = currentTime;
}
}
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
Serial.println("Hello, This is ESP32 Encoder RPM meter!");
// Initialize Encoder Pins as Inputs
pinMode(ENC1A, INPUT);
pinMode(ENC1B, INPUT);
pinMode(ENC2A, INPUT);
pinMode(ENC2B, INPUT);
// Initialize LED Pins as Outputs
pinMode(LED1_PIN, OUTPUT);
pinMode(LED2_PIN, OUTPUT);
// Initialize LEDs to OFF
digitalWrite(LED1_PIN, LOW);
digitalWrite(LED2_PIN, LOW);
// Attach Interrupts for Encoders
attachInterrupt(digitalPinToInterrupt(ENC1A), ISR_Encoder1, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENC2A), ISR_Encoder2, CHANGE);
}
void loop() {
unsigned long currentMillis = millis();
// Calculate blink intervals based on RPM
if (rpm1 > 0) {
blinkInterval1 = 60000 / (rpm1 * 2);
if (blinkInterval1 < 100) { // Cap to prevent too fast blinking
blinkInterval1 = 100;
}
} else {
blinkInterval1 = 1000; // Default when RPM is zero
}
if (rpm2 > 0) {
blinkInterval2 = 60000 / (rpm2 * 2);
if (blinkInterval2 < 100) { // Cap to prevent too fast blinking
blinkInterval2 = 100;
}
} else {
blinkInterval2 = 1000; // Default when RPM is zero
}
// Handle LED1 blinking (Green)
if (currentMillis - lastBlinkTime1 >= blinkInterval1) {
ledState1 = !ledState1;
digitalWrite(LED1_PIN, ledState1 ? HIGH : LOW);
lastBlinkTime1 = currentMillis;
}
// Handle LED2 blinking (Red)
if (currentMillis - lastBlinkTime2 >= blinkInterval2) {
ledState2 = !ledState2;
digitalWrite(LED2_PIN, ledState2 ? HIGH : LOW);
lastBlinkTime2 = currentMillis;
}
// Print RPM values to Serial Monitor
Serial.print("Enc1: ");
Serial.print(rpm1);
Serial.print(" RPM\tEnc2: ");
Serial.println(rpm2);
// No delay for better responsiveness
}