/*
  @title: Distance Measurement and Alarm system
  @author: Sebastien Eckersley-Maslin
  @company: Blue Chilli Technology
  @date: 2 March 2010
  
  @description:
    This program reads in the value from a Sharp GP2Y0A sensor and converts it to a linearised
    distance in cm.  It then displays the result on a 2x16 LCD screen and sounds a piezo alert
    buzzer of the distance is less than a certain range.
 
  @resources: 
    linearising the data: http://www.acroname.com/robotics/info/articles/irlinear/irlinear.html
    create custom lcd char: http://arduino.cc/en/Reference/LiquidCrystalCreateChar
    connect LCD screen: http://arduino.cc/en/uploads/Tutorial/lcd_bb.png
 */

#include <LiquidCrystal.h>

// LCD Screen setup
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// I/O Pin declarations
const int analogInPin   = 0;              // Analog input pin that the sharp distance sensor is attached to
const int alertPin      = 6;              // Digital output pin for the piezo buzzer

// distance formula values
const int mprime       = 16667;
const int bprime       = 15;
const int k            = 10;
const int maxDistance  = 200;             // maximum distance of the sensor (in cm)

// Alert constants
const int alertDistance = 40;             // Distance to sound the alarm in cm

// variables
int sensorValue = 0;                      // value read from the sensor
int distance = 0;                         // calculated distance (in cm)

// lcd glyphs
byte squareChar[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};


// Setup Function ----------------------------------------
void setup() {

  // Setup the LCD screen
  lcd.begin(16, 2);
  lcd.createChar(0, squareChar);

  // Setup pins
  pinMode(alertPin, OUTPUT);  

}


// Main Loop ---------------------------------------------
// The main loop reads in the analog sensor value, converts
// it to distance (in cm), prints it to the screen and then
// checks to see if the alarm needs to be sound
void loop() {

  // Read the sharp distance sensor
  sensorValue = readSensor();

  // Calculate distance based on formula
  distance = (mprime / (sensorValue + bprime)) - k;

  // Draw the distance to the screen
  printDistance(distance);

  // Print the bar graph on the screen
  printBarGraph(distance);

  // sound the alert if the range is less than the alert distance
  soundAlert(distance);

}



// Print Distance ------------------------------------------
// This function prints the distance to the LCD screen and
// in doing so clears the old value
void printDistance(int _distance) {
  
  lcd.setCursor(0, 0);
  lcd.print(_distance);
  lcd.print(" cm       ");
  
}



// Read Sensor Value -------------------------------------
// This function reads in the sensor value and takes
// the average reading of it over 5 iterations.
int readSensor() {
  int _i;
  int _sensorValue = 0;
  for(_i = 0; _i < 5; _i ++) {
    _sensorValue += analogRead(analogInPin);            
    delay(10);
  }
  _sensorValue = _sensorValue / 5;
  return _sensorValue;
}



// Print Bar Graph ----------------------------------------
// This function loops through the 16 characters of the 
// LCD screen and prints a SQUARE character at a position
// proportional to the distance sent in.
void printBarGraph(int _distance){
  int _bar;
  int _i;

  lcd.setCursor(0, 1);
  _bar = map(_distance, 0, maxDistance, 0, 16);
  
  for(_i = 0; _i < 16; _i ++){
    if(_bar == _i)
      lcd.write(0);              // Square Glyph defined above
    else
      lcd.print(".");    
  } 
}

// Sound Alert Buzzer -------------------------------------
// This function sounds the alert buzzer if the distance
// is less than the preset alert distance
void soundAlert(int _distance) {
  
   if(_distance < alertDistance)   
    digitalWrite(alertPin, HIGH);
  else
    digitalWrite(alertPin, LOW);
    
}


