Calculating RPM's... Problem in code...

Well…

int cath = 2;//negative of the reciver
int ando = 3;//positive of the reciver
int rpm = 0;//the RPM's variable
int revolutions = 0;//the variable for counting revolutions 
int go = false;
unsigned long count = 0;//the variable for counting the code loops
unsigned long max_count = 0;//the loops in a second

void setup()
 {
   pinMode(cath, OUTPUT);
   pinMode(ando, OUTPUT);
   Serial.begin(9600);
   Serial.println("Started...");  
 }

void loop()
 {
   //for the sensor
   
  if(millis()<=1000)
  {
    max_count++;//increments it
     Serial.println("Calculating loops... Please wait...");//sends serial data to make timing accurate
  }
  else//we finished counting the loops in a second, 
  {
    go = true;//we can start calculating RPM's
  }
  
   digitalWrite(cath, LOW);
   digitalWrite(ando, HIGH);
   digitalWrite(cath, HIGH);
   digitalWrite(ando, LOW);
   pinMode(ando, INPUT);
   
   if(go==true)//if we must start calculating RPM's
   {
   if(count<=max_count)//if we looped for less than about a second
   {
     count++;//increment it
     if(digitalRead(ando) == LOW)//check if we got a revolution
     {
       //off, and that means we got a revolution
       revolutions++;//increment it
       Serial.print("Revolution Count: ");  
       Serial.println(count); 
     }
   }
   else//if we've been 
   {
     count = 0;//reset it
     rpm = revolutions * 60;//calculates the RPM's
     //output the RPM's
     Serial.print("RPM's: ");    
     Serial.println(rpm);  
   }
   }
    pinMode(ando, OUTPUT);
 }

That is what I have, The problem is finding how many times the program runs in loops within a second.
I’m puzzled, Any ideas? What i need is a statement that is valid within the same second since it was first run, Then it waits a second and reruns.
Thanks
~ReCreate

If I understand the code, you first try calibrate how many loops you can do in a second by watching millis() then run a loop for your estimated second counting transitions - right? I’m pretty sure you can’t get a useful result that way because the time for a loop depends on what’s inside it.

As one suggestion to time a second try something like your first loop with the transition count in it:

unsigned int begintime=millis();
while (millis<begintime+1000){
  count your transitions
}
calculate your rpms

you may find this ok but it will freeze your code for a second and, you’ll have an error rate of several percent at realistic rpms.

Another approach is maybe

unsigned long begintime=millis();
while (transitioncount<=10){
  count your transitions
}
unsigned long timefortentransitions=millis()-begintime;
calculate your rpms

this will be quicker and maybe more accurate depending on how many transitions you count.

Yes, that is what it does, I am having a hard time understanding what you mean about your post though, Could you show me what you mean?
I am on the brink of giving up…

I give up.

If you are looking for an instantaneous rpm value, you need to note when one signal occurs. Then, when the next signal occurs, note the time. The 1 rev/elapsed time value can be used to determine the number of revolutions that would occur in one minute, if they all took the same length of time.

If you are looking at average rpm over some period of time, count the number of revolutions in that period of time.

If you need help with writing the code, describe what you want to accomplish, what you have accomplished, and what is right (and wrong) about what you have accomplished. It's not that hard (if you have 30 years pf programming experience).

But, don't give up! :wink:

I think what your trying to do is better served with a different approach. I have some RPM calc code working on a Mega that uses interrupts to capture a digital input event (cath or ando in your app), and another interrupt to watch for timer rollovers.

With these I calculate the period time of 1 revolution every time the digital interrupt occurs like this...

Period_Ticks = Timer_Value + Timer_Max * RolloverCount;
Timer_value = 0; // note that this implementation requires a reset of one of the onboard timers... can't use the same one used for millis()
RPM = const_K * Period_Ticks;
RolloverCount = 0;

And in the rollover interrupt code...

RolloverCount++;

Is this what your after or have I missed the mark?

Ok I have to admit, I didn’t give up, And to be honest, I can’t >.<.
Anyways, what i want to be able to have a timer that counts to a second that can be reset, like millis, Is there any way to reset it back to 0?

I implemented an RPM calculator with a Hall effect sensor on the frame, without using interrupts.

I offer an extract of my code below. This compiles, but I haven't tested this exact version. The program from which it was taken does work, though.

// a bike RPM calculator
// Andrew Davidson

const int magSensorPin  = 53;       // digital - Hall effect
const int revFlashPin   = 12;      // indicator LED for each revolution

const int magnetIn = LOW;      // sensor value when magnet is in range
const int magnetOut = HIGH;      // sensor value when magnet is out of range

const int revTimeout = 3000;      // if no revs in this period, wheel has stopped (ms)

int curMagState  = magnetOut;      // current state of the magnet sensor
int prevMagState = magnetOut;       // prior state of the magnet sensor

long curRevTime;            // clock time of the latest pass of the magnet
long prevRevTime;            // clock time of the prior pass of the magnet

long  revCount = 0;            // number of revolutions we've seen
int   magRPM = 0;            // RPMs of the latest pass (revolution) of the magnet


void setup () {
  pinMode (magSensorPin, INPUT);
  pinMode (revFlashPin, OUTPUT);
}

void loop () {

  //..... do other stuff


  // check the magnet sensor on the rotating wheel

  curMagState = digitalRead (magSensorPin);

  if (curMagState != prevMagState) {

    // something has changed

    if (curMagState == magnetIn) {

      // we've just detected the start of a new revolution
      // (call out the troops!)

      // count it and turn on an LED to indicate it

      revCount++;
      digitalWrite (revFlashPin, true);

      // remember this moment

      curRevTime = millis ();

      // and see how long it has been since the last revolution

      long thisRev = curRevTime - prevRevTime;

      // calculate the RPMs from the time of this latest revolution

      // 1 minute = 60 * 1000 ms
      // RPM = ms/min / ms/rev

      magRPM = 60000 / thisRev;

      // and remember the interval for the next time

      prevRevTime = curRevTime;

    }   

    else  

      // the magnet has just left the sensor's range,
      // so turn off the indicator LED

    digitalWrite (revFlashPin, false);
    
  }

  else

    // no change in magnet state, but check
    // to see if pedaling has stopped by comparing the
    // interval since the last revolution against a
    // timeout value

      if ((millis () - prevRevTime) > revTimeout) {

      // wheel has stopped rotating

      magRPM = 0;

    }


  // remember the current state of the magnet for next time

  prevMagState = curMagState;

  //......
  // and go do other stuff

}

Perhaps it could be useful to you.

.andy

Oh...Hmmm...thanks...
But I'm not sure if it will be useful to me...
But can someone please tell me how I can do what I asked?
Edit:100 post! :smiley:
Edit2:http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200662708/2#2

Anyways, what i want to be able to have a timer that counts to a second that can be reset, like millis, Is there any way to reset it back to 0?

Yes it is possible. You could hijack Timer1 to do this for you by operating it in Clear Timer on Compare mode (CTC) with a prescaler. Here is the setup...

TCCR1A = 0;
TCCR1B = B00001100;  // CTC mode, prescaler = clk/8
OCR1A = 62500;  // 62500 * 256 = 16 million system clock ticks = 1 second
TIMSK1 = B00000010;  // enable interrupt for OCR1A compare match

What this does is tells timer #1 to count at a rate of 1/256th the system clock, so every 256 system clock ticks, Timer 1 increments by 1. It counts to 62500, generates an Output Compare match interrupt to say "hey, I've reached 62500!!!". Then it resets itself to 0 and repeats.

If you use the above you also must define the interrupt handler or your Atmel will hang (generating an interrupt without a handler goes to nowhere = full logic stop). Here is an interrupt handler that could be used with the above...

ISR(TIMER1_COMPA_vect) { 
  sei();
  // what do you want to do now?
  cli();
};

If you want to reset Timer1 (or set it to any other value for that matter, just do this wherever you want...

TCNT1 = 0;  // or any other int value

Be forewarned, this is code performs direct register address assignment and bypasses all the wonderful preventive measures written into the Arduino environment. It might conflict with a past or present library.

Having said all this, I'm not sure this is getting you to your solution. Wrapping a timer every 1 second is still a long way away from calculating an RPM at reasonable accuracy. In fact I'm thinking now your trying to trigger your calculation on a whole unit of time (every second). You should think to trigger your calculation on each unit of revolution.

So...I just add those code snips to my code and it will reset it?

Can't say for sure, I haven't studied your code. To be honest you kind of lost me and I'm not perfectly clear on exactly what you're trying to accomplish.

I did forget to mention too, best place to learn about these timers is in the atmega datasheet...

Chapter 15.

What I want is to reset whatever millis returns back to 0, as if the arduino was reset.

The millis function is not designed to be reset and although there are hacks that can be used, they could easily break in a future Arduino release. There is almost certainly a better way to do what you need.

Perhaps if you explained more about why you want to reset millis then people could contribute solutions that are best suited for your application.

From your first post it sounds like you want to calibrate some timing. Could you say more about this?

Well, What i wanted is to have some sort of counter that counts to 1 second, and then resets, And for me to be able to know exactly where the timer is at.
So i tried to find out how many loops are in 1 second doing that, So It would loop until it reaches the amount of loops that are equivalent to a second, But that didn't work too well...

You could try something like this:

counter = millis() % 1000;

Hmmm... Can you explain that? I don't see how that would work...

the value of counter will increase from 0 (when millis is 0) to 1000 and start over from 0 each second.

the % operator take the modulus of a number. In this case its the remainder after millis is divided by 1000 (the number of milliseconds in a second).

try it - put it in a sketch and print the value to the serial monitor.

Oh, neat thanks!

Ok so i have this

int cath = 2;//negative of the reciver
int ando = 3;//positive of the reciver
int rpm = 0;//the RPM's variable
int revolutions = 0;//the variable for counting revolutions 
int go = false;
int count = 0;//the variable for counting the code loops

void setup()
 {
   pinMode(cath, OUTPUT);
   pinMode(ando, OUTPUT);
   pinMode(13,OUTPUT);
   digitalWrite(13,HIGH);
   Serial.begin(9600);
   Serial.println("Started...");  
 }

void loop()
 {
   digitalWrite(cath, LOW);
   digitalWrite(ando, HIGH);
   digitalWrite(cath, HIGH);
   digitalWrite(ando, LOW);
   pinMode(ando, INPUT);
   
   count =  millis() % 1000; 
   
   //Serial.println(digitalRead(ando));//just show me what is getting recived
   if(count<=999)//if we looped for less than about a second
   {
     if(digitalRead(ando) == LOW)//check if we got a revolution
     {
       //off, and that means we got a revolution
       revolutions++;//increment it
     }
   }
   else//if we've been 
   {
     rpm = revolutions * 60;//calculates the RPM's
     //output the RPM's
     Serial.print("RPM's: ");    
     Serial.println(rpm);  

   }
    pinMode(ando, OUTPUT);
 }

And it does not work, It is never reaching 1000, This is really getting damn frustrating, Nothings working, Any ideas?