View Single Post
Old 05-12-2008, 07:37 AM   #43 (permalink)
dcb
needs more cowbell
 
dcb's Avatar
 
Join Date: Feb 2008
Location: ÿ
Posts: 5,038

pimp mobile - '81 suzuki gs 250 t
90 day: 96.29 mpg (US)

schnitzel - '01 Volkswagen Golf TDI
90 day: 53.56 mpg (US)
Thanks: 158
Thanked 269 Times in 212 Posts
2 things:
1. (not related to the signal issue), is a25 battery power? You want the guino to stay on when the key is removed.

2. I didn't get much time this weekend, but the code below will display the low level vcc counts and the injector open time and the number of injector pulses received. It may help with troubleshooting.

(EDIT, this code is defunct, debug has been integrated into main codebase)
Code:
//CHANGE THESE VALUES FOR YOUR CAR/TASTE
boolean debug=true;
unsigned long vssPulsesPerMile=3200; 
//double injectorGPH=20.0;
unsigned long microSecondsPerGallon = 180000000; //injector flow rate
int numberOfCylinders=4; 
int numberOfInjectors=4;
int tankSize=13300;  //in 1000ths of a gallon, this is 13.3 gallons
int brightness[]={0,85,170,255}; //left button cycles through these brightness settings
int brightnessIdx=2;
int contrast=15;  //looks ok when looking down at the display
int currentTripResetTimeout=15;  //minutes
int injectorSettleTime=15;  //microseconds
//DONT CHANGE ANYTHING BELOW THIS LINE
//(well, change at your own risk anyway)

//unsigned long microSecondsPerGallon=1/injectorGPH * 60 * 60 * 100000 * numberOfInjectors;

//Vehicle Interface Pins
int InjectorOpenPin=2;
int InjectorClosedPin=3;
int VSSPin=14; //analog 0

//LCD Pins
int DIPin = 4; // register select RS
int DB4Pin=7; 
int DB5Pin=8; 
int DB6Pin=12; 
int DB7Pin=13;
int ContrastPin=6;
int EnablePin = 5; 
int BrightnessPin=9;

int PiezoPin=10;  //trigger on the injector interrupts
int soundSource=0; //0 for mute, 1 for injector interrupts, 2 for vss interrupts

int lbuttonPin = 17; // Left Button, on analog 3,  
int mbuttonPin = 18; // Middle Button, on analog 4 
int rbuttonPin = 19; // Right Button, on analog 5 

int vssBit = 1;     //  pin14 is a bitmask 8 on port C  
int lbuttonBit = 8; //  pin17 is a bitmask 8 on port C  
int mbuttonBit = 16; // pin18 is a bitmask 16 on port C  
int rbuttonBit = 32; // pin19 is a bitmask 32 on port C  

int buttonState = lbuttonBit + mbuttonBit + rbuttonBit; // start with the buttons in the right state

//overflow counter used by millis()
extern volatile unsigned long timer0_overflow_count;
unsigned long microSeconds (void){
  return ((timer0_overflow_count << 8) + TCNT0) * 4;
}
unsigned long elapsedMicroseconds(unsigned long startMicroSeconds ){
  unsigned long msec = microSeconds();
  if(msec >= startMicroSeconds)
    return msec-startMicroSeconds;
  return 4294967295 - (startMicroSeconds-msec);//someone check my work here
}

//Trip prototype
class Trip{
public:
  unsigned long seconds; //how long has this trip been running
  unsigned long injPulses; //rpm
  unsigned long injHiSec;// seconds the injector has been open
  unsigned long injHius;// microseconds, fractional part of the injectors open 
  unsigned long vssPulses;//from the speedo
  
  //these functions actually return in thousandths
  unsigned long miles();  
  unsigned long gallons();
  unsigned long mpg();  

  unsigned long time(); //mmm:ss  
  
  void update(Trip t);
  void reset();
  Trip();
};

//LCD prototype
class LCD{
public:
  LCD( ) ;
  void gotoXY(int x, int y);
  void print(char * string);
  void init();
  void tickleEnable();
  void cmdWriteSet();
  void LcdCommandWrite(int value);
  void LcdDataWrite(int value);
  int pushNibble(int value);
};

//main objects we will be working with:
unsigned long injHiStart; //for timing injector pulses
LCD lcd;
Trip tmpTrip;
Trip instant;
Trip current;
Trip tank;


void processInjOpen(void){
  injHiStart = microSeconds();
  if(soundSource==1)
    digitalWrite(PiezoPin,HIGH);
}

void processInjClosed(void){
  tmpTrip.injHius += elapsedMicroseconds(injHiStart); 
  tmpTrip.injPulses++;
  if(soundSource==1)
    digitalWrite(PiezoPin,LOW);
}

//attach the vss/buttons interrupt
int vsspinstate=0;
boolean piezoToggle = true;
ISR( PCINT1_vect ){ 
  int p = PINC;//bypassing digitalRead for interrupt performance
  if ((p & vssBit) != (vsspinstate & vssBit)){
    tmpTrip.vssPulses++;
    if(soundSource==2){
      digitalWrite(PiezoPin,piezoToggle?HIGH:LOW);
      piezoToggle!=piezoToggle;
    }
  }
  vsspinstate = p;
  buttonState &= p;
} 

void setup (void){ 
  pinMode(BrightnessPin,OUTPUT);
  analogWrite(BrightnessPin,255-brightness[brightnessIdx]);

  lcd.init();

  lcd.print("OpenGauge       ");
  lcd.gotoXY(0,1);
  lcd.print("         MPGuino");
  pinMode(InjectorOpenPin, INPUT); 
  pinMode(InjectorClosedPin, INPUT); 
  pinMode(VSSPin, INPUT);      
  attachInterrupt(0, processInjOpen, FALLING);
  attachInterrupt(1, processInjClosed, RISING);

  pinMode( PiezoPin, OUTPUT); 

  pinMode( lbuttonPin, INPUT ); 
  pinMode( mbuttonPin, INPUT ); 
  pinMode( rbuttonPin, INPUT );
  

  //"turn on" the internal pullup resistors
  digitalWrite( lbuttonPin, HIGH); 
  digitalWrite( mbuttonPin, HIGH); 
  digitalWrite( rbuttonPin, HIGH); 
  digitalWrite( VSSPin, HIGH); 

  //low level interrupt enable stuff
  PCICR |= (1 << PCIE1); 
  PCMSK1 |= (1 << PCINT8); 
  PCMSK1 |= (1 << PCINT11); 
  PCMSK1 |= (1 << PCINT12); 
  PCMSK1 |= (1 << PCINT13);     

  if (debug) Serial.begin(9600);
  delay(1500);
} 

unsigned long looptime=1000000; //one second
void loop (void){ 
  unsigned long loopStart=microSeconds();

  instant.reset();           //clear instant
  instant.update(tmpTrip);   //"copy" of tmpTrip in instant now
  tmpTrip.reset();           //reset tmpTrip so we don't lose too many interrupts
  current.update(instant);   //use instant to update current
  tank.update(instant);      //use instant to update tank


  updateDisplay(); 

//see if any buttons were pressed
  if(!(buttonState&lbuttonBit)){
    brightnessIdx = (brightnessIdx + 1) % 4;
    analogWrite(BrightnessPin,255-brightness[brightnessIdx]);
  }

  buttonState=lbuttonBit + mbuttonBit + rbuttonBit;//reset the buttons
  
  while (elapsedMicroseconds(loopStart) < (looptime));//

} 


char fBuff[7];//used by format
//format a number into NNN.NN  the number should already be representing thousandths
char * format(unsigned long num){
  unsigned long d = 10000;
  long t;
  int dp=3;
  int l=6;

  //123456 = 123.46
  if(num>9999999){
    d=100000;
    dp=99;
    num/=100;
  }else if(num>999999){
    dp=4;
    num/=10;
  }
    
  unsigned long val = num/10;
  if ((num - (val * 10)) >= 5)  //will the first unprinted digit be greater than 4?
    val += 1;   //round up val
  
  for(int x = 0; x < l; x++){
    if(x==dp)      //time to poke in the decimal point?
      fBuff[x]='.';
    else{
      t = val/d;  
      fBuff[x]= '0' + t%10;//poke the ascii character for the digit.
      val-= t*d;
      d/=10;      
    }
  }
  fBuff[6]= 0;         //good old zero terminated strings 
  return fBuff;
}


void updateDisplay() {
  lcd.gotoXY(0,0);lcd.print("%D");lcd.print(format(instant.injHius*1000));lcd.print(" C");lcd.print(format(instant.injPulses*1000));
  lcd.gotoXY(0,1);lcd.print("VC");lcd.print(format(instant.vssPulses*1000));lcd.print(" T");lcd.print(format(tank.time()));
//  lcd.gotoXY(0,2);lcd.print("TC");lcd.print(format(tank.vssPulses*1000));lcd.print(" G");lcd.print(format(tank.gallons()));
  
}


void updateDisplay2() {
  lcd.gotoXY(0,0);
  lcd.LcdDataWrite(7); //special IN character
//  lcd.print(format(instant.miles()));
  lcd.print(format(123456));
  lcd.LcdDataWrite(0); //half of the M/G symbol
  lcd.LcdDataWrite(1); //other half of the M/G symbol
//  lcd.print(format(current.mpg()));
  lcd.print(format(tank.time()));
  lcd.LcdDataWrite(6); //special CU character
  lcd.gotoXY(0,1);
  lcd.LcdDataWrite(5); //special MI character
//  lcd.print(format(tank.miles()));
  lcd.print(format(1234567));
  lcd.LcdDataWrite(2); //half of the TK symbol
  lcd.LcdDataWrite(3); //other half of the TK symbol
  //lcd.print(format(memoryTest()));
//  lcd.print(format(tank.gallons()));
  lcd.print(format(12345678));
  lcd.LcdDataWrite(4); //special GA character
}

Trip::Trip(){
}

unsigned long Trip::miles(){
  return (vssPulses*1000)/vssPulsesPerMile;
}

unsigned long  Trip::gallons(){
  return (injHius*1000)/microSecondsPerGallon;
}

unsigned long  Trip::mpg(){
  
  unsigned long mi=miles();
  unsigned long gal=gallons();
  if (gal==0) gal=1;//default to a thousandth of a gallon so not division by zero
  return mi*1000/gal;
}

//return the seconds as a time mmm.ss, eventually hhh:mm too
unsigned long Trip::time(){
//  return seconds*1000;
  int d = 60;
//  if(seconds/60 > 999) d = 3600; //scale up to hours.minutes if we get past 999 minutes
  return ((seconds/d)*1000) + ((seconds%d) * 10); 
}


void Trip::update(Trip t){
  seconds++;  //we call update once a second
  injPulses+=t.injPulses;
  vssPulses+=t.vssPulses;
  injHius+=t.injHius;
  if (injHius>=1000000){  //rollover into the injHiSec counter
    injHiSec++;
    injHius=1000000-injHius;
  }

}

void Trip::reset(){
  seconds=0;
  injPulses=0;
  injHius=0;
  injHiSec=0;
  vssPulses=0;
}


//LCD functions
LCD::LCD(){
}
//x=0..16, y= 0..1
void LCD::gotoXY(int x, int y){
  if (debug) Serial.println("");
  int dr=x+0x80;
  if (y==1) 
    dr += 0x40;
  if (y==2) 
    dr += 0x14;
  if (y==3) 
    dr += 0x54;
  lcd.LcdCommandWrite(dr);  
}

void LCD::print(char * string){
  if (debug) Serial.print(string);
  int x = 0;
  char c = string[x];
  while(c != 0){
    lcd.LcdDataWrite(c); 
    x++;
    c = string[x];
  }
}

//do the lcd initialization voodoo
void LCD::init(){
  pinMode(EnablePin,OUTPUT); 
  pinMode(DIPin,OUTPUT); 
  pinMode(DB4Pin,OUTPUT); 
  pinMode(DB5Pin,OUTPUT); 
  pinMode(DB6Pin,OUTPUT); 
  pinMode(DB7Pin,OUTPUT); 
  delay(500);

  LcdCommandWrite(0b0010);  // 4 bit operation  

  LcdCommandWrite(0b00101000);// 4-bit interface, 2 display lines, 5x8 font 
  LcdCommandWrite(0b00001100);  // display control: 
  LcdCommandWrite(0b00000110);  // entry mode set: increment automatically, no display shift 


  LcdCommandWrite(0b01000000);  // set cgram
  //create some custom characters
  byte chars[]={//if you squint, you can kind of see the characters below.  see the 'N' in the lower right?
  //     M/,G             T,K          GA      MI      CU      IN
    0b00101,0b00000,0b00000,0b00000,0b01100,0b10100,0b01100,0b11100,
    0b00111,0b00100,0b00000,0b00000,0b10000,0b11100,0b10000,0b01000,
    0b00101,0b01000,0b00111,0b10100,0b10100,0b10100,0b10000,0b01000,
    0b00101,0b10000,0b00010,0b11000,0b01100,0b10100,0b01100,0b11100,
    0b00000,0b01100,0b00010,0b10100,0b00010,0b00111,0b00101,0b01001,
    0b00001,0b10000,0b00010,0b10100,0b00101,0b00010,0b00101,0b01101,
    0b00010,0b10100,0b00000,0b00000,0b00111,0b00010,0b00101,0b01011,
    0b00100,0b01100,0b00000,0b00000,0b00101,0b00111,0b00111,0b01001};
    
    for(int x=0;x<8;x++)  
      for(int y=0;y<8;y++)  
          //LcdDataWrite(chars[y*8+x]); //write the character data to the character generator ram

  LcdCommandWrite(0x00000001);  // clear display, set cursor position to zero   

  LcdCommandWrite(0x10000000);  // set dram to zero 

  analogWrite(ContrastPin,contrast);
}  

void  LCD::tickleEnable(){ 
  // send a pulse to enable 
  digitalWrite(EnablePin,HIGH); 
  delayMicroseconds(1);  // pause 1 ms according to datasheet 
  digitalWrite(EnablePin,LOW); 
  delayMicroseconds(1);  // pause 1 ms according to datasheet 
}  

void LCD::cmdWriteSet(){ 
  digitalWrite(EnablePin,LOW); 
  delayMicroseconds(1);  // pause 1 ms according to datasheet 
  digitalWrite(DIPin,0); 
} 

int LCD::pushNibble(int value){ 
  digitalWrite(DB7Pin, value & 128); 
  value <<= 1; 
  digitalWrite(DB6Pin, value & 128); 
  value <<= 1; 
  digitalWrite(DB5Pin, value & 128); 
  value <<= 1; 
  digitalWrite(DB4Pin, value & 128); 
  value <<= 1; 
  return value;
}

void LCD::LcdCommandWrite(int value){ 
  value=pushNibble(value);
  cmdWriteSet(); 
  tickleEnable(); 
  value=pushNibble(value);
  cmdWriteSet(); 
  tickleEnable(); 
  delay(2); 
} 

void LCD::LcdDataWrite(int value){ 
  digitalWrite(DIPin, HIGH); 
  value=pushNibble(value);
  tickleEnable(); 
  value=pushNibble(value);
  tickleEnable(); 
  delay(2); 
} 


// this function will return the number of bytes currently free in RAM
int memoryTest() {
  int byteCounter = 0; // initialize a counter
  byte *byteArray; // create a pointer to a byte array
  while ( (byteArray = (byte*) malloc (byteCounter * sizeof(byte))) != NULL ) {
    byteCounter++; // if allocation was successful, then up the count for the next try
    free(byteArray); // free memory after allocating it
  }
  free(byteArray); // also free memory after the function finishes
  return byteCounter; // send back the highest number of bytes successfully allocated
}
__________________
WINDMILLS DO NOT WORK THAT WAY!!!

Last edited by dcb; 05-20-2008 at 01:55 AM..
  Reply With Quote