Devices & Components
9V Battery Clip
FTDI Friend with Micro USB Port + extras
Resistor, 200 ohm
SPDT SWITCH
9v Battery
Arduino Pro Mini 328 - 5V/16 MHz
5V 1.5A Linear Voltage Regulator - 7805 TO-220
TO-220 Clip-On Heatsink
Adafruit Perma-Proto Half-sized Breadboard PCB - Single
Standard LCD 16x2 + extras - white on blue
Magnetic contact switch (door sensor)
Capacitor 10 uF
Hardware & Tools
Soldering kit
Hot Glue Gun
Software & Tools
Arduino IDE
FTDI Drivers
SOLIDWORKS
Project description
Code
Speedometer Script
cpp
1#include <LiquidCrystal.h> 2const int rs = 7, en = 2, d4 = 13, d5 = 12, d6 = 11, d7 = 10; 3LiquidCrystal lcd(rs, en, d4, d5, d6, d7); 4 5#define CLOCK_FREQUENCY 16000000 6volatile unsigned int secs = 0; 7 8#define magnet 3 //magnetic switch 9int count = 0; //revolutions of the wheel 10double t = 0; //timestamp since start of program 11double distance = 0.0013048795; //distance traveled in miles in one revolution of the wheel if wheel diameter is 26.32 in 12double velocity = 0; //value updated every revolutions of wheel 13double lastTime = 0; //timestamp of last revoution 14double odometer = 0; //total distance traveled 15volatile bool state = false; //state of magnetic switch 16 17// custom characters 18uint8_t empty[8] = {0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000}; 19uint8_t l[8] = {0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000}; 20uint8_t ml[8] = {0b11000,0b11000,0b11000,0b11000,0b11000,0b11000,0b11000,0b11000}; 21uint8_t center[8] = {0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100}; 22uint8_t mr[8] = {0b11110,0b11110,0b11110,0b11110,0b11110,0b11110,0b11110,0b11110}; 23uint8_t r[8] = {0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111}; 24 25String custChars[6] = {"\x01","\x02","\x03","\x04","\x05","\x06"}; 26 27// int i = 0; 28// int c = 0; 29int idleCount = 0; //seconds since last revolution 30int oneLoopCount = 0; //to only clear lcd once when in idle 31 32// ISR function 33void updateSpeed(){ 34 state = true; //true when magnetic switch is closed 35} 36 37// timer driven interrrupt to track idle time 38ISR(TIMER1_COMPA_vect) { 39 idleCount = idleCount + 1; 40} 41 42void setup() { 43 Serial.begin(9600); 44 // set up the LCD's number of columns and rows: 45 lcd.begin(16, 2); 46 47 // inputpullup seems to be required for this sensor; need to drive current maybe? 48 pinMode(magnet, INPUT_PULLUP); 49 50 // choose the interrupt sensing mode 51 attachInterrupt(digitalPinToInterrupt(magnet), updateSpeed, FALLING); 52 53 //set frequency of the timer, timer driven interrupt every T = 1/freq 54 setupTimer(1.0); 55 56 // create custom characters 57 lcd.createChar(1, empty); 58 lcd.createChar(2, l); 59 lcd.createChar(3, ml); 60 lcd.createChar(4, center); 61 lcd.createChar(5, mr); 62 lcd.createChar(6, r); 63} 64 65void loop() { 66 t = (millis() / 1000.0); 67 int h = floor(t/3600); 68 int m = floor(t/60) - (60*floor(t/3600)); 69 int s = floor(t) - (60*floor(t/60)); 70 71// lcd.setCursor(0, 0); 72// lcd.print(h); 73// lcd.setCursor(1, 0); 74// lcd.print(":"); 75// lcd.setCursor(3, 0); 76// lcd.print(m); 77// lcd.setCursor(4, 0); 78// lcd.print(":"); 79// lcd.setCursor(5, 0); 80// lcd.print(s); 81 82 lcd.setCursor(0,0); 83 lcd.print(m); 84 lcd.setCursor(2,0); 85 lcd.print("min"); 86 87 if(idleCount >= 7){ 88 velocity = 0.0; 89 90 // clear LCD once 91 if(oneLoopCount == 0){ 92 lcd.clear(); 93 oneLoopCount = 1; 94 } 95 96 // print velocity 97 lcd.setCursor(7, 0); 98 lcd.print(velocity); 99 lcd.setCursor(13, 0); 100 lcd.print("mph"); 101 102 // print odometer 103 lcd.setCursor(0,1); 104 lcd.print(odometer); 105 lcd.setCursor(5, 1); 106 lcd.print("mi"); 107 108 // print velocity graphic 109 int bars = floor(velocity); 110 int sects = bars/5; 111 lcd.setCursor(8+sects,1); 112 bars = bars - 5*sects; 113 lcd.print(custChars[bars]); 114 for(int u = 0;u<sects;u++){ 115 lcd.setCursor(8+u,1); 116 lcd.print(custChars[5]); 117 } 118 } 119 120 if(state){ 121 // update revolution count and velocity calculation 122 count++; 123 velocity = ((distance * 3600)/((t - lastTime))); 124 125 // zero velocities over 50 mph as assumed double counts, can be adjusted if you fast 126 if((t - lastTime) <= 0.09396){ 127 velocity = 0.0; 128 } 129 130 // clear LCD each iteration for graphic 131 lcd.clear(); 132 133 // print velocity 134 lcd.setCursor(7, 0); 135 lcd.print(velocity); 136 lcd.setCursor(13, 0); 137 lcd.print("mph"); 138 139 // i += 1; 140 // if(i > 2){ 141 // c += 1; 142 // if(c > 4){ 143 // c = 0; 144 // } 145 // //RGB_color_picker(c); 146 // i = 0; 147 // } 148 149 // update variables 150 lastTime = t; 151 state = false; 152 idleCount = 0; 153 oneLoopCount = 0; 154 } 155 156 // recalculate odometer 157 odometer = count * distance; 158 159 // print odometer 160 lcd.setCursor(0,1); 161 lcd.print(odometer); 162 lcd.setCursor(5, 1); 163 lcd.print("mi"); 164 165 // print velocity graphic 166 int bars = floor(velocity); 167 int sects = bars/5; 168 lcd.setCursor(8+sects,1); 169 bars = bars - 5*sects; 170 lcd.print(custChars[bars]); 171 for(int u = 0;u<sects;u++){ 172 lcd.setCursor(8+u,1); 173 lcd.print(custChars[5]); 174 } 175} 176 177void setupTimer(float freq){ 178// set up Timer 179 noInterrupts(); // stop interrupts 180 181 //set Timer1 interrupt at 1 Hz = 1 time per second 182 TCCR1A = 0; // initialize TCCR1A register 183 TCCR1B = 0; // initialize TCCR1B register 184 TCNT1 = 0; // initialize counter value to 0 185 // turn on CTC mode 186 TCCR1B |= (1 << WGM12); 187 // set CS10 and CS12 bits for 1024 prescaler 188 TCCR1B |= (1 << CS12) | (1 << CS10); 189 // set compare match register for 1hz increments 190 OCR1A = CLOCK_FREQUENCY/freq/1024 - 1; 191 // enable timer compare match A interrupt 192 TIMSK1 |= (1 << OCIE1A); 193 194 interrupts(); // allow interrupts 195}
Downloadable files
Speedometer Case and Mounting CAD
SOLIDWORKS Pack and Go zip file
Speedomer Case and Mounting CAD.zip
Documentation
Schematic
Circuit diagram
Speedometer Schematic.png

Comments
Only logged in users can leave comments