Starter's question about programming a speedometer

Could someone help me with my program?

I'm trying to make a speedometer with hall sensor. The serial monitor is giving me values of below 0. (minus). Could someone help me?

// laatst werkende versie, zonder kmh weergave
//int led = 13; //LED pin
const int sensor = 0; //sensor pin

int pinA = 2;
int pinB = 3;
int pinC = 4;
int pinD = 5;
int pinE = 6;
int pinF = 7;
int pinG = 8;
int D1 = 9;
int D2 = 10;
int D3 = 11;
int D4 = 12;

int val; //numeric variable

/// test 

// const int reed = A3;
float circumference;
float pi = 3.141592653589;
unsigned long time0 = 0;
unsigned long time1;
unsigned long revolutionTime;

// test 


void setup()
{
 /// Test part 
 Serial.begin(9600);
 ////
 pinMode(LED_BUILTIN, OUTPUT);
 //pinMode(led, OUTPUT); //set LED pin as output
 pinMode(sensor, INPUT); //set sensor pin as input

 // initialize the digital pins as outputs.
 pinMode(pinA, OUTPUT);     
 pinMode(pinB, OUTPUT);     
 pinMode(pinC, OUTPUT);     
 pinMode(pinD, OUTPUT);     
 pinMode(pinE, OUTPUT);     
 pinMode(pinF, OUTPUT);     
 pinMode(pinG, OUTPUT);   
 pinMode(D1, OUTPUT);  
 pinMode(D2, OUTPUT);  
 pinMode(D3, OUTPUT);  
 pinMode(D4, OUTPUT);  
 
}

void loop()
{
 val = digitalRead(sensor); //Read the sensor
 if(val == LOW) //when magnetic field is detected, turn led on
 {
   digitalWrite(LED_BUILTIN, HIGH);
   
 }
 else
 {
   digitalWrite(LED_BUILTIN, LOW);
   
 }

 circumference = (pi * 26); //26 = the diameter of the wheel
 int reedState = digitalRead(sensor);
 if (reedState == HIGH) {
   
   time1 = millis();
   revolutionTime = (time1 - time0);
   time0 = time1;
   int kmh = (circumference / revolutionTime) * 3600000; //this is the conversion from inches/millisecond to kmh/hour.
   kmh = kmh-8000;
   Serial.println(kmh);
delay(4000); // print every 4 seconds


 }
     
 }

How is this a tutorial?

delay(4000);I can't think that's helping in any way

It looks like I've posted this in the wrong forum, could someone move it?

I understand what you mean with the delay function.

I added this to read the monitor, otherwise, the amount of numbers is infinite

int kmh = (circumference / revolutionTime) * 3600000;

What is the result of this calculation? Will an int data type hold that result without overflow?

You're right, that is the problem... How can i solve it?

By using a data type with a bigger box, C++ Data Types.

Use a data type that can hold the result of the calculation (long) or do the calculation in a manner that does not cause overflow.

I'm using this one now.... Still not working right... Could someone help me?

Found it here : Hall Effect speedometer, help with code ! [SOLVED] - Programming Questions - Arduino Forum

// wheel radius in mm * 100 * 2 * ( pi * 10000 ) = 94.248000 mm circumference.
// 6 0's were used in scaling up radius and pi, 6 places are divided in the end
// and the units work out. You can use integers more accurate than float on
// Arduino at greatly faster speed. Both type of long can hold any 9-digits.
// Arduino variable type long long can hold any 19 digits is 19 place accuracy.
// if you work in Small Units and scale back later, integers are plenty accurate.
// remember, this value has to be divided by microseconds per turn.
const unsigned long wheel_circumference = 431800UL * 2UL * 31416UL; // = 94,248,000
// wheel circumference gets divided by microseconds, 1,000,000/sec (usec or us).
// wheel turns once for 94248000 mm/100 in 1000000 usecs =

unsigned long Speed = 0;
unsigned long PrevSpeed = 0;

int LED_pin;

volatile byte hall_rising = 0; // interrupt flag
volatile unsigned long irqMicros;

unsigned long startMicros;
unsigned long elapsedMicros;

unsigned long ledFlashStartMillis;
const unsigned long ledFlashWaitMillis = 10;

unsigned long displayStartMillis;
const unsigned long displayWaitMillis = 200;


void wheel_IRQ()
{
  irqMicros = micros();
  hall_rising = 1;
}

void setup()
{
  pinMode( 2, INPUT_PULLUP ); // pin # is tied to the interrupt
  pinMode( LED_pin, OUTPUT );
  Serial.begin( 9600 ); // can this be faster? faster would be better
  Serial.println(wheel_circumference);
  delay( 1000 );

  attachInterrupt( 0, wheel_IRQ, RISING ); // pin 2 looks for LOW to HIGH change
}

void loop()
{
  static unsigned long loopCount = 0; // I expect loop() runs > 33KHz

 


  if ( hall_rising == 1 )
  {
    digitalWrite( LED_pin, HIGH );
    elapsedMicros = irqMicros - startMicros;
    startMicros = irqMicros;

    ledFlashStartMillis = millis();
    hall_rising = 2;
  }
  else if  ( hall_rising == 2 )
  {
    if ( millis() - ledFlashStartMillis >= ledFlashWaitMillis )
    {
      digitalWrite( LED_pin, LOW );
      hall_rising = 0;
    }
  }


  if( elapsedMicros != 0 )
  {
    Speed = (wheel_circumference * 0.0009) / elapsedMicros;
 //. here i added a coefficient that means i'm converting to km/h so it's micrometers *3600 / 10^6 and /4 (num of //.magnets)

   
    if ( Speed != PrevSpeed )
    {
      Serial.print( Speed ); // this now shows mm/sec with no remainder
      Serial.print( "km/h" );
      Serial.println( );

      loopCount = 0; // HERE IS THE FIX JUST THIS ONE LINE ADDED
    }

    PrevSpeed = Speed;
  }
    }

Still not working right...

In your original post, you said "The serial monitor is giving me values of below 0. (minus)". This time, to make it harder for us to help you, you are not going to give any clues about what is not "right"?

Thanks for your help... I've found a solution. Any thoughts about this code?

#include <math.h>

float pi = M_PI;

//Variables used for calculations

float diameter = 0.6; // [m]

int ticks = 0, rpm = 0;

int hallsensor = 2;  //The Hall effect sensor (HES) output of fan  connected to pin no ... of Arduino due


int nr_magnets = 1;



void pickrpm ()
//This is the interrupt subroutine that increments ticks counts for each HES response.
{ ticks++; }

void setup()
{
  pinMode(hallsensor, INPUT);
  Serial.begin(9600);
  attachInterrupt(0, pickrpm, HIGH); 

}
  
void loop ()
{ 
  
ticks = 0;      // Make ticks zero before starting interrupts.

interrupts();    // or use sei(); for other boards- to Enables interrupts
delay (1000);     //Wait 1 second
noInterrupts();  //  or use  cli();  for other boards- to Disable interrupts

rpm = (ticks * 60);

float w = (rpm/60)*2*pi;

float v = (w*(diameter/2)/nr_magnets);

int v_round = v;

//Print calculated Speed at the serial port 
  Serial.print (rpm, DEC);    
  Serial.print (" RPM\r\n");
  Serial.print (w);
  Serial.print (" rad/s\r\n");
  Serial.print (v);
  Serial.print (" km/h\r\n");


        }  

}  // end of loop function

float pi = M_PI; Were you thinking about changing the value of π ?

"ticks" should be qualified 'volatile'

No, i'm not changing PI, but it makes it easier to read.

Changing ticks to volatile, what would be the difference?

jweikamp:
No, i'm not changing PI

So why is it a variable?

I've changed it to M_PI everywhere.

In my speedo project using a Hall Effect sensor, I found the pulsIn() function easier to use than an interrupt.

John.

Could you share your code?

Thanks in advance

jweikamp:
Could you share your code?

Thanks in advance

I can share info on how to use the pulsIn() function and other aspects, but not the full code. Please explore the pulseIn() function in the Reference section. It really is simple.

John.

This is my code to determine the car speed. It just measures the duration for the Hall Effect connection to be high. This duration is inversely proportional to the car speed. You just need to determine the constant to relate one to the other.

void detCarSpeed(){
unsigned long duration;
duration = pulseIn(HEpin, HIGH, HEtimeout)/1000; //pulse length in millis
if (duration == 0) carSpeed = 0; //timout so call it zero kph
else {carSpeed = (wheelConstant/duration); //adjust wheelConstant to fine tune
wheelClicks++;
}
}

John.

Something like this? Could you help me with get this working?

#include <math.h>

int HEpin = 2;

unsigned int duration;

int HEtimeout = 1000;
int wheelClicks = 0;

float carSpeed = 0;

float wheelConstant = 700*2*M_PI;

void setup()

{

  pinMode(HEpin, INPUT);
 Serial.begin(9600);
}


void detCarSpeed(){
  unsigned long duration;
  duration = pulseIn(HEpin, HIGH, HEtimeout)/1000; //pulse length in millis
  if (duration == 0) carSpeed = 0;       //timout so call it zero kph
  else {carSpeed = (wheelConstant/duration); //adjust wheelConstant to fine tune
  wheelClicks++;
  }
}


void loop()

{

  duration = pulseIn(HEpin, HIGH);

  Serial.println ("duration ");
  Serial.print(duration);
  Serial.println ("speed ");
  Serial.print(carSpeed);
  delay(2000);
}

Hi jw.

You're on the right path. A few thoughts:

I declare the HE pin this way: "pinMode(HEpin, INPUT_PULLUP)". This makes the HE pin normally high to avoid a floating voltage at the pin.

Use this to declare the value of the HE pin: "#define HEpin 2". That makes it a constant rather than it an int variable (it is not gong to vary):

I declare the variable speed as type byte. That allows for 0 to 255. I don't need decimal places for the speed.

I would select a value for the wheel constant rather than a formula. Make an estimate and don't worry about accuracy. You can adjust it when you have a working program.

Inside your loop you have used the pulseIn function. You should be calling the detCarSpeed() function. That uses the pulsIn function to determine the speed.

I would test the sketch by placing the HE sensor on the work bench and moving a magnet near to it and away from it. You need to understand how the sensor works.

I don't think you need the "delay(2000)". If your loop calls the detCarSpeed function it will not return until it determines a duration or times out. It won't overload the serial monitor.

Good luck. You'll get there. Glad to help.

John.