Hi, I'm trying to use Arduino in order to calculate RPM. I have at my disposal an IR phototransistor and IR LEDs.
The components are the following:
IR phototransistor: 3mm,SFH 309 FA-3/4 with 10k ohm resistor
IR LED: 5mm 870nm 10deg with 220 ohm resistor
The idea was to have a small reflector on the edge of the wheel, and to point both the IR LED and IR Phototransistor at the edge of the wheel. Every time the wheel does a revolution, the LED shines into the sensor, pretty self-explanatory.
I have tried many many different circuit configurations. It still doesn't work. I don't know if it's my code not working or I have the wrong components or my circuit that is wrong, or if it's the general approach of my code that is wrong. It keeps indicating that the RPM is 0 whatever I do.
I'm rather new at Arduino and electronics, I'm just getting started so bare with me please.
As extra info I have mostly used ChatGPT for this code.
// Define the pins
const int irLedPin = 7;
const int phototransistorPin = A0;
// Variables to store the RPM calculation
volatile unsigned long lastMillis = 0;
volatile unsigned int revolutions = 0;
unsigned long rpm = 0;
void setup() {
pinMode(irLedPin, OUTPUT);
pinMode(phototransistorPin, INPUT);
Serial.begin(9600);
// Attach an interrupt to the phototransistor pin
attachInterrupt(digitalPinToInterrupt(phototransistorPin), calculateRPM, RISING);
}
void loop() {
// Turn on the IR LED
digitalWrite(irLedPin, HIGH);
// Print RPM every second
if (millis() - lastMillis >= 1000) {
noInterrupts();
rpm = revolutions * 60; // Convert revolutions per second to RPM
revolutions = 0;
lastMillis = millis();
interrupts();
// Print the RPM value
Serial.print("RPM: ");
Serial.println(rpm);
}
}
// ISR to count revolutions
void calculateRPM() {
revolutions++;
}
Use pin 2 or 3 for the photo transistor insteadof A0. Only these pins can be configured for external interrupts on a Uno. A transistor does not have a cathode.
Unfortunately I'm still stuck with the same result, it stills shows me that RPM is 0 on the serial monitor, here's the new code using pin 2.
// Define the pins
const int irLedPin = 7;
const int phototransistorPin = 2; // Use pin 2 for the phototransistor
// Variables to store the RPM calculation
volatile unsigned long lastMillis = 0;
volatile unsigned int revolutions = 0;
unsigned long rpm = 0;
void setup() {
pinMode(irLedPin, OUTPUT);
pinMode(phototransistorPin, INPUT);
Serial.begin(9600);
// Attach an interrupt to the phototransistor pin
attachInterrupt(digitalPinToInterrupt(phototransistorPin), calculateRPM, RISING);
}
void loop() {
// Turn on the IR LED
digitalWrite(irLedPin, HIGH);
// Print RPM every second
if (millis() - lastMillis >= 1000) {
noInterrupts();
rpm = revolutions * 60; // Convert revolutions per second to RPM
revolutions = 0;
lastMillis = millis();
interrupts();
// Print the RPM value
Serial.print("RPM: ");
Serial.println(rpm);
}
}
// ISR to count revolutions
void calculateRPM() {
revolutions++;
}
I'm beginning to think about simply using different components, I simply no undertandin of where I'm wrong and it's frustrating me
Your layout seems perfect for testing this but these can possibly go wrong:
IR led
Ensure it is correctly wired.
You could even replace it with a red led but that must be nearer the photo transistor but at least you would see it glowing.
Photo transistor
Wrong polarity - just try changing the two connections and see what happens.
If the room is very bright, the photo transistor could already be saturated or light leaking from the led could already blind it.
Try disconnecting the led and reconnecting it which watching the serial console.
If all else fails, then connect the photo transistor to an analog pin and simply read it in the loop(). Something like:
You could modify your code to turn an LED on and off to indicate the state of the phototransistor's output. You can then use this to set-up your hardware.
Something like:
// Define the pins
const int irLedPin = 7;
const int phototransistorPin = 2; // Use pin 2 for the phototransistor
const int monitorPin = 13;
// Variables to store the RPM calculation
volatile unsigned long lastMillis = 0;
volatile unsigned int revolutions = 0;
unsigned long rpm = 0;
void setup() {
pinMode(irLedPin, OUTPUT);
pinMode(phototransistorPin, INPUT);
pinMode(monitorPin, OUTPUT);
Serial.begin(9600);
// Attach an interrupt to the phototransistor pin
attachInterrupt(digitalPinToInterrupt(phototransistorPin), calculateRPM, RISING);
// Turn on the IR LED
digitalWrite(irLedPin, HIGH);
}
void loop() {
// use monitorPin to indicate the state of the phototransistor
digitalWrite(monitorPin,(digitalRead(phototransistorPin)));
// Print RPM every second
if (millis() - lastMillis >= 1000) {
noInterrupts();
rpm = revolutions * 60; // Convert revolutions per second to RPM
revolutions = 0;
lastMillis = millis();
interrupts();
// Print the RPM value
Serial.print("RPM: ");
Serial.println(rpm);
}
}
// ISR to count revolutions
void calculateRPM() {
revolutions++;
}
I've used pin13 to use the internal LED on a Uno R3.
Note that I have moved the line that turns on the LED from loop() to setup() - you only need to turn it on once.
Channel 1 - yellow trace - Input signal to pin 2.
Channel 2 - red trace - monitorPin shows the state of the phototransistor.
Channel 3 - blue trace - Serial output from pin 1.
I've decided to restart everything and go step by step, and I've gotten the transistor to work.
Turns out I also had the transistor connected the wrong way...
I just used this simple wiring and code, this time using 5v to power the IR LED and not the digital pins.
and now using the same wiring, I now have a code that works for calculating RPM!
const int phototransistorPin = A0; // Pin for the phototransistor
const int threshold = 530; // Threshold value for detecting the reflective tape
volatile unsigned int revolutionCount = 0;
unsigned long lastMillis = 0;
unsigned long rpm = 0;
void setup() {
Serial.begin(115200);
pinMode(phototransistorPin, INPUT);
}
void loop() {
// Read the value from the phototransistor
int sensorValue = analogRead(phototransistorPin);
// Detect threshold crossing
static int lastSensorValue = sensorValue;
if (lastSensorValue > threshold && sensorValue <= threshold) {
revolutionCount++;
}
lastSensorValue = sensorValue;
// Calculate and print RPM every second
if (millis() - lastMillis >= 1000) {
noInterrupts(); // Disable interrupts while calculating RPM
rpm = revolutionCount * 60; // Convert revolutions per second to RPM
revolutionCount = 0;
lastMillis = millis();
interrupts(); // Re-enable interrupts
// Print RPM value
Serial.print("RPM: ");
Serial.println(rpm);
}
delay(10);
}
might need improvements, right now it's precision is low, only giving values in with a 60 interval, but this code will only be used for high rpms, from around 1500 to 3500. Thanks all for your help and if you have any suggestions feel free