Mitsubishi Outlander PHEV heater

Mitsubishi hybrid drive unit hacking
Turbopete
Posts: 75
Joined: Mon Aug 30, 2021 8:42 pm

Re: Mitsubishi Outlander PHEV heater

Post by Turbopete »

Got it working nicely now! Love the display output aswell - very useful!
Attachments
3D3D4876-77B4-4CD9-B8DA-161B6720BB37.jpeg
User avatar
Bigpie
Posts: 1594
Joined: Wed Apr 10, 2019 8:11 pm
Location: South Yorkshire, UK
Has thanked: 75 times
Been thanked: 303 times

Re: Mitsubishi Outlander PHEV heater

Post by Bigpie »

Nice :D I am pretty pleased with the display.
VW Beetle 2003
Outlander front generator
Prius Gen 3 inverter (EVBMW logic board)
Outlander charger
3x Golf GTE batteries
Chademo Charging
Outlander water heater
Turbopete
Posts: 75
Joined: Mon Aug 30, 2021 8:42 pm

Re: Mitsubishi Outlander PHEV heater

Post by Turbopete »

It’s awesome and great work! I’d like to add a safety delay to switching off the water pump until the temp is back down to say 30 degrees C! Probably have to make it permantly live tho to ensure it runs even when the ignition is switched off. Either that or just get a delayed relay!
arber333
Posts: 3261
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 232 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

Turbopete wrote: Thu Dec 29, 2022 8:04 pm It’s awesome and great work! I’d like to add a safety delay to switching off the water pump until the temp is back down to say 30 degrees C! Probably have to make it permantly live tho to ensure it runs even when the ignition is switched off. Either that or just get a delayed relay!
Hm... you could readback the heater CAN temp byte4 and run the pump when temp is higher than X. It would require a transistor and a relay, but you would have a circulation system independant of heat source. I wanted to built similar heating myself. On one side Outlander heater run by a DUE uC and on the other Webasto fuel heater. I wanted to use Webasto pump to also run when Outlander heater would be ON.
Turbopete
Posts: 75
Joined: Mon Aug 30, 2021 8:42 pm

Re: Mitsubishi Outlander PHEV heater

Post by Turbopete »

Interesting development today - the heater wouldnt start until the temperature got above -1 degrees C!
Turbopete
Posts: 75
Joined: Mon Aug 30, 2021 8:42 pm

Re: Mitsubishi Outlander PHEV heater

Post by Turbopete »

arber333 wrote: Thu Dec 29, 2022 9:52 pm Hm... you could readback the heater CAN temp byte4 and run the pump when temp is higher than X. It would require a transistor and a relay, but you would have a circulation system independant of heat source. I wanted to built similar heating myself. On one side Outlander heater run by a DUE uC and on the other Webasto fuel heater. I wanted to use Webasto pump to also run when Outlander heater would be ON.
I like this idea - it will be my next mini project i think!
User avatar
Bigpie
Posts: 1594
Joined: Wed Apr 10, 2019 8:11 pm
Location: South Yorkshire, UK
Has thanked: 75 times
Been thanked: 303 times

Re: Mitsubishi Outlander PHEV heater

Post by Bigpie »

Turbopete wrote: Sat Jan 21, 2023 12:35 pm Interesting development today - the heater wouldnt start until the temperature got above -1 degrees C!
Not at computer at min, is the temp feedback unsigned, I made that mistake early on, might not have pushed the change?
VW Beetle 2003
Outlander front generator
Prius Gen 3 inverter (EVBMW logic board)
Outlander charger
3x Golf GTE batteries
Chademo Charging
Outlander water heater
User avatar
EV_Builder
Posts: 1199
Joined: Tue Apr 28, 2020 3:50 pm
Location: The Netherlands
Has thanked: 16 times
Been thanked: 33 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by EV_Builder »

arber333 wrote: Thu Dec 29, 2022 9:52 pm Hm... you could readback the heater CAN temp byte4 and run the pump when temp is higher than X. It would require a transistor and a relay, but you would have a circulation system independant of heat source. I wanted to built similar heating myself. On one side Outlander heater run by a DUE uC and on the other Webasto fuel heater. I wanted to use Webasto pump to also run when Outlander heater would be ON.
Maybe an takeover relais construction would perform better. So if relais of pump is switched on everything is fed/switched from that relais too.
In that way when you turn of the car and pump runs it keeps running until it should turn off and everything will turn off then.
Converting an Porsche Panamera
see http://www.wdrautomatisering.nl for bespoke BMS modules.
royhen99
Posts: 210
Joined: Sun Feb 20, 2022 4:23 am
Location: N. Wiltshire. UK
Has thanked: 16 times
Been thanked: 98 times

Re: Mitsubishi Outlander PHEV heater

Post by royhen99 »

Temerature is unsigned in the version I have

//temperatures
unsigned int temp1 = msg.buf[3] - 40;
unsigned int temp2 = msg.buf[4] - 40;
tom91
Posts: 1305
Joined: Fri Mar 01, 2019 9:15 pm
Location: Bristol
Has thanked: 102 times
Been thanked: 216 times

Re: Mitsubishi Outlander PHEV heater

Post by tom91 »

Yes it should be signed, as they have an offset of -40. so if the recieved value is lower then 40 it would just roll over.
Founder Volt Influx https://www.voltinflux.com/
Webstore: https://citini.com/
User avatar
Peter
Posts: 310
Joined: Fri Dec 14, 2018 9:07 pm
Location: North West Lancs, UK
Been thanked: 8 times

Re: Mitsubishi Outlander PHEV heater

Post by Peter »

Hi Forum. For anyone interested I took the top off my PHEV heater.... cos I am nosey :-)
Pics reveal heater connections etc.
IMG_2454.JPG
IMG_2455.JPG
IMG_2456.JPG
Ctwidle
Posts: 89
Joined: Wed Jan 06, 2021 9:44 pm
Been thanked: 11 times

Re: Mitsubishi Outlander PHEV heater

Post by Ctwidle »

Probably a very basic question but what does the coolant pump require more than just 12v and ground to run? I can see two signal wires in the loom that go to the VCU but I’m not sure what they do.
Alibro
Posts: 853
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 265 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Does anyone know if the 7807A021 will operate the same?
It is going for a good price here
https://ebay.us/xxCqz2
I need a bigger hammer!
User avatar
Bigpie
Posts: 1594
Joined: Wed Apr 10, 2019 8:11 pm
Location: South Yorkshire, UK
Has thanked: 75 times
Been thanked: 303 times

Re: Mitsubishi Outlander PHEV heater

Post by Bigpie »

Looks the same as the one I've got in the Beetle.
VW Beetle 2003
Outlander front generator
Prius Gen 3 inverter (EVBMW logic board)
Outlander charger
3x Golf GTE batteries
Chademo Charging
Outlander water heater
Alibro
Posts: 853
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 265 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Bigpie wrote: Fri Jan 19, 2024 4:47 pm Looks the same as the one I've got in the Beetle.
I hope so, I just ordered one. :o
I need a bigger hammer!
arber333
Posts: 3261
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 232 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

Alibro wrote: Fri Jan 19, 2024 6:50 pm I hope so, I just ordered one.
I used two different P/Ns and they both operate on the same commands.
Alibro
Posts: 853
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 265 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

arber333 wrote: Fri Jan 19, 2024 9:56 pm I used two different P/Ns and they both operate on the same commands.
Thanks mate, I'll report back when it arrives.
I need a bigger hammer!
Alibro
Posts: 853
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 265 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Turbopete wrote: Tue Dec 20, 2022 5:17 pm Scratch that last question - i figured out that my code was still wrong! This is the code that i am using now:

Code: Select all

#include <mcp_can.h>
#include <SPI.h>
#include <TaskScheduler.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define INVERTPOT true
#define OPENINVERTERCONTACTORS //uncomment to check can bus for Open Inverter opmode for contactors, prevents heating over precharge resistor
#ifdef OPENINVERTERCONTACTORS
unsigned long inverterLastRec;
byte inverterStatus;
#endif
unsigned long temperatureLastRec;


#define MAXTEMP 85
#define MINTEMP 40
unsigned int targetTemperature = 0;
bool enabled = false;
bool hvPresent = false;
bool heating = false;
int power = 20;
int currentTemperature = 0;
const int potPin = A0;
const int ledPin = 3;

long unsigned int canId;
unsigned char len = 0;
unsigned char buf[8];
char msgString[128];                        // Array to store serial string



#define CAN_INT 2                              // Set INT to pin 2
MCP_CAN CAN(10);                               // Set CS to pin 10

void ms10Task();
void ms100Task();
void ms1000Task();

Task ms10(10, -1, &ms10Task);
Task ms100(100, -1, &ms100Task);
Task ms1000(1000, -1, &ms1000Task);

Scheduler runner;

void setup() {
    Serial.begin(115200);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
      Serial.println(F("SSD1306 allocation failed"));
      for(;;); // Don't proceed, loop forever
    }
    displayOff();
    Serial.println("Outlander Heater Control");
    pinMode(ledPin, OUTPUT);
    
    //while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_8MHz))              // init can bus : baudrate = 500k
    //while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ))
      // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
//    Serial.println("MCP2515 Initialized Successfully!");
      Serial.println("CAN BUS Shield init ok!");
  else
//    Serial.println("Error Initializing MCP2515...");
      Serial.println("CAN BUS Shield init fail");
      
  CAN.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN_INT, INPUT);                            // Configuring pin for /INT input
  
 // Serial.println("MCP2515 Library Receive Example...");
 

    Serial.println("CAN BUS Shield init ok!");

    runner.init();

    runner.addTask(ms10);
    ms10.enable();

    runner.addTask(ms100);
    ms100.enable();

    runner.addTask(ms1000);
    ms1000.enable();

}

void displayTemperature(void) {
  display.clearDisplay();
  display.setTextSize(3); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 10);
  display.print(currentTemperature);
  display.print("/");
  display.print(targetTemperature);

  if (power == 2) {
      display.fillRect(0, 0, 10, SCREEN_HEIGHT, SSD1306_WHITE);
  } else if (power == 1) {
      display.fillRect(0, SCREEN_HEIGHT/2, 10, SCREEN_HEIGHT, SSD1306_WHITE);
  }

  display.display();      // Show initial text
}

void displayOff(void) {
  display.clearDisplay();
  display.setTextSize(3); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(40, 10);
  display.println(F("Off"));
  display.display();      // Show initial text
}


void ms10Task() {
  //send 0x285
   uint8_t canData[8];
   canData[0] = 0x00;
   canData[1] = 0x00;
   canData[2] = 0x14;
   canData[3] = 0x21;
   canData[4] = 0x90;
   canData[5] = 0xFE;
   canData[6] = 0x0C;
   canData[7] = 0x10;

   CAN.sendMsgBuf(0x285, 0, sizeof(canData), canData);
}

void ms100Task() {
  int sensorValue = analogRead(potPin);

  if (INVERTPOT) {
    if (sensorValue < 923) {
      enabled = true;
    } else {
      enabled = false;
    }
  } else {
    if (sensorValue > 100) {
      enabled = true;
    } else {
      enabled = false;
    }
  }

  //if heater is not sending feedback, disable it, safety and that
  if (millis() - temperatureLastRec > 1000) {
    enabled = false;
    Serial.println("No Temperature recieved");
  }

  if (INVERTPOT) {
      targetTemperature = map(sensorValue, 1023, 100, MINTEMP, MAXTEMP);
  } else {
      targetTemperature = map(sensorValue, 100, 1023, MINTEMP, MAXTEMP);
  }

    //send 0x188
  #ifdef OPENINVERTERCONTACTORS
  bool contactorsClosed = inverterStatus == 0x01;
  if (!contactorsClosed) {
    enabled = false;
  }
  #else
  bool contactorsClosed = true;
  #endif

  digitalWrite(ledPin, enabled);

  if (enabled) {
    displayTemperature();
  } else {
    displayOff();
  }
   

  if (contactorsClosed && enabled && currentTemperature < targetTemperature) {
   uint8_t canData[8];
   canData[0] = 0x03;
   canData[1] = 0x50;
   canData[3] = 0x4D;
   canData[4] = 0x00;
   canData[5] = 0x00;
   canData[6] = 0x00;
   canData[7] = 0x00;

   //switch to lower power when reaching target temperature
   if (currentTemperature < targetTemperature - 10) {
    canData[2] = 0xA2;
    power = 2;
   } else {
    canData[2] = 0x32;
    power = 1;
   }
   
    CAN.sendMsgBuf(0x188, 0, sizeof(canData), canData);
  } else {
    power = 0;
  }

}


void ms1000Task() {
  Serial.println("Heater Status");
  Serial.print("HV Present: ");
  Serial.print(hvPresent);
  Serial.print(" Heater Active: ");
  Serial.print(heating);
  Serial.print(" Water Temperature: ");
  Serial.print(currentTemperature);
  Serial.println("C");
  Serial.println("");
  Serial.println("Settings");
  Serial.print(" Heating: ");
  Serial.print(enabled);
  Serial.print(" Desired Water Temperature: ");
  Serial.print(targetTemperature);
  Serial.print(" Inverter: ");
  Serial.print(inverterStatus);
  Serial.println("");
  Serial.println("");

}

void loop() {
  // put your main code here, to run repeatedly:
  runner.execute();
  //if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
  //{
       //CAN.readMsgBuf(&canId, &len, buf);    // read data,  len: data length, buf: data buf
       //unsigned int canId = CAN.getCanId(); this line can be removed
       //if (canId == 0x398) {

if(!digitalRead(CAN_INT))                         // If CAN_INT pin is low, read receive buffer
  {
    CAN.readMsgBuf(&canId, &len, buf);      // Read data: len = data length, buf = data byte(s)
    
    if((canId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
      sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (canId & 0x1FFFFFFF), len);
    else
      sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", canId, len);
  
    //Serial.print(msgString);
  
    if((canId & 0x40000000) == 0x40000000){    // Determine if message is a remote request frame.
      sprintf(msgString, " REMOTE REQUEST FRAME");
      //Serial.print(msgString);
    } else {
      for(byte i = 0; i<len; i++){
        sprintf(msgString, " 0x%.2X", buf[i]);
        //Serial.print(msgString);
      }
    }
 //       unsigned int canId = CAN.getCanId();
        if (canId == 0x398) {
          //Heater status
          if (buf[5] == 0x00) {
            heating = false;
            power = 0;
          } else if (buf[5] > 0) {
            heating = true;
          }
          //hv status
          if (buf[6] == 0x09) {
            hvPresent = false;
          } else if (buf[6] == 0x00) {
            hvPresent = true;
          }

          //temperatures
          unsigned int temp1 = buf[3] - 40;
          unsigned int temp2 = buf[4] - 40;
          if (temp2 > temp1) {
            currentTemperature = temp2;
          } else {
            currentTemperature = temp1;
          }
          temperatureLastRec = millis();
        }
        #ifdef OPENINVERTERCONTACTORS
        if (canId == 0x02) {
          inverterLastRec = millis();
          inverterStatus = buf[0];
        }
        #endif

    }

    #ifdef OPENINVERTERCONTACTORS
//      if(inverterLastRec + 500 < millis()) {
//        inverterStatus = 0;
//      }
    #endif
  }

Apologies for the untidyness - im learning!
Hi guys
My heater has arrived and I'm setting up a test station to confirm I can control it before ripping the car apart.
IMG_20240203_133204081.jpg
But I need a little guidance with the Arduino side of things as I'm pretty clueless at programming. I have the sketch above from Turbopete on a nano and can see it sending 0285 message so hopefully that bit is OK.
IMG_20240203_141102052_HDR.jpg
This sketch seems to include control for a display but I cannot find any thread showing details of model or how it was connected.
Also can anyone please advise the resistance of the POT and how to connect it? It looks like the wiper of the POT is on A0 but where does the other side go? Is it just 5V?

EDIT: I did a search for Adafruit 128 x 32 OLED displays and found this. https://www.adafruit.com/product/4440
Is this the right one?

Thanks guys
I need a bigger hammer!
Alibro
Posts: 853
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 265 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

I only managed an hour or so at it today but managed to get hot water pumping. :)
IMG_20240204_150908144.jpg
I could see 10A at 250V
IMG_20240204_150914264.jpg
IMG_20240204_151128961.jpg

I only had a 4k7 pot connected between ground and A0 so not sure if that is suitable as I think the heat requested was around 85C and it wouldn't drop below that. I think I could see a 10k pot in a previous photo from Jamie so I'll dig one out and give it a go. Does this sound correct?
I need a bigger hammer!
User avatar
Bigpie
Posts: 1594
Joined: Wed Apr 10, 2019 8:11 pm
Location: South Yorkshire, UK
Has thanked: 75 times
Been thanked: 303 times

Re: Mitsubishi Outlander PHEV heater

Post by Bigpie »

Pot size irrelevant, connect one side to gnd, other to vcc and wiper to A0
VW Beetle 2003
Outlander front generator
Prius Gen 3 inverter (EVBMW logic board)
Outlander charger
3x Golf GTE batteries
Chademo Charging
Outlander water heater
arber333
Posts: 3261
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 232 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

Alibro wrote: Sun Feb 04, 2024 5:07 pm I only had a 4k7 pot connected between ground and A0 so not sure if that is suitable as I think the heat requested was around 85C and it wouldn't drop below that. I think I could see a 10k pot in a previous photo from Jamie so I'll dig one out and give it a go. Does this sound correct?
I dont fuss with the pot. I simply use a digital input and internal CAN loop. I use this for the pump too. So when heater temp is lower than 50deg i request full power, when it is at 50deg i lower this to halfh and when heater reaches 55deg i terminate the request. This keeps heater output at 50deg in general which saves kWh acc to Q = m*c*dT. I may up the temp to 60deg if this will not be enough.
Alibro
Posts: 853
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 265 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Thanks guys,
Doing family stuff atm but will have another look later.
I need a bigger hammer!
Alibro
Posts: 853
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 265 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

It works a treat!!! :D

I connected the 4k7 pot as instructed and commented out the Openinverter precharge safety checks and it works perfectly with the water temp following the requested temp.
I already have a 12V circuit which only goes live after the main positive contactor kicks in so I'll use that to power the heater when it is installed.
I've also ordered a couple of OLED displays so I'll have a go at getting them to work.

Thanks again guys for your help with this as I'm very much standing on your shoulders here.

I was a little surprised at how hot the case of the heater got and couldn't help thinking it is a pity to loose all that heat but I suspect I'm too late trying to capture it as I would need to have custom designed some kind of enclosure with fans.
arber333 wrote: Sun Feb 04, 2024 5:31 pm I dont fuss with the pot. I simply use a digital input and internal CAN loop. I use this for the pump too. So when heater temp is lower than 50deg i request full power, when it is at 50deg i lower this to halfh and when heater reaches 55deg i terminate the request. This keeps heater output at 50deg in general which saves kWh acc to Q = m*c*dT. I may up the temp to 60deg if this will not be enough.
My coding skills are virtually zero so now I have it working I think I'll leave well alone. :P
I need a bigger hammer!
arber333
Posts: 3261
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 232 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

Alibro wrote: Mon Feb 05, 2024 4:10 pm was a little surprised at how hot the case of the heater got and couldn't help thinking it is a pity to loose all that heat but I suspect I'm too late trying to capture it as I would need to have custom designed some kind of enclosure with fans.
Like i said heater wants to go all the way to 85deg if you let it. Thats a waste of power. I wanted to use a limit to lower this to 55 as the kj are less there = less kWh.
May i use your posted code to setup my loop instead of pot? It should work on any teensy...? Or do you use teensy?
arber333
Posts: 3261
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 232 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

I went through the code quickly and eliminated anything connected with pot.
I used Heater_pin which is the same pin as A0 analog, only digital side... i think it is D14
Then i removed reading of desired temperature as i find it unneccesary. I removed cconnected conditional as well.

The way this code works is to transmitt complete 0x188 telegram each 100ms. If we toggle the switch to GND(pullup) it will command heater to turn ON. It reads its own temperature and govern the loop by 5deg hysteresis if not turning OFF when reaching 55deg. You can of course set any temperature in code. You could even use the pot to set variable for desired temperature and use a different pin to start the process. I may go and write another code...

See if it works directly as you can load the pot directly to GND to activate the pin with the same circuit. But i would change to toggle switch soon.

Code: Select all

#include <mcp_can.h>
#include <SPI.h>
#include <TaskScheduler.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define INVERTPOT true
#define OPENINVERTERCONTACTORS //uncomment to check can bus for Open Inverter opmode for contactors, prevents heating over precharge resistor
#ifdef OPENINVERTERCONTACTORS
unsigned long inverterLastRec;
byte inverterStatus;
#endif
unsigned long temperatureLastRec;


#define MAXTEMP 85
#define MINTEMP 40
bool enabled = false;
bool hvPresent = false;
bool heating = false;
int power = 20;
uint8_t Heatertemp = 0;
//const int potPin = A0;
const int Heater_pin = D14; //What is the equivalent digital input to A0?
const int ledPin = 3;

long unsigned int canId;
unsigned char len = 0;
unsigned char buf[8];
char msgString[128];                        // Array to store serial string



#define CAN_INT 2                              // Set INT to pin 2
MCP_CAN CAN(10);                               // Set CS to pin 10

void ms10Task();
void ms100Task();
void ms1000Task();

Task ms10(10, -1, &ms10Task);
Task ms100(100, -1, &ms100Task);
Task ms1000(1000, -1, &ms1000Task);

Scheduler runner;

void setup() {
    Serial.begin(115200);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
      Serial.println(F("SSD1306 allocation failed"));
      for(;;); // Don't proceed, loop forever
    }
    displayOff();
    Serial.println("Outlander Heater Control");
    pinMode(ledPin, OUTPUT);
    pinMode(Heater_pin,INPUT_PULLUP); // set Heater pin to input with using built in pull up resistor    
     
    //while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_8MHz))              // init can bus : baudrate = 500k
    //while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ))
      // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
//    Serial.println("MCP2515 Initialized Successfully!");
      Serial.println("CAN BUS Shield init ok!");
  else
//    Serial.println("Error Initializing MCP2515...");
      Serial.println("CAN BUS Shield init fail");
      
  CAN.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN_INT, INPUT);                            // Configuring pin for /INT input

 // Serial.println("MCP2515 Library Receive Example...");
 

    Serial.println("CAN BUS Shield init ok!");

    runner.init();

    runner.addTask(ms10);
    ms10.enable();

    runner.addTask(ms100);
    ms100.enable();

    runner.addTask(ms1000);
    ms1000.enable();

}

void displayTemperature(void) {
  display.clearDisplay();
  display.setTextSize(3); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 10);
  display.print(currentTemperature);
  display.print("/");
//  display.print(targetTemperature);

  if (power == 2) {
      display.fillRect(0, 0, 10, SCREEN_HEIGHT, SSD1306_WHITE);
  } else if (power == 1) {
      display.fillRect(0, SCREEN_HEIGHT/2, 10, SCREEN_HEIGHT, SSD1306_WHITE);
  }

  display.display();      // Show initial text
}

void displayOff(void) {
  display.clearDisplay();
  display.setTextSize(3); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(40, 10);
  display.println(F("Off"));
  display.display();      // Show initial text
}


void ms10Task() {
  //send 0x285
   uint8_t canData[8];
   canData[0] = 0x00;
   canData[1] = 0x00;
   canData[2] = 0x14;
   canData[3] = 0x21;
   canData[4] = 0x90;
   canData[5] = 0xFE;
   canData[6] = 0x0C;
   canData[7] = 0x10;

   CAN.sendMsgBuf(0x285, 0, sizeof(canData), canData);
}

void ms100Task() {
  int sensorValue = analogRead(potPin);

//  if (INVERTPOT) {
//    if (sensorValue < 923) {
//      enabled = true;
//    } else {
//      enabled = false;
//    }
//  } else {
//    if (sensorValue > 100) {
//      enabled = true;
//    } else {
//      enabled = false;
//    }
//  }

  //if heater is not sending feedback, disable it, safety and that
  if (millis() - temperatureLastRec > 1000) {
    enabled = false;
    Serial.println("No Temperature recieved");
  }

//  if (INVERTPOT) {
//      targetTemperature = map(sensorValue, 1023, 100, MINTEMP, MAXTEMP);
//  } else {
//      targetTemperature = map(sensorValue, 100, 1023, MINTEMP, MAXTEMP);
//  }

    //send 0x188
  #ifdef OPENINVERTERCONTACTORS
  bool contactorsClosed = inverterStatus == 0x01;
  if (!contactorsClosed) {
    enabled = false;
  }
  #else
  bool contactorsClosed = true;
  #endif

  digitalWrite(ledPin, enabled);

  if (enabled) {
    displayTemperature();
  } else {
    displayOff();
  }
   

  if (contactorsClosed && enabled) {
   uint8_t canData[8];
   if(digitalRead(Heater_pin) == LOW) { // if heater pin is ON 
   canData[0] = 0x03;  }     
    else {
   canData[0] = 0x00;
   }    
   canData[1] = 0x50;
   if(Heatertemp > 55) { // if temp is higher than 55deg     
   canData[2] = 0x00;
        } 
   else if(Heatertemp > 50) { // if temp is higher than 50deg
   canData[2] = 0x32; // seems to be current command (dec/10)
        }         
   else {
   canData[2] = 0xA2;
        } 
   canData[3] = 0x40;            
   canData[4] = 0x00;
   canData[5] = 0x00;
   canData[6] = 0x00;
   canData[7] = 0x00;
 
    CAN.sendMsgBuf(0x188, 0, sizeof(canData), canData);
  } else {
    power = 0;
  }

}


void ms1000Task() {
  Serial.println("Heater Status");
  Serial.print("HV Present: ");
  Serial.print(hvPresent);
  Serial.print(" Heater Active: ");
  Serial.print(heating);
  Serial.print(" Water Temperature: ");
  Serial.print(Heatertemp);
  Serial.println("C");
  Serial.println("");
  Serial.println("Settings");
  Serial.print(" Heating: ");
  Serial.print(enabled);
  Serial.print(" Inverter: ");
  Serial.print(inverterStatus);
  Serial.println("");
  Serial.println("");

}

void loop() {
  // put your main code here, to run repeatedly:
  runner.execute();
  //if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
  //{
       //CAN.readMsgBuf(&canId, &len, buf);    // read data,  len: data length, buf: data buf
       //unsigned int canId = CAN.getCanId(); this line can be removed
       //if (canId == 0x398) {

if(!digitalRead(CAN_INT))                         // If CAN_INT pin is low, read receive buffer
  {
    CAN.readMsgBuf(&canId, &len, buf);      // Read data: len = data length, buf = data byte(s)
    
    if((canId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
      sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (canId & 0x1FFFFFFF), len);
    else
      sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", canId, len);
  
    //Serial.print(msgString);
  
    if((canId & 0x40000000) == 0x40000000){    // Determine if message is a remote request frame.
      sprintf(msgString, " REMOTE REQUEST FRAME");
      //Serial.print(msgString);
    } else {
      for(byte i = 0; i<len; i++){
        sprintf(msgString, " 0x%.2X", buf[i]);
        //Serial.print(msgString);
      }
    }
 //       unsigned int canId = CAN.getCanId();
        if (canId == 0x398) {
          //Heater status
          if (buf[5] == 0x00) {
            heating = false;
            power = 0;
          } else if (buf[5] > 0) {
            heating = true;
          }
          //hv status
          if (buf[6] == 0x09) {
            hvPresent = false;
          } else if (buf[6] == 0x00) {
            hvPresent = true;
          }

          //temperatures
          unsigned int temp1 = buf[3] - 40;
          unsigned int temp2 = buf[4] - 40;
          if (temp2 > temp1) {
            Heatertemp = temp2;
          } else {
            Heatertemp = temp1;
          }
          temperatureLastRec = millis();
        }
        #ifdef OPENINVERTERCONTACTORS
        if (canId == 0x02) {
          inverterLastRec = millis();
          inverterStatus = buf[0];
        }
        #endif

    }

    #ifdef OPENINVERTERCONTACTORS
    #endif
  }
Post Reply