As long as it is not touching the parts they will be OK. It didnt go too high for me as i set it up to no more than 55deg.
If there is water in the lines it diesnt get much hotter than your target.
As long as it is not touching the parts they will be OK. It didnt go too high for me as i set it up to no more than 55deg.
Code: Select all
//I declare variables
uint8_t Htemp = 0;
uint8_t Heatertemp = 0;
//I setup CAN reading
if(incoming.id==0x398){
Htemp = incoming.data.bytes[3] ;
Heatertemp = Htemp-40;
//I use this function and send it at 800ms
void sendCANframeD() { // Heater
outframe.id = 0x188; // 0x188 03 50 A2 40 00 00 00 00
outframe.length = 8; // Data payload 8 bytes
outframe.extended = 0; // Extended addresses - 0=11-bit 1=29bit
outframe.rtr=1; //No request
if(digitalRead(Heater_pin) == LOW) { // if heater pin is ON
outframe.data.bytes[0]=0x03; // when 55deg power goes to 0A
}
else {
outframe.data.bytes[0]=0x00;
}
outframe.data.bytes[1]=0x50; // 50 works
if(Heatertemp > 55) { // if temp is higher than 55deg
outframe.data.bytes[2]=0x00; // when 55deg power goes to 0A
}
else if(Heatertemp > 50) { // if temp is higher than 50deg
outframe.data.bytes[2]=0x32; // seems to be current command (dec/10)
}
else {
outframe.data.bytes[2]=0xA2;
}
outframe.data.bytes[3]=0x40; // 40 works
outframe.data.bytes[4]=0x00; //
outframe.data.bytes[5]=0x00; //
outframe.data.bytes[6]=0x00;
outframe.data.bytes[7]=0x00;
if(debug) {printFrame(&outframe,1);} //If the debug variable is set, show our transmitted frame
if(myVars.CANport==0) Can0.sendFrame(outframe); //Mail it
else Can1.sendFrame(outframe);
}
//I call timer command...
Timer4.attachInterrupt(sendCANframeURGENT).start(10000); // This sets an interrupt time to send an URGENT CAN frame every 10ms.
//To send this function....
void sendCANframeURGENT() {
outframe.id = 0x285; // 0x285 00,00,14,39,91,FE,0C,10 Driving
outframe.length = 8; // Data payload 8 bytes
outframe.extended = 0; // Extended addresses - 0=11-bit 1=29bit
outframe.rtr=1; //No request
outframe.data.bytes[0]=0x00;
outframe.data.bytes[1]=0x00;
if(digitalRead(PP_pin) == HIGH) { // we are driving, no EVSE connected
outframe.data.bytes[2]=0x14; // PP EVSE connected signal
}
else {
outframe.data.bytes[2]=0xB6; //if we sense PP signal we are charging
}
if(digitalRead(BMS_pin) == HIGH) { // if BMS_pin is high
outframe.data.bytes[3]=0x39;
outframe.data.bytes[4]=0x91;
outframe.data.bytes[5]=0xFE;
outframe.data.bytes[6]=0x0E;
outframe.data.bytes[7]=0x10;
}
else {
outframe.data.bytes[3]=0x00;
outframe.data.bytes[4]=0x00;
outframe.data.bytes[5]=0x00;
outframe.data.bytes[6]=0x00;
outframe.data.bytes[7]=0x00;
}
if(debug) {printFrame(&outframe,1);} //If the debug variable is set, show our transmitted frame
if(myVars.CANport==0) Can0.sendFrame(outframe); //Mail it
else Can1.sendFrame(outframe);
}
Thank you for quick reply, did try those quickly with no difference. Bus should be ok, same controller controls mitsubishi charger and other devices. And 0x285 is seen by heater as response byte0 changes to 1. Maybe I'll clean most of other code and try only heater, just to be sure.
I had some trouble with feedback loop because i didnt use uint8_t variables for reading CAN report.evMacGyver wrote: ↑Wed Oct 12, 2022 2:06 pm Thank you for quick reply, did try those quickly with no difference. Bus should be ok, same controller controls mitsubishi charger and other devices. And 0x285 is seen by heater as response byte0 changes to 1. Maybe I'll clean most of other code and try only heater, just to be sure.
I have such a bad luck with heaters, first ampera LIN-bus heater and now mitsubishi, both communicates but no heat. Weather is getting colder![]()
My bad, Ampera Eberspacher is SWCAN indeed. Currently I did not use any conversion on response messages, will investigate more later.arber333 wrote: ↑Wed Oct 12, 2022 7:21 pm I had some trouble with feedback loop because i didnt use uint8_t variables for reading CAN report.
Hm... Ampera heater does not work with LIN bus. It is a SWCAN device. A bit different protocol, but still a single wire bus.
You could try it with Macchina M2. I think it has 2x CAN bus, 1x LIN bus and 1x SWCAN transcievers installed.
OK... if you are pressed for heat i recommend you have a look at dishwasher heaters. It is a 230VAC element setup to provide 1800W. If you use it with 360Vdc i would advise to use two in series for 3600W. Plenty of power, it just needs some regulation. How to shut it off? Use a 20A Nissan precharge relay or similar silver contact HV relay with magnetic inserts.evMacGyver wrote: ↑Wed Oct 12, 2022 7:31 pm My bad, Ampera Eberspacher is SWCAN indeed. Currently I did not use any conversion on response messages, will investigate more later.
Glad we can be of help.evMacGyver wrote: ↑Thu Oct 13, 2022 4:39 pm
I need to add control valves to coolant circuit, so that I can limit battery heat and use car original webasto again. HV heater draws quite a lot of juice..
No, as i used those same lines to power that particular heater in my car last winter.
Please could you tell me which MCP library your using ? Im struggling to get this to compile?Bigpie wrote: ↑Wed Nov 10, 2021 4:55 pm https://github.com/jamiejones85/OutlanderHeaterControl can control it, it's hardcoded for 50 degrees and heating on for now, it overshoots the desired temperature but it works.
Code: Select all
while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ))
Any chance you could give me a pointer as to which bits need to change - ive looked through the examples but im very much a beginner in the world of coding and this has me baffled!royhen99 wrote: ↑Fri Dec 16, 2022 12:43 pm The library has been updated so it no longer uses getCanId. This is now in the readMsgBuf() function. The examples show what needs to change.
Line 60 also needs to change to this.Code: Select all
while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ))
Code: Select all
void loop() {
long unsigned int canId;
unsigned char len = 0;
unsigned char buf[8];
// 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) {
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
}
I simply switched ON the pump with car starting so coolant will flow regardless.