Hello,
I have been working on finding the RPM of a motor using an optical encoder. I have a motor "maxon DC motor 9V 118742" connected to an encoder "Avago HEDS 5540#A02" by which I would need to know the number of revolutions the engine makes. I have an "Arduino Uno" and turning between the forum I understand how to make connections, but I have not found a code that worked. Could you help me write a code that works? Thank you.
Well you haven't presented any of the sketches you've already tried... Perhaps you should show us
one that you've tried so we can fix it or work out why.
You should be using the external interrupt for this application.
You have the 5540 model which has an index pulse on its pin #2. If you connect that to pin 2 or 3 of the UNO you should be able to read the count with an external interrupt.
There are many projects for tachometers and speedometers to be found.
With the motor you have the rpm should be high enough that simply counting the pulses over a fixed period of time might be accurate enough for your application. Here's very simple code which counts pulses for one second.
volatile unsigned long count = 0;
unsigned long copyCount = 0;
unsigned long lastRead = 0;
unsigned long interval = 1000;//one second
void setup()
{
Serial.begin(115200);
Serial.println("start...");
pinMode(2,INPUT_PULLUP);
attachInterrupt(0, isrCount, RISING); //interrupt signal to pin 2
}
void loop()
{
if (millis() - lastRead >= interval) //read interrupt count every second
{
lastRead += interval;
// disable interrupts,make copy of count,reenable interrupts
noInterrupts();
copyCount = count;
count = 0;
interrupts();
Serial.println(copyCount);
}
}
void isrCount()
{
count++;
}
Thank you cattledog!! With your code rotating by hand the motor I visualize the number of turns (which should be) corrected on the serial monitor. I will test this code when I provide a specific voltage value to the motor at the laboratory.
One last question: Do you know why when I turn from vertical position in the horizontal position the motor the value of speed varies by 2-3 orders of magnitude?
MarkT:
No it won't its not correct. The 'tick' variable should be declared volatile, and should be accessed from
the main sketch with interrupts disabled:
noInterrupts () ;
if (tick >= 360) // read and
{
tick = 0; // write access to tick is protected.
interrupts () ;
rpmPrint = rpm();
Serial.println(rpmPrint);
oldTimeMillis = timeMillis;
}
else
interrupts () ; // mustn't forget to enable interrupts again whatever the if condition.
Hi MarkT, I've tried to implement your correction, but there is something wrong in the code and I do not understand where. The complete code is below:
volatile int tick = 0;
int oldIn = 0;
int currentIn = 0;
float mins = 0;
float timeMillis = 0;
float oldTimeMillis = 0;
float rpmReturn = 0;
float rpmPrint;
void setup() {
// put your setup code here, to run once:
// attachInterrupt(digitalPinToInterrupt(2), readRPM, CHANGE);
pinMode(2, INPUT);
Serial.begin(9600);
}
void loop() {
currentIn = digitalRead(2);
if(currentIn != oldIn){
tick++;
}
timeMillis = millis();
noInterrupts () ;
if (tick >= 360) // read and
{
tick = 0; // write access to tick is protected.
interrupts () ;
rpmPrint = rpm();
Serial.println(rpmPrint);
oldTimeMillis = timeMillis;
}
else
interrupts () ; // mustn't forget to enable interrupts again whatever the if condition.
oldIn = currentIn;
}
void readRPM(){
tick++;
}
float rpm() {
timeMillis = timeMillis - oldTimeMillis;
mins = (timeMillis / 1000) / 60;
rpmReturn = 1/mins;
return rpmReturn;
}
cattledog:
You should be using the external interrupt for this application.
You have the 5540 model which has an index pulse on its pin #2. If you connect that to pin 2 or 3 of the UNO you should be able to read the count with an external interrupt.
There are many projects for tachometers and speedometers to be found.
With the motor you have the rpm should be high enough that simply counting the pulses over a fixed period of time might be accurate enough for your application. Here's very simple code which counts pulses for one second.
volatile unsigned long count = 0;
unsigned long copyCount = 0;
unsigned long lastRead = 0;
unsigned long interval = 1000;//one second
pinMode(2,INPUT_PULLUP);
attachInterrupt(0, isrCount, RISING); //interrupt signal to pin 2
}
void loop()
{
if (millis() - lastRead >= interval) //read interrupt count every second
{
lastRead += interval;
// disable interrupts,make copy of count,reenable interrupts
noInterrupts();
copyCount = count;
count = 0;
interrupts();
Serial.println(copyCount);
}
}
void isrCount()
{
count++;
}
Hi cattledog, I tried your code by connecting the motor to a voltage source and giving them input values from 2 to 5 volts, but I got completely the wrong values. Do you know why?
cattledog:
I do not think you are connected to the correct pins for GND(1), index(2), and Vcc(4). See figure 1 of the data sheet. http://docs.avagotech.com/docs/AV02-1046EN
Yes you are right! I've made the right connection and now everything works! Thank you so much.
adanilo90:
Yes you are right! I've made the right connection and now everything works! Thank you so much.
i mean this right connection , but thanks i saw the data sheet and apply it in my encoder .
i have another question please, i try to control my IAC and i don't know what is the suitable driver to connect with it and depending on what?
if any one know the electrical signal cable of IAC ( idle air control ) connect with driver motor , did you know what is the type of driver and it's connection with IAC and thanks