All pastes #2118312 Raw Edit

Untitled

public text v1 · immutable
#2118312 ·published 2012-02-17 03:09 UTC
rendered paste body
#include <LiquidCrystal.h>

/*
 *   Boost Gauge project for my Nissan Stagea
 *   To Do:
 *          1. Fix the boost bar graph scaling to re-read the values after its been changed in the menu - DONE
 *          2. Move the alarm code and all the calculation code out of the display printing routine. - DONE
 *             - Perhaps move the display printing into a suborutine? - LATER?
 *          3. Read/Write EEPROM for saving etc variable. Make sure to handle the case where there is no data in EEPROM.
 *             - http://arduino.cc/playground/Code/EEPROMWriteAnything 
 *          3. Think of a better way to do the menus and tidy things up. Code is pretty nasty right now.
 *          4. Add a peak value feature with adjustable timeout.
 *          5. Fix display errors when graph scale is set low and boost significantly higher causes it to wrap to the first line.
 */

/*
 *LCD Pinout            Cable Pin header    Arduino Pin
 *1 - GND                1
 *2 - +5V                2
 *3 - Contrast           3
 *4 - RS                 4                  2
 *5 - RW                 5                  3
 *6 - E(Enable)          6                  4
 *7 - DB0
 *8 - DB1
 *9 - DB2
 *10 - DB3
 *11 - DB4               7                  5
 *12 - DB5               8                  6
 *13 - DB6               9                  7
 *14 - DB7               10                 8
 *15 - Backlight +5V     11                 NC
 *16 - Backlight GND     12                 NC
 */


// LiquidCrystal lcd(rs, rw, enable, d4, d5, d6, d7)  - 4 bit mode
LiquidCrystal    lcd(2,   3,      4,  5,  6,  7,  8);
// LiquidCrystal lcd(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7) - 8 bit mode
//LiquidCrystal    lcd(2,   3,      4,  5,  6,  7,  8,  9, 10, 11, 12);




// Analog 0-5v Sensor in
word Analog1pin = A5;
int Analog1Raw = 0;
int Analog1mV = 0;
float Analog1AFR = 0;

// Shift Regsiter pins for Button Input
#define ShiftData  9
#define ShiftClock 10  
#define ShiftLatch 11

// Other pins
#define BuzzerPin 12

// Stored config
#define CONFIG_START 0
#define CONFIG_VERSION stageav1


/* -- This shit doesnt work....

struct ConfigStruct {

  int BoostMin;  // BoostMin for graph Scaling
  int BoostMax;  // BoostMax for graph Scaling
  int BoostAlarm;// Alarm for audible/visual boost warning
};

ConfigStruct Config = { 0 , 0 , 0 };

Config.BoostMin = 0;
Config.BootMax = 500;
Config.BoostAlarm = 300;
*/


// Variable for buttons
unsigned int buttonScanInterval = 100;    // Interval between checking for button press
unsigned long buttonScanLastms = 0;       // Last time we looked
byte ButtonBits = 255;                    // B11111111
unsigned int ButtonRepeatDelay = 200;     // 300ms delay for button repeat 
unsigned long ButtonRepeatLastms = 0;     // Last time a button was pressed

// Variables for tracking menu states  :: 0 - Run (no menu), 1 - Display Menu
byte MenuState = 0;
byte SubMenu = 0;                    // Used to track what SubMenu we're in
unsigned int MenuTimeout = 10000;    // 10 second timeout for menus


// Text display timer variables
unsigned int timerTextInterval = 100;    // interval between sensor data updates
unsigned long timerTextLastms = 0;       // Last time we looked

// mV for boost min and max. This is used for the bar graph
int BoostMin = 0;
int BoostMax = 500;   // 17 psi
int BoostAlarm = 300; // 10 psi

// Bar Graph magic
unsigned int timerBarGraphInterval = 10;  // interval between bar graph updates
unsigned long timerBarGraphLastms = 0;    // Last time we looked
int LCDWidth = 16;                        // LCD Display width in chars
int LCDPixelWidth = 5;                    // Each char is 5 pixels wide
int LCDBars = LCDWidth * LCDPixelWidth;   // This is the number of pixels we have to use
int mVPerBar = BoostMax / LCDBars;        // Bar graph magic calculations
int mVPerChar = mVPerBar * LCDPixelWidth; //mV per full char
int BarGraphValue = 0;                    // This variable is used further down when printing the bar graph
int BarGraphWritten = 0;                  // This variable is used to track how much whitespace we need to print after the bar to clear the display.

const float kpa2psi = 0.145037738;

void setup()
{
//  lcd.begin(24, 4);
  
  lcd.begin(16, 2);
  // Setup our custom chars for the bar graph
  byte bar1[8] = {
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
  };
  lcd.createChar(1, bar1);
  
  byte bar2[8] = {
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
  };
  lcd.createChar(2, bar2);
  
  byte bar3[8] = {
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
  };
  lcd.createChar(3, bar3);
  
  byte bar4[8] = {
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
  };
  lcd.createChar(4, bar4);
  
  byte bar5[8] = {
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
  };
  lcd.createChar(5, bar5);
  
    byte leftArrow[8] = {
    B00010,
    B00110,
    B01111,
    B11111,
    B01111,
    B00110,
    B00010,
  };
  lcd.createChar(6, leftArrow);

    byte rightArrow[8] = {
    B01000,
    B01100,
    B11110,
    B11111,
    B11110,
    B01100,
    B01000,
  };
  lcd.createChar(7, rightArrow);
  
  // Smiley - just for fun
  byte smile[8] = {
    B10001,
    B00000,
    B00100,
    B01100,
    B00000,
    B10001,
    B01110,
  };
  lcd.createChar(8, smile);
  
  lcd.begin(16, 2);  

  Serial.begin(9600);

  // Set Pin modes   
  pinMode(BuzzerPin, OUTPUT);            // alarm buzzer
  digitalWrite(BuzzerPin, LOW);          // Initially, off.  

  pinMode (Analog1pin, INPUT);    // boost sensor in

  
  // Set Shift Register Pin Modes
  pinMode(ShiftData, INPUT);
  pinMode(ShiftClock, OUTPUT);
  pinMode(ShiftLatch, OUTPUT);
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print ("Boost Gauge...");

  delay(500);
  lcd.clear();
}

void loop()
{
  
  // Get the current ms value to compare timers with.
  unsigned long currentMillis = millis(); 

  //////////////////////////
  //  Button Input/Menus  //
  //////////////////////////
  
  // Scan for button presses at the defined interval
  if (currentMillis - buttonScanLastms > buttonScanInterval)
  {
    buttonScanLastms = currentMillis;
    
    // Reset to "all-on"
    // ButtonBits = 255; // B11111111
    
    // Reset to "all-off"
    ButtonBits = 0;
       
    // Delay for key repeat - Delay the rescan if we've had a keypress detected within the ButtonRepeat time.
    if (currentMillis - ButtonRepeatLastms > ButtonRepeatDelay)
    {
      /*
      Using shift register example from http://arduino.cc/en/Tutorial/ShftIn12
      */
      //Pulse the latch pin high to collect parallel data.
      digitalWrite(ShiftLatch,1);
      delayMicroseconds(20);
      //Drop the latch low to start shifting data into the MCU serially.
      digitalWrite(ShiftLatch,0);
      
      // Collect the data into a byte var.
      ButtonBits = shiftIn(ShiftData, ShiftClock, MSBFIRST);
      // Serial.println(ButtonBits, BIN);
    }
    

    

    
    
    if (ButtonBits == B00000000)        // No buttons pressed
    {
      // We can use this section for timeout code if necessary later.
    }    
    else if (ButtonBits == B10000000)  // Escape (Top Left)
    {
      ButtonRepeatLastms = currentMillis;
      // If we're not in a Menu, set the MenuState, and then print the main menu.
      if (MenuState == 0)
      {
        MenuState = 1;      // Set this flag to say we're in a menu
        SubMenu = 0;        // Reset this to be main menu
        WriteMenu(SubMenu);
        
        
      }
      // If we're in a menu, set MenuState to 0 and clear the display in preperation for sensor view.
      else if (MenuState > 0)
      {
        MenuState = 0;      // Set this flag to say we're not in a menu
        lcd.clear();
      }
    }
    else if (ButtonBits == B01000000)  // Up (Top Middle)
    {
      ButtonRepeatLastms = currentMillis;
      // If We're in a Menu
      if (MenuState > 0)
      {
        // And we're in Menu 1 (Graph MaxBoost)
        if (SubMenu == 1)
        {
          BoostMax = BoostMax + 5;
          mVPerBar = BoostMax / LCDBars;        // Bar graph magic calculations
          mVPerChar = mVPerBar * LCDPixelWidth; //mV per full char
        }
        // And we're in Menu 2 (Boost Alarm)
        else if (SubMenu == 2)
        {
          BoostAlarm = BoostAlarm + 5;
        }
        
        WriteMenu(SubMenu);
      }
    }
    else if (ButtonBits == B00100000)  // Enter (Top Right)
    {
      ButtonRepeatLastms = currentMillis;
    }
    else if (ButtonBits == B00010000)  // Not used
    {
      ButtonRepeatLastms = currentMillis;
    }
    else if (ButtonBits == B00001000)  // Right (Bottom Right)
    {
      ButtonRepeatLastms = currentMillis;
      // If we're in a menu, Increment the SubMenu variable and print the menu.
      if (MenuState > 0)
      {
        SubMenu++;
        WriteMenu(SubMenu);
      }
    }
    else if (ButtonBits == B00000100)  // Down (Bottom Middle)
    {
      ButtonRepeatLastms = currentMillis;
      // If We're in a Menu
      if (MenuState > 0)
      {
        // And we're in Menu 1 (Graph MaxBoost)
        if (SubMenu == 1)
        {
          BoostMax = BoostMax - 5;
          mVPerBar = BoostMax / LCDBars;        // Bar graph magic calculations
          mVPerChar = mVPerBar * LCDPixelWidth; //mV per full char
        }
        // And we're in Menu 2 (Boost Alarm)
        else if (SubMenu == 2)
        {
          BoostAlarm = BoostAlarm - 5;
        }
        
        WriteMenu(SubMenu);
      }
    }
    else if (ButtonBits == B00000010)  //Left (Bottom Left)
    {
      ButtonRepeatLastms = currentMillis;
      // If we're in a menu, Decrement the SubMenu variable and print the menu.
      if (MenuState > 0)
      {
        SubMenu--;
        WriteMenu(SubMenu);
      }
    }
    else if (ButtonBits == B00000001)  // Not Used
    {
      ButtonRepeatLastms = currentMillis;
    }
    else
    {
        // Do Nothing if some idiot presses more than one button at a time.
    }
  


  } 
  
  //////////////////////////////////////
  //        Bar Graph / Alarm        //
  /////////////////////////////////////
  if (currentMillis - timerBarGraphLastms > timerBarGraphInterval)
  {
    timerBarGraphLastms = currentMillis;    

    //Read our sensor "Analog1"
    Analog1Raw = analogRead(Analog1pin);
    
    // Turn the alarm on or off.
    if (Analog1Raw < BoostAlarm)   digitalWrite(12, LOW);        // Everything is fine...
    if (Analog1Raw >= BoostAlarm)   digitalWrite(12, HIGH);        // Alarm!!
    
    // We only want to print the bar graph stuff if we're not in a menu.
    if (MenuState == 0) {
    
      lcd.setCursor (0,1);
      BarGraphValue = Analog1Raw;
      BarGraphWritten = 0;
      
      // To speed bar graph drawing, each full char is equivelent to 1/16th of the scale
      // Print a full char for every full 1/16th of the scale and then print out a single part char for the remainder.
      while (BarGraphValue > mVPerChar)
      {      
        lcd.write(5);                                  // Write full blocks each representing 1x mvPerChar.
        BarGraphValue = BarGraphValue - mVPerChar;     // Drop the remaining BarGraphValue by what we've printed
        BarGraphWritten++;                             // Increment the char printed counter
      }
      
      // Print the appropriate 'part char' representing the remainder BarGraphValue.
      if (BarGraphValue > ( 3 * mVPerBar))
      {
        lcd.write(4);
      }
      else if (BarGraphValue > ( 2 * mVPerBar))
      {
        lcd.write(3);
      }
      else if (BarGraphValue > ( 1 * mVPerBar))
      {
       lcd.write(2);
      }
      else if (BarGraphValue > ( 0 * mVPerBar))
      {
       lcd.write(1);    
      }
      
      BarGraphWritten++;    //Increment the chars printed counter.
  
      
      // Print whitespace to the end of the line. Always prints over whats there. May be inefficient on LCD IO.
      while ((BarGraphWritten - LCDWidth) < 0)
      {
        lcd.write(" ");
        BarGraphWritten++;
      }
    }    
  } //if (currentMillis - timerBarGraphLastms > timerBarGraphInterval)


  
  /////////////////////////////
  //       Text Display      //
  /////////////////////////////
  if (currentMillis - timerTextLastms > timerTextInterval && MenuState == 0 )
  {
    timerTextLastms = currentMillis;
    
    //Debugging - Print the pin Voltage. 0-5000 
    /* 
    lcd.setCursor(12,0);
    if (Analog1mV<1000) lcd.print(' ');
    if (Analog1mV<100) lcd.print(' ');
    if (Analog1mV<10) lcd.print(' ');
    lcd.print(Analog1mV);
    */
    
    // Map it to mV.
    //Analog1mV = map(Analog1Raw, 0, 1023, 0, 5000);
    
    //psi=(0.04+((Analog1mV/1000)/(0.004*5)))*kpa2psi
    // float Analog1mVx = Analog1mV;
    //float Analog1Psi = (0.04+((Analog1mVx/1000)/(0.004*5)))*kpa2psi;
    
    float Analog1Psi = Raw2PSI(Analog1Raw);
    lcd.setCursor(0,0);
    if (Analog1Psi<10) lcd.print(' ');
    lcd.print (Analog1Psi);
    lcd.print ("psi");
  
  } // if (currentMillis - timerTextLastms > timerTextInterval)  

}


// Self explanitory
void WriteMenu (int menuID) {
  // Clear the screen ready for menus
  lcd.clear();
  if (menuID == 0)
  {
    lcd.setCursor(0,0);
    lcd.print("<  Main  Menu  >");
    lcd.setCursor(0,1);
    lcd.print("Esc | Enter=Save");
  }
  else if (menuID == 1)
  {
    lcd.setCursor(0,0);
    lcd.print("<Graph MaxBoost>");
    lcd.setCursor(0,1);
    lcd.print(Raw2PSI(BoostMax));
    lcd.print ("psi");
  }
  else if (menuID == 2)
  {
    lcd.setCursor(0,0);
    lcd.print("< Boost  Alarm >");
    lcd.setCursor(0,1);
    lcd.print(Raw2PSI(BoostAlarm));
    lcd.print ("psi");
  }
  // Unknown Menu ID.. oh noes!
  else
  {
    lcd.setCursor(0,0);
    lcd.print("<  Undef Menu  >");
    lcd.setCursor(0,1);
    lcd.print("menuID: ");
    lcd.print(menuID);
  }
}



float Raw2PSI(int value){
  float result;
  result = map(value, 0, 1023, 0, 5000);
  result = (0.04+((result/1000)/(0.004*5)))*kpa2psi;
  return result;
}






/* void padding( int number, byte width ) {
  int currentMax = 10;
  char returnString[width];
  
  for (byte i = 0; i < width-1; i++){
    if (number < currentMax) {
	returnString[i]=("0");
    }
    currentMax *= 10;
  }
  // ToDo: Loop over the rest of the string, add to returnString and return
  Serial.print(number);
} 

*/