Jump to content
HybridZ

Arduino controled gauges


winstonusmc

Recommended Posts

Been working on some arduino integration into my Z for a little while. I have come with the idea of using an Arduino micro controller to give me a level of calibration to the gauges and give the ability to have warning lights that more modern cars have. I also want to broadcast the values on a sort of CANBUS to interact with other systems.

 

I purchased a oil and temp gauge on eBay to mess with. I was going to try to repurpose it as a boost and afr gauge, but the bi-metal strips are not near fast enough to keep up with a boost or afr signal.

 

starting out I have coded warning lights on both the oil and temp gauge. I havent designed a circuit yet for either sensors though. Still just playing around with it for now.

 

20150919_203127_zpsdrirxmyj.jpg

 

I have ordered a few Arduino Pro Minis to mount on custom printed boards that will run the gauges.

Link to comment
Share on other sites


const int tempPin    = A0;

const int batteryPin = A1;

const int oilPin     = A2;  

const int tempOutput = 9;

const int oilOutput  = 10;

const int tempLed    = 12;

const int oilLed     = 13;





int oilPressure = 0;

int coolantTemp = 0;

float sourceVoltage = 0.00; 



void setup() {

  Serial.begin(9600);

  pinMode(tempLed, OUTPUT);

  pinMode(oilLed, OUTPUT);

}



void loop() {

  batteryVoltage();

  tempGauge();

  //oilGauge();

  

  // print the results to the serial monitor:

  Serial.print(" ");

  Serial.print(sourceVoltage);

  Serial.print("V");

  Serial.print(" ");

  Serial.print(coolantTemp);

  Serial.print("*F");

  Serial.print(" ");

  Serial.print(oilPressure);

  Serial.println("psi");

  

  delay(100);

}



void batteryVoltage() {

    sourceVoltage = analogRead(batteryPin) * 0.0198817038;

}



void tempGauge() { 

  

  // gauge variables

  const int sensorCalMin = 0; //minimum sensor value 

  const int sensorCalMax = 1023; //maximum sensor value 

  const int valueMin = 15; //gauge value at 120*

  const int valueMax = 88; //gauge value at 250*

  const int warning = 220; // warning level value

  

  int tempSensor = 0;

  int outputValue = 0;

 

  tempSensor = analogRead(tempPin); // read the analog in value:

  coolantTemp = map(tempSensor, sensorCalMin, sensorCalMax, 0.00, 300.00); //calibration of temp sensor

  outputValue = map(coolantTemp, 120, 250, valueMin, valueMax); //calibration of temp gauge

  outputValue = constrain(outputValue, 0, 100); //Gauge limits

  

  analogWrite(tempOutput, outputValue);

  if (coolantTemp >= (warning)) // Low warning light

  {

    digitalWrite(tempLed, HIGH);

  }

  if (coolantTemp <= (warning - 5)) //Hysteresis for light off

  {

    digitalWrite(tempLed, LOW);

  }

  //Serial for DeBug

  //Serial.print(" Temp Sensor Value = ");

  //Serial.print(tempSensor);

  //Serial.print(" output = ");

  //Serial.print(outputValue);

}



void oilGauge() { 

  

  // gauge variables

  const int sensorCalMin = 0; //minimum sensor value 

  const int sensorCalMax = 1023; //maximum sensor value

  const int valueMin = 41; //gauge value at 0psi

  const int valueMax = 115; //gauge value at 90psi

  const int warning = 15; // warning level value

  

  int oilSensor = 0;

  int outputValue = 0;

 

  // read the analog in value:

  oilSensor = analogRead(oilPin);

  // map it to the range of the analog out:

  oilPressure = map(oilSensor, sensorCalMin, sensorCalMax, 0, 90);

  outputValue = map(oilPressure, 0, 90, valueMin, valueMin);

  outputValue = constrain(outputValue, 0, 120); //Gauge limits

  analogWrite(oilOutput, outputValue);

  if (oilPressure <= (warning)) // Low warning light

  {

    digitalWrite(oilLed, HIGH);

  }

  if (oilPressure >= (warning + 3)) //Hysteresis for light off

  {

    digitalWrite(oilLed, LOW);

  }

}

The code, feel free to critique. I am very new to coding, so I am open to suggestions.

Link to comment
Share on other sites

Looks good to me. Did you consider replacing the needle moving mechanism with a stepper? Or is this to retain stock gauges without any modifications?

 

Logic looks fine to me. Only things I would do are just some convenience and code reducing changes:

  • Move and rename const ints out of methods into global namespace (or whatever it is in processing), eg. oilPressureMax, etc.
  • Generalize the hysteresis idiom into a function (could also use an 'else' clause in front of the second if statement, but that's minor)
  • Generalize the gauge setting into a function, eg. 'setGauge(oilOutput, sensorData, gaugeData)' or something like that.
Link to comment
Share on other sites

DON'T RUN 12V TO ANY OF YOUR PINS!

 

If you're using one of the older Arduinos you can run up to 5v to those pins or 3.3v on the new Dues. You're going to fry that board if you're not using a voltage ladder to step the cars 0v-14v (yes 14v whilst running) down to 0v-5v

 

You're also going to need to use a voltage doubler to get 0v-10v out of the 5v outputs on an older arduino or 2 doublers to get 13.2v out of the new boards outputs.

 

 

One last thing, remember the amperage constraints of the Arduino, you've only got like 200mAh on all output pins combined with a 20mAh (they're rated for a max of 40mAh, but getting that much has been inconsistent for me) limit per pin. Those older gauges are going to suck that up like a sponge. You're not going to be able to work more than 2 or 3 gauges at once without building a more complex driver system (multi channel led driver would work) and many gauges might not work at all.

Example: https://www.youtube.com/watch?v=uDFOjg54TyM -- His 6 modern gauges require about 600mAh to run all of them, that's about 100mAh per gauge... or 5x what is rated for the Arduino per pin and 3x the amount of total current the Arduino can output.

Edited by Midri
Link to comment
Share on other sites

Well if you look close, you will see a NPN transistor that has 12v on it and arduino is hooked into that. Those gauges wouldn't even move on 5v. Tried it with just the potentiometer on 5v. These gauges are crazy slow, so I am looking into alternatives for the third gauge hole, like a oled display.

Link to comment
Share on other sites

A transistor (I personally would use a MOSFET) will work for outputs I suppose if you use PWM drive them with 12v and gate them with 5v/3.3v, but your inputs to actually read the sensors from the engine are all going to be 12v so be careful.

Edited by Midri
Link to comment
Share on other sites

Working with megasquirt has shown me that a normal variable resistor type sensor like a temp sensor uses a 5v signal from the ECU in a voltage divider circuit the same way the Arduino would work. as long as I supply the voltage from the Arduino. In the Datsun gauges it is 12v, but the way I am going to tap into them will be similar to how an ECU does it.

Edited by winstonusmc
Link to comment
Share on other sites

  • 1 month later...

More progress on the gauge setup. I have connected an Arduino to the CANBUS on my Megasquirt 3 to display things that the ECU knows. The whole idea is to run any gauges off of CAN that the ECU provides, like coolant temp, AFR, boost, even oil pressure. This way I simplify wiring and remove extra sensors on the engine.

 

I have ordered an OLED display to insert into the gauge body and may upgrade to a high def color later. I have been working on coding to display the info from the CanBus on the Megasquirt this weekend and have setup a simple LCD displaying MAP and AFR to demonstrate the concept.

 

 

Also the code is hosted on Github:

https://github.com/winstonusmc/arduino/blob/master/arduino_megasquirt_afr_map_gauge


#include <SPI.h>

#include "mcp_can.h"

#include <LiquidCrystal.h>



LiquidCrystal lcd(9, 8, 7, 6, 5, 4);





//raw readings

int seconds = 0;

int pw1 = 0;

int pw2 = 0;

int rpm = 0;



int adv = 0;

float afrtgt1 = 0.0;



float baro = 0;

float MAP = 0;

float mat = 0;

float clt = 0;



int tps = 0;

float bat = 1;

float afr1 = 1;

int cel_status = 0;



unsigned long previousMillis = 0;





unsigned char Flag_Recv = 0;

unsigned char len = 0;

unsigned char buf[8];

INT32U canId = 0x000;

char str[20];





MCP_CAN CAN(10);                                            // Set CS to pin 10



void setup()

{

    Serial.begin(115200);

    

    lcd.begin(16, 2);

    lcd.setCursor(0,0);

    lcd.print("MAP ");

    lcd.setCursor(6,0);

    lcd.print("AFR");

    CAN.begin(CAN_500KBPS);                       // init can bus : baudrate = 500k

    CAN.init_Mask(0,0,0x7ff);                      

    CAN.init_Mask(1,0,0x7ff);                     

    //CAN.init_Filt(0,0,0x5f0);                      

    //CAN.init_Filt(1,0,0x5f2);                      

    //CAN.init_Filt(2,0,0x5f3);                      

    //CAN.init_Filt(3,0,0x0);                      

    //CAN.init_Filt(4,0,0x0);                      

    //CAN.init_Filt(5,0,0x0);                     



}





void loop() {

  canRead();

  //rpmSmoothing();

  canDisplay();

}   



void canRead() {

  if(CAN_MSGAVAIL == CAN.checkReceive()) {         // check if data coming

    CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

    switch (CAN.getCanId()) {

    case 0x5f0:

      seconds = word(buf[0] , buf[1]);

      pw1 = word(buf[2] , buf[3]);

      pw2 = word(buf[4] , buf[5]);

      rpm = word(buf[6] , buf[7]);

      break;

    

    case 0x5f1:  // Group 1

      adv = word(buf[0] , buf[1]);

      afrtgt1 = buf[4];

      //mat = word(buf[4] , buf[5]);

      //clt = word(buf[6] , buf[7]);

      break;

      

    case 0x5f2:  // Group 2

      baro = word(buf[0] , buf[1]);

      MAP = word(buf[2] , buf[3]);

      mat = word(buf[4] , buf[5]);

      clt = word(buf[6] , buf[7]);

      break;

    

    case 0x5f3:   // Group 3

      tps = ((buf[0] * 256) + buf[1]);

      bat = ((buf[2] * 256) + buf[3]);

      afr1 = ((buf[4] * 256) + buf[5]);

      //afr2 = (((buf[6] *256) + buf[7]);

      break;

    }    

  }        

}





void canDisplay() {



  const int interval = 50;

  unsigned long currentMillis = millis();

  //refresh rate

  if (currentMillis - previousMillis >= interval) { //if time elapsed is greater than the signal interval

    previousMillis = currentMillis; //then reset time

    

    // Display to LCD and Serial

    lcd.setCursor (0,1);

    lcd.print((MAP/10), 1);



    lcd.setCursor (6,1);

    lcd.print(afr1/10, 1);

    lcd.setCursor (10,1);

    lcd.print("/1");



 



    Serial.print(" Snds ");

    Serial.print(seconds);

    Serial.print(" RPM ");

    Serial.print(rpm);

    Serial.print(" PW1 ");

    Serial.print(pw1/1000, 2);

    Serial.print(" ADV ");

    Serial.print(adv/10, 1);

    Serial.print(" AFRtgt ");

    Serial.print(afrtgt1/10, 1);

    Serial.print(" AFR ");

    Serial.print(afr1/10, 1);

    Serial.print(" MAP ");

    Serial.print(MAP/10, 1);

    Serial.print(" CLT ");

    Serial.print(clt/10, 1);

    Serial.print(" TPS ");

    Serial.print(tps/10);

    Serial.println(" ");

 

  }

}







Edited by winstonusmc
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...