Problem with bike speedometer

HI GUYS, I have problem with speedometer and I looked many tutorials but most of them missed my problem. When I use below code in Arduino and bring sensor to near magnet speed is change which is good however if I away magnet from sensor, speed stays higher value which is not correct(it has to go 0 value) now I think that something wrong with this tutorials. any help will save my day

this example from https://www.instructables.com/id/Arduino-Bike-Speedometer/

// pin connected to reed switch
#define reed 11

int reedVal;
int maxDebounceTicks = 100;
int currentDebounceTicks;
int time = 0;
// the wheel radius, in kilometers
float radius = 0.0003556;
float circumference;
float velocity = 0.00;
float distance = 0.00;

// initialize LCD with the numbers of the interface pins


void setup() {
  // set up the LCD's number of columns and rows


  Serial.begin(9600);

  currentDebounceTicks = maxDebounceTicks;

  circumference = 2 * 3.14 * radius;

  pinMode(reed, INPUT);

  cli();

  // set entire TCCR1A register to 0
  TCCR1A = 0;

  // set entire TCCR1B register to 0
  TCCR1B = 0;

  // initialize counter value to 0;
  TCNT1  = 0;

  // set timer count for 1khz increments
  // = (16*10^6) / (1000*8) - 1
  OCR1A = 1999;

  // turn on CTC mode
  TCCR1B |= (1 << WGM12);

  // Set CS11 bit for 8 prescaler
  TCCR1B |= (1 << CS11);

  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

  sei();
}

void loop() {
  displayText();
  delay(100);
}

ISR(TIMER1_COMPA_vect) {
  reedVal = digitalRead(reed);
  if (reedVal) {
    // wait the given number of ticks, before calculating the velocity
    if (currentDebounceTicks == 0) {
      // circumference in kilometers, time in hours
      velocity = circumference/((float)time/3600000);
      time = 0;
      currentDebounceTicks = maxDebounceTicks;
      distance = distance + circumference;

    } else {
      if (currentDebounceTicks > 0) {
        currentDebounceTicks -= 1;
      }
    }
  } else {
    if (currentDebounceTicks > 0) {
      currentDebounceTicks -= 1;
    }
    
  }

  if (time > 2000) {
    // set velocity to 0 when tire is still for 2 seconds
    velocity = 0;
  } else {
    time += 1;
   
  }
}

void displayText(){

//  Serial.println(int(velocity));
// Serial.println(" km/h");
//
//  if (distance > 1) {
//   Serial.println(distance);
//    Serial.println(" km");
//  }
//   else {
//    Serial.println(int(distance * 1000));
//    Serial.println(" m");
//  }

  Serial.println(velocity);
//  Serial.println(distance);
}

(deleted)

spycatcher2k:
Do you have a pull down resistor on your sensor? This would be needed if it does not have one of its own.

OFF COURSE I prevented floating with resistor

Hi Arkadas,

this code makes direct use of timer and counter registers. This really is nothing for beginners.
If you want to use this code. You just have to have the exact same hardware as at instructables
in every detail compile the code upload it and be satisfied what this codeversion can do.
As a beginner never ask how to modify this code.

Of course as a real beginner you cannot know that this code works this way.
That' why I'm writing it.

I guess your hardware is different from what in the instrucables-manual is used.

If you just need a bike-speedo-meter go buy a ready to use product.

If you want to learn how programming works this code is really the wrong one to start with.
You have to know a lot of about timers and counters on the low hardware-levek and their different modes of operation.
I estimate only the most sophisticated 10% of all arduino-users here in the can work on this level of using timer-registers etc.

It will be much much easier to learn the basics of programming and writing a code that does the same thing
but with the use of functions like millis()

I recommend reading this tutorial

Arduino Programming Course

It is easy to understand and a good mixture between writing about important concepts
and get you going.

Somehow lately there are a lot of total-nooby-questions in a style of "can you write the code for me?"
So I have the impression lately some teachers told their students:
"here's your homework of programming an Arduino come back in four weeks with your code running"

to compare learning programming with a allday-situation

imagine you want to learn to ride a bike.
You have looked at somebody who is doing it
and think AH! I understand sit on the saddle put your hands on the handlebars
and kick your feet down and then it is moving.

You know from your own experience that's not all.

  • You have to learn how to put the pedal in a certain position to start,
  • you have to learn where is the brake,
  • you have to learn how to shift gears

you have to practice BALANCING on the bike with your OWN BODY

it is similar with learning to program

You have to learn some basics. You have to practice

Asking here in the forum in this style

"I have this code here but it does not do what it should" End of message

is like you fell off the bike and then go to a experienced biker
telling him "I was unable to ride the bike" can YOU drive my bike for 200 meters to get me going?"

Makes no sense at all. It's the same thing with programming.

Though the difference is your "programming"-Bike has fivehundred wheels, fifty pedals, eighty gearshifting-levers
five handlebars etc.

For starting to move (=programming) it is enough to get explained use handlebar number three, pedals number 27 and wheels 1,2,3 and 4.

But that's a different execise than doing a backflip in the halfpipe. You simple don't start freestyle BMX-ing with backflips in the halfpipe. You start with basic exercises. It's the same thing with learning programming. You start with small exercises.

best regards Stefan

StefanL38:
Hi Arkadas,

this code makes direct use of timer and counter registers. This really is nothing for beginners.
If you want to use this code. You just have to have the exact same hardware as at instructables
in every detail compile the code upload it and be satisfied what this codeversion can do.
As a beginner never ask how to modify this code.

Of course as a real beginner you cannot know that this code works this way.
That' why I'm writing it.

I guess your hardware is different from what in the instrucables-manual is used.

If you just need a bike-speedo-meter go buy a ready to use product.

If you want to learn how programming works this code is really the wrong one to start with.
You have to know a lot of about timers and counters on the low hardware-levek and their different modes of operation.
I estimate only the most sophisticated 10% of all arduino-users here in the can work on this level of using timer-registers etc.

It will be much much easier to learn the basics of programming and writing a code that does the same thing
but with the use of functions like millis()

I recommend reading this tutorial

Arduino Programming Course
Arduino Programming Course Contents

It is easy to understand and a good mixture between writing about important concepts
and get you going.

Somehow lately there are a lot of total-nooby-questions in a style of "can you write the code for me?"
So I have the impression lately some teachers told their students:
"here's your homework of programming an Arduino come back in four weeks with your code running"

to compare learning programming with a allday-situation

imagine you want to learn to ride a bike.
You have looked at somebody who is doing it
and think AH! I understand sit on the saddle put your hands on the handlebars
and kick your feet down and then it is moving.

You know from your own experience that's not all.

  • You have to learn how to put the pedal in a certain position to start,
  • you have to learn where is the brake,
  • you have to learn how to shift gears

you have to practice BALANCING on the bike with your OWN BODY

it is similar with learning to program

You have to learn some basics. You have to practice

Asking here in the forum in this style

"I have this code here but it does not do what it should" End of message

is like you fell off the bike and then go to a experienced biker
telling him "I was unable to ride the bike" can YOU drive my bike for 200 meters to get me going?"

Makes no sense at all. It's the same thing with programming.

Though the difference is your "programming"-Bike has fivehundred wheels, fifty pedals, eighty gearshifting-levers
five handlebars etc.

For starting to move (=programming) it is enough to get explained use handlebar number three, pedals number 27 and wheels 1,2,3 and 4.

But that's a different execise than doing a backflip in the halfpipe. You simple don't start freestyle BMX-ing with backflips in the halfpipe. You start with basic exercises. It's the same thing with learning programming. You start with small exercises.

best regards Stefan

hı thanks for your comment but this not related to hardware. ı most reed switch have same principle

The whole 'debounce' counter thing looks confusing to me. Here is a re-write that uses a more traditional form of state change detection and debounce. I also added some comments to make the logic more clear.

// pin connected to reed switch
const byte ReedPin = 11;
// the wheel radius and circumference, in kilometers
const float WheelRadius = 0.0003556;
const float WheelCircumference = 2 * PI * WheelRadius;
const float KPHconst = WheelCircumference * 3600000.0; // Killometers per hour at 1 revolution per millisecond.


const unsigned DebounceTime = 10;  // Milliseconds of bouncing to ignore


unsigned TickCounter = 0;


// Shared with the ISR.  Must mark as 'volatile' so the compiler knows
// they can change at any time
volatile float CurrentVelocity = 0.00; // kph
volatile float TotalDistance = 0.00; // km


void setup()
{
  Serial.begin(9600);


  pinMode(ReedPin, INPUT);


  noInterrupts();


  // set entire TCCR1A register to 0
  TCCR1A = 0;


  // set entire TCCR1B register to 0
  TCCR1B = 0;


  // initialize counter value to 0;
  TCNT1  = 0;


  // set to Waveform Generation Mode 4 (CTC mode, TOP is in OCR1A)
  TCCR1B |= (1 << WGM12);


  // set TOP for 1kHz interrupts
  // = (16*10^6) / (1000*8) - 1
  OCR1A = 1999;


  // Set CS11 bit for 8 prescaler (2 MHz clock)
  TCCR1B |= (1 << CS11);


  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);


  interrupts();
}


void loop()
{
  displayText();
  delay(100);
}


// Interrupt occurs every millisecond
ISR(TIMER1_COMPA_vect)
{
  static unsigned long lastStateChangeTime = 0;
  static boolean reedWasClosed = false;


  unsigned long currentTime = millis();
  boolean reedIsClosed = digitalRead(ReedPin);


  // Check for state change
  if (reedIsClosed != reedWasClosed && currentTime - lastStateChangeTime > DebounceTime)
  {
    reedWasClosed = reedIsClosed;
    lastStateChangeTime = currentTime;
    if (reedIsClosed)
    {
      // Reed Has Just Closed
      TotalDistance += WheelCircumference;


      // KPHconst is KPH at 1 revolution per tick.
      CurrentVelocity = KPHconst / TickCounter;
      TickCounter = 0;
    }
  }


  // Count milliseconds unless the wheel has stopped
  if (TickCounter > 2000)
  {
    // set velocity to 0 when tire is still for 2 seconds
    CurrentVelocity = 0;
  }
  else
  {
    TickCounter++;
  }
}


void displayText()
{
  // Because 'volatile' variables can change any time interrupts are enabled
  // we have to make local copies while interrupts are disabled.  If we don't
  // the value of the variable might change half-way through fetching!
  float localTotalDistance;
  float localCurrentVelocity;
  noInterrupts();
  localTotalDistance = TotalDistance;
  localCurrentVelocity = CurrentVelocity;
  interrupts();


  //  Serial.print(int(localCurrentVelocity));
  //  Serial.println(" km/h");
  //
  //  if (TotalDistance > 1) {
  //   Serial.print(localTotalDistance);
  //    Serial.println(" km");
  //  }
  //   else {
  //    Serial.print(int(localTotalDistance * 1000.0));
  //    Serial.println(" m");
  //  }


  Serial.println(localCurrentVelocity);
  //  Serial.println(localTotalDistance);
}

johnwasser:
The whole 'debounce' counter thing looks confusing to me. Here is a re-write that uses a more traditional form of state change detection and debounce. I also added some comments to make the logic more clear.

// pin connected to reed switch

const byte ReedPin = 11;
// the wheel radius and circumference, in kilometers
const float WheelRadius = 0.0003556;
const float WheelCircumference = 2 * PI * WheelRadius;
const float KPHconst = WheelCircumference * 3600000.0; // Killometers per hour at 1 revolution per millisecond.

const unsigned DebounceTime = 10;  // Milliseconds of bouncing to ignore

unsigned TickCounter = 0;

// Shared with the ISR.  Must mark as 'volatile' so the compiler knows
// they can change at any time
volatile float CurrentVelocity = 0.00; // kph
volatile float TotalDistance = 0.00; // km

void setup()
{
 Serial.begin(9600);

pinMode(ReedPin, INPUT);

noInterrupts();

// set entire TCCR1A register to 0
 TCCR1A = 0;

// set entire TCCR1B register to 0
 TCCR1B = 0;

// initialize counter value to 0;
 TCNT1  = 0;

// set to Waveform Generation Mode 4 (CTC mode, TOP is in OCR1A)
 TCCR1B |= (1 << WGM12);

// set TOP for 1kHz interrupts
 // = (1610^6) / (10008) - 1
 OCR1A = 1999;

// Set CS11 bit for 8 prescaler (2 MHz clock)
 TCCR1B |= (1 << CS11);

// enable timer compare interrupt
 TIMSK1 |= (1 << OCIE1A);

interrupts();
}

void loop()
{
 displayText();
 delay(100);
}

// Interrupt occurs every millisecond
ISR(TIMER1_COMPA_vect)
{
 static unsigned long lastStateChangeTime = 0;
 static boolean reedWasClosed = false;

unsigned long currentTime = millis();
 boolean reedIsClosed = digitalRead(ReedPin);

// Check for state change
 if (reedIsClosed != reedWasClosed && currentTime - lastStateChangeTime > DebounceTime)
 {
   reedWasClosed = reedIsClosed;
   lastStateChangeTime = currentTime;
   if (reedIsClosed)
   {
     // Reed Has Just Closed
     TotalDistance += WheelCircumference;

// KPHconst is KPH at 1 revolution per tick.
     CurrentVelocity = KPHconst / TickCounter;
     TickCounter = 0;
   }
 }

// Count milliseconds unless the wheel has stopped
 if (TickCounter > 2000)
 {
   // set velocity to 0 when tire is still for 2 seconds
   CurrentVelocity = 0;
 }
 else
 {
   TickCounter++;
 }
}

void displayText()
{
 // Because 'volatile' variables can change any time interrupts are enabled
 // we have to make local copies while interrupts are disables.  If we don't
 // the value of the variable might change half-way thourgh fetching!
 float localTotalDistance;
 float localCurrentVelocity;
 noInterrupts();
 localTotalDistance = TotalDistance;
 localCurrentVelocity = CurrentVelocity;
 interrupts();

//  Serial.print(int(localCurrentVelocity));
 //  Serial.println(" km/h");
 //
 //  if (TotalDistance > 1) {
 //   Serial.print(localTotalDistance);
 //    Serial.println(" km");
 //  }
 //   else {
 //    Serial.print(int(localTotalDistance * 1000.0));
 //    Serial.println(" m");
 //  }

Serial.println(localCurrentVelocity);
 //  Serial.println(localTotalDistance);
}

YES you catch the error. problem was state change detection. previous code prints velocity value, when reed pin is high so this will cause to problem ı corrected code below also I will write admin of instructable website.

int currentState;         
int lastState = 0;  
ISR(TIMER1_COMPA_vect) {
  currentState = digitalRead(reed);
  if (currentState != lastState && currentState == HIGH) {
    // wait the given number of ticks, before calculating the velocity
    if (currentDebounceTicks == 0) {

        velocity = circumference/((float)time/3600000);
      time = 0;
      currentDebounceTicks = maxDebounceTicks;
      distance = distance + circumference;

    } else {
      if (currentDebounceTicks > 0) {
        currentDebounceTicks -= 1;
      }
    }
  }else {
    if (currentDebounceTicks > 0) {
      currentDebounceTicks -= 1;
    }
    
  }

  lastState = currentState;

  if (time > 2000) {
    // set velocity to 0 when tire is still for 2 seconds
    velocity = 0;
    
  } else {
    time += 1;
   
  }
}

johnwasser:
The whole 'debounce' counter thing looks confusing to me. Here is a re-write that uses a more traditional form of state change detection and debounce. I also added some comments to make the logic more clear.

// pin connected to reed switch

const byte ReedPin = 11;
// the wheel radius and circumference, in kilometers
const float WheelRadius = 0.0003556;
const float WheelCircumference = 2 * PI * WheelRadius;
const float KPHconst = WheelCircumference * 3600000.0; // Killometers per hour at 1 revolution per millisecond.

const unsigned DebounceTime = 10;  // Milliseconds of bouncing to ignore

unsigned TickCounter = 0;

// Shared with the ISR.  Must mark as 'volatile' so the compiler knows
// they can change at any time
volatile float CurrentVelocity = 0.00; // kph
volatile float TotalDistance = 0.00; // km

void setup()
{
 Serial.begin(9600);

pinMode(ReedPin, INPUT);

noInterrupts();

// set entire TCCR1A register to 0
 TCCR1A = 0;

// set entire TCCR1B register to 0
 TCCR1B = 0;

// initialize counter value to 0;
 TCNT1  = 0;

// set to Waveform Generation Mode 4 (CTC mode, TOP is in OCR1A)
 TCCR1B |= (1 << WGM12);

// set TOP for 1kHz interrupts
 // = (1610^6) / (10008) - 1
 OCR1A = 1999;

// Set CS11 bit for 8 prescaler (2 MHz clock)
 TCCR1B |= (1 << CS11);

// enable timer compare interrupt
 TIMSK1 |= (1 << OCIE1A);

interrupts();
}

void loop()
{
 displayText();
 delay(100);
}

// Interrupt occurs every millisecond
ISR(TIMER1_COMPA_vect)
{
 static unsigned long lastStateChangeTime = 0;
 static boolean reedWasClosed = false;

unsigned long currentTime = millis();
 boolean reedIsClosed = digitalRead(ReedPin);

// Check for state change
 if (reedIsClosed != reedWasClosed && currentTime - lastStateChangeTime > DebounceTime)
 {
   reedWasClosed = reedIsClosed;
   lastStateChangeTime = currentTime;
   if (reedIsClosed)
   {
     // Reed Has Just Closed
     TotalDistance += WheelCircumference;

// KPHconst is KPH at 1 revolution per tick.
     CurrentVelocity = KPHconst / TickCounter;
     TickCounter = 0;
   }
 }

// Count milliseconds unless the wheel has stopped
 if (TickCounter > 2000)
 {
   // set velocity to 0 when tire is still for 2 seconds
   CurrentVelocity = 0;
 }
 else
 {
   TickCounter++;
 }
}

void displayText()
{
 // Because 'volatile' variables can change any time interrupts are enabled
 // we have to make local copies while interrupts are disables.  If we don't
 // the value of the variable might change half-way thourgh fetching!
 float localTotalDistance;
 float localCurrentVelocity;
 noInterrupts();
 localTotalDistance = TotalDistance;
 localCurrentVelocity = CurrentVelocity;
 interrupts();

//  Serial.print(int(localCurrentVelocity));
 //  Serial.println(" km/h");
 //
 //  if (TotalDistance > 1) {
 //   Serial.print(localTotalDistance);
 //    Serial.println(" km");
 //  }
 //   else {
 //    Serial.print(int(localTotalDistance * 1000.0));
 //    Serial.println(" m");
 //  }

Serial.println(localCurrentVelocity);
 //  Serial.println(localTotalDistance);
}

Also Thanks for your answer

akardas16:
OFF COURSE I prevented floating with resistor

The question is based on statistics. We don't know who you are. Every week on this forum, you will see 50% of posts concerning switch input problems are caused by this. So please be understanding if we ask.

aarg:
The question is based on statistics. We don't know who you are. Every week on this forum, you will see 50% of posts concerning switch input problems are caused by this. So please be understanding if we ask.

yes I know floating issue took much time for me to solve. thanks for your answer