openobject.org

Bike POV Beta 5

From Open Source Urbanism

Code for the Arduino Bike POV project

Status: working (no EEPROM storage yet. Use the font.h code from Bike_POV_Beta_4)
Environment: Arduino 0011 (not working on version 12)

This code has been superseded. Get the latest version here.

//============================================================
// 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/>.
//
// B5.3
// Last Modified: October 16, 2008
//============================================================

#undef int() // fixes a bug with the stdio.h
#include <stdio.h> // gives access to function sprintf

// 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[] = {
  1,2,3,4,5,6,7};

// 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 = 10;  // 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)

// 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
  // set the number of wheel rotations
  // future version should get this value from EEPROM memory
  // store the value in m then (numWheelRotations = distance * 1000 / wheelCurcum)
  numWheelRotations = 0;  // for now just let it equal 0
}

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
      break;  // restart the text string
    }
  }
}

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;
}