Bike POV Beta 6
From Open Source Urbanism
Code for the Arduino Bike POV project
Status: working
Environment: Arduino 0011 (not working on version 12)
Download Arduino sketch: Bike POV Beta 6.zip
Or copy the following code into the Arduino programming environment (use the font.h code from Bike_POV_Beta_4).
//============================================================ // Arduino Bike POV // // by Scott Mitchell // www.openobject.org // Open Source Urbanism // // Copyright (C) 2008 Scott Mitchell 12-10-2008 // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // A copy of the GNU General Public License // can be found at <http://www.gnu.org/licenses/>. // // B6.1 // Last Modified: October 19, 2008 //============================================================ #undef int() // fixes a bug with the stdio.h #include <stdio.h> // gives access to function sprintf #include <EEPROM.h> //Needed to access the eeprom read write functions // defining the alphabet #include "font.h" // get access to better timekeeping. ref: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1193623343 extern volatile unsigned long timer0_overflow_count; // define the Arduino LED pins in use const int LEDpins[] = { 0,1,2,3,4,5,6}; // number of LEDs const int charHeight = sizeof(LEDpins); const int charWidth = 5; // set up display parameters const int numFrames = 350; // number of frames per rotation unsigned long frameDuration = 1000; // time for each frame in microseconds - updated from rotation speed const int letterSpace = 4; // number of frames between letters const int textOffset = 100; // start distance from magnet in frames unsigned long startTime = microSeconds(); // start time for wheel rotation in microseconds unsigned long resetTime = 10000000; // reset time for text in microseconds (10 sec) // sensor setup const int sensorPIN = 0; // define the Arduino sensor pin const int mean = 508; // sensor at rest (no magnet) const int sensitivity = 30; // sensor sensitivity // distance and speed variables (floats are avoided because they slow the Arduino down) unsigned long numWheelRotations; // the base from which all other data is calculated const unsigned long wheelCircum = 1100; // bike wheel circumference in mm (adjust this to match your bike) // EEPROM setup int saveSwitchPin = 7; // digital pin for save button int memLoc = 188; // EEPROM memory address - any number between 0 and (512 - 4) long storedMetres; // the distance in metres stored in memory // text string char textString[50] = "HELLO"; // declared large enough to hold a full string void setup() { for (int i = 0; i<charHeight; i++) pinMode(LEDpins[i], OUTPUT); // set each pin as an output pinMode(saveSwitchPin, INPUT); // set the save button as an input // should we clear the EEPROM memory? int j=0; while(digitalRead(saveSwitchPin) == HIGH){ // is the save switch being pressed? cycleLEDs(HIGH, 20); // indicate the button press and take care of debounce cycleLEDs(LOW, 20); j++; if(j>5){ // if the button is held for longer than 4 cycles EEPROMWriteInt(memLoc, 0); // write 0 to the memory location allLEDs(HIGH); // indicate a clear has taken place delay(1000); allLEDs(LOW); break; // exit the while loop } } // set the number of wheel rotations from data stored in EEPROM memory storedMetres = EEPROMReadInt(memLoc); // EEPROM value is stored in metres numWheelRotations = (storedMetres * 1000)/ wheelCircum; // metres converted to number of wheel rotations } void loop() { // printing every letter of the textString for (int i=0; i<sizeof(textString); i++){ printLetter(textString[i]); // space between letters pauseFrame(letterSpace); if(microSeconds() > resetTime){ resetTime += 10000000; // add 10 seconds to it, it will get reset when the sensor is triggered break; // restart the text string } } // check for save button press int j=0; while(digitalRead(saveSwitchPin) == HIGH){ // is the save switch being pressed? cycleLEDs(HIGH, 20); // indicate the button press and take care of debounce j++; if(j>3){ // if the button is held for longer than 3 cycles unsigned long distancem = numWheelRotations * wheelCircum / 1000; // calculate the distance in metres if(storedMetres != distancem){ // if it hasn't already been stored EEPROMWriteInt(memLoc, distancem); // write the metres to memory storedMetres = distancem; allLEDs(HIGH); // indicate a save has taken place delay(500); allLEDs(LOW); } break; // exit the while loop } } } void printLetter(char ch) { byte b; // make sure the character is within the alphabet bounds (defined by the font.h file) // if it's not, make it a blank character if (ch < 32 || ch > 126) ch = 32; // converts the ASCII number to the font index number ch -= 32; // step through each byte of the character array for (int i=0; i<charWidth; i++) { b = font[ch][i]; // bit shift through the byte and output it to the pin for (int j=0; j<charHeight; j++) { digitalWrite(LEDpins[j], !!(b & (1 << j))); } // space between columns pauseFrame(1); } //clear the LEDs for (int k=0; k<charHeight; k++) { digitalWrite(LEDpins[k], LOW); } } void pauseFrame(int frames){ unsigned long currentTime; int sensVal; // variable to store the value coming from the sensor unsigned long endTime = microSeconds() + (frames * frameDuration); // calculate the end time while(microSeconds() < endTime && microSeconds() < resetTime){ // check the sensor sensVal = analogRead(sensorPIN); // read the Hall Effect Sensor if (sensVal > (mean + sensitivity) || sensVal < (mean - sensitivity)) { currentTime = microSeconds(); // in microseconds if(currentTime < (startTime + (20 * frameDuration))){ // de-bounce the sensor reading startTime = currentTime; // reset the start time } else { resetTime = currentTime + (textOffset * frameDuration); // set the sensor flag variable frameDuration = (currentTime - startTime) / numFrames; // recalculate frameDuration if(frameDuration > 10000) frameDuration = 10000; // limit the frame duration to a reasonable time numWheelRotations++; // add 1 to the number of wheel rotations setTextString(currentTime - startTime); // reset the display text startTime = currentTime; // reset the start time } } } } void setTextString(unsigned long duration){ int n; // number of char written to the string (not used) // calculate distance unsigned long distancem = numWheelRotations * wheelCircum / 1000; // distance in metres unsigned long distancekm = distancem / 1000; // distance in km (this truncates the number) unsigned long distanceRem = distancem - (distancekm * 1000); // the bit after the decimal point // calculate speed // mm / microsecond x 1000 is mm / millisecond // mm / millisecond is equivalent to m / sec // m / sec x 60 x 60 is m / hr // m / hr / 1000 is km / hr unsigned long speed100m = wheelCircum * 36000 / duration; // 100m per hour unsigned long speedkm = speed100m / 10; // km per hour unsigned long speedRem = speed100m - (speedkm * 10); // the bit after the decimal point // print a new text string into the variable n = sprintf(textString, "%ld.%.3ld km %ld.%.ld km/hr \n", distancekm, distanceRem, speedkm, speedRem); } // get an accurate time reading. ref: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1193623343 unsigned long microSeconds(void) { return ((timer0_overflow_count << 8) + TCNT0)*4; } //This function will write a 4 byte long integer to the eeprom from the specified address void EEPROMWriteInt(int p_address, long p_value) { byte Byte1 = ((p_value >> 0) & 0xFF); byte Byte2 = ((p_value >> 8) & 0xFF); byte Byte3 = ((p_value >> 16) & 0xFF); byte Byte4 = ((p_value >> 24) & 0xFF); EEPROM.write(p_address, Byte1); EEPROM.write(p_address + 1, Byte2); EEPROM.write(p_address + 2, Byte3); EEPROM.write(p_address + 3, Byte4); } //This function will read a 4 byte long integer from the eeprom from the specified address unsigned long EEPROMReadInt(int p_address) { byte Byte1 = EEPROM.read(p_address); byte Byte2 = EEPROM.read(p_address + 1); byte Byte3 = EEPROM.read(p_address + 2); byte Byte4 = EEPROM.read(p_address + 3); // bit shifting left more than 8 places wont work because the result gets truncated // so do this in two stages long firstTwoBytes = ((Byte1 << 0) & 0xFF) + ((Byte2 << 8) & 0xFF00); long secondTwoBytes = (((Byte3 << 0) & 0xFF) + ((Byte4 << 8) & 0xFF00)); secondTwoBytes *= 65536; // multiply by 2 to power 16 - bit shift 24 to the left return (firstTwoBytes + secondTwoBytes); } void allLEDs(int newState) { // turn all the LEDs ON or OFF for (int i=0; i<charHeight; i++) { digitalWrite(LEDpins[i], newState); } } void cycleLEDs(int LEDdirection, int LEDdelay) { int i; // turn all the LEDs ON and OFF in a cycle if(LEDdirection == HIGH){ for (i=0; i<charHeight; i++) { digitalWrite(LEDpins[i], HIGH); delay(LEDdelay); digitalWrite(LEDpins[i], LOW); } } else { for (i=charHeight-1; i>=0; i--) { digitalWrite(LEDpins[i], HIGH); delay(LEDdelay); digitalWrite(LEDpins[i], LOW); } } }

