Bicycle Speedometer

Hall Effect Sensor, LCD, and Pic16F628 Microcontroller

Bicycle Speedometer with Hall Effect Sensor on the cable tip

Have you ever wondered how fast you’re going on your bicycle or how far you’ve traveled? Well, now you can find out with a bicycle speedometer! This cool device can be mounted on the handle of your bike, and it has a two-line LCD display that shows your speed in miles per hour and the distance you’ve traveled in miles.

To make this speedometer work, it needs a 9V battery, a toggle switch, and a reset push button. It also uses a special kind of sensor called the Hall Effect Sensor UGN3503V, which detects a magnetic field in the presence of a small magnet. You can see a picture of the sensor and magnet in the photo.

Speed detection by Hall Effect Sensor

Here’s how the speedometer works: the Hall Sensor is attached to the rear wheel of the bicycle along the rod that holds the wheel. A small magnet, about the size of a dime and 0.25 inches in diameter, is glued to the wheel so that it passes near the Hall Sensor. Every time the magnet passes the Hall sensor, it triggers an interrupt in the PIC16F628 microcontroller. The interrupt routine then calculates the current speed and distance and displays it on the LCD.

So, now you can keep track of how fast you’re going and how far you’ve traveled on your bike! Just attach the speedometer to your bike, turn it on with the toggle switch, and reset it with the push button whenever you want to start over. It’s super easy and fun!

Bicycle Speedometer Schematic
Speed and Distance shown on LCD Display

Hall Effect Sensor – attached to ethernet cable with shrink tubing
Testing the Hall Effect Sensor and the magnet to induce Interrupt routine
LM358 Op Amp to boost the Hall Sensor signal

Speedometer C Program

/* This speedometer1.c program is working
   A Khan Feb. 10, 2010 - 
   
*/
unsigned char dia = 20;         // Wheel size 20 inches diameter
unsigned char cntr = 0;         // number of RB0 transition
unsigned char ovrflw = 0 ;      // number of timer0 overflows
unsigned char pulse = 0;        // pulse for Mph calculation

//unsigned char flag = 0;       // A flag to indicate an interrupt has occured

// Variable used in functions speed, Distance, rpm
unsigned int mile = 5280; // 1 mile is 5280 feet
float FAST, speed() = 0, spd, pi = 3.1415; // value of pi

  // Configure LCD - 4 bit mode
  // LCD Module connections
  sbit LCD_RS at RB2_bit;
  sbit LCD_EN at RB3_bit;
  sbit LCD_D4 at RB4_bit;
  sbit LCD_D5 at RB5_bit;
  sbit LCD_D6 at RB6_bit;
  sbit LCD_D7 at RB7_bit;

  sbit LCD_RS_Direction at TRISB2_bit;
  sbit LCD_EN_Direction at TRISB3_bit;
  sbit LCD_D4_Direction at TRISB4_bit;
  sbit LCD_D5_Direction at TRISB5_bit;
  sbit LCD_D6_Direction at TRISB6_bit;
  sbit LCD_D7_Direction at TRISB7_bit;

  void interrupt()
{
        if(INTCON.INTF)
        {
         /*
         * RB0 External interrupt
         */
         cntr++ ;// count the wheel turns
         //RA1_bit = ~RA1_bit  ; // for testing only
         INTCON.INTF =0;         // clear the Ext. Interrupt flag
        }
        else if(INTCON.T0IF)
        {
        /*
        * TIMER 0 overflow
        */
        ovrflw++ ;// count the number of overflows to determine
        //how many external interrupt pulses happen in one second
        INTCON.T0IF =0;         // Clear Timer 0 interrupt flag
        }

}

float speed (unsigned char pulse, unsigned char dia)
{
//unsigned char pulse;
//float spd;
// speed in miles/hr
spd = (pulse * pi *  dia * 360)/(12 * mile) ;  // calculate speed

return spd;  // return the value of speed = spd
}

//dist (unsigned int cntr, unsigned char dia)
//{
//float distance;
// Distance in miles
//distance =  (cntr * pi * dia)/(12 * mile);
//return distance ;
//}

//rpm (unsigned int cntrps) // cntrps = counter value per second
//{
//float distance;
// revolution per minute
//revolution = (cntrps * 60);
//return revolution;
//}


void main()
{
 //unsigned char pulse, cntr;
// unsigned char dia = 20;         // Wheel size 20 inches diameter
 //unsigned char RPM, Distance ;
 //unsigned char rev[4];
 unsigned char tick[4];
 unsigned char quick [15];
 //float FAST, speed();
  PORTA = 0; //Clear Port A
  TRISA = 0; // Port A is Output


// Configure Interrupt
OPTION_REG = 0b10000111;//PortB pull-up should be disabled - Prescale is 256
INTCON = 0b10110000;
TMR0 = 0x00;          // load value in Timer 0

Lcd_Init();
Lcd_Cmd(_LCD_Clear);
Lcd_Cmd(_LCD_Cursor_OFF);
//Lcd_Out(1,1,"Suleman");
//Delay_ms(2000);

/*
 * main loop
*/
for(;;)
{
if (ovrflw >= 15)//4 Mhz/4=1usec*256 prescale=256 usec per instruction
                                    // so for TMR0 to overflow (ff->00) it needs 256 instructions, so 256usec * 256 = 65.5 millisec                           // And in One second 1000 millisec/65.5 millisec = 15.26 or approximately 15
{
INTCON.GIE = 0; //Stop all Interrupts
                //cntr = 15;
                //pulse = cntr;

Lcd_Cmd(_LCD_Clear); // Clear LCD
                //Lcd_Out(1,1,"MPH");
                //BytetoStr(RPM,rev);

                //Lcd_Cmd(_LCD_Clear); // Clear LCD
                //Lcd_Out(1,1,"Tick");
                //Delay_ms(1000);

pulse = cntr;
BytetoStr(pulse, tick);
Lcd_Out(1,1,tick);    // Display the pulse value

                //FAST = speed(pulse, dia);

                //FloattoStr(FAST,quick);
                //Lcd_Out(1,5,quick);    // Display the pulse value
                
                
                //Lcd_Cmd(_LCD_Clear); // Clear LCD
                //Lcd_Out(1,1,"Mph");
                //FloattoStr(FAST,rev);
                //Lcd_Out(1,5,rev);    // Display the counter value
                
                
                ovrflw = 0;  // Clear Timer overflows
                //oldcntr = oldcntr + cntr; // for Distance
                //cntr = 0;
INTCON.GIE = 1; //Enable all Interrupts
                }
                else                                                                                                                                                                                                                                                                                                                                                                                                                                                                      if (ovrflw < 15626)         // wait 1 second : 15626 = 16 000 000 / 4 / 256, rounded up
                {
                //INTCON.GIE = 0; //Stop all Interrupts
                //RPM = ovrflw;
                //LongWordtoStr(RPM,rev);
                //Lcd_Out(1,1,rev);
                //Delay_ms(2000);
                //INTCON.GIE = 1;  //Enable all Interrupts
                }
                }
   

}

One thought on “Bicycle Speedometer

Comments are closed.