EV car conversion hardware

21 Oct.,2022

 

PTC Heater for Bus

Code: Select all

/*
   EberspaecherHeater.c

   The heater communicates using J1939 protocol. It has to be "woken up" one time with a 0x100 message and then
   must see a "keep alive" to stay active, which is the 0x621 message. The message repetition rate is between
   25 and 100ms intervals.

   The Eberspacher CAN version will work when used with a 33.33Kb SWCAN. The data below is the minimum required
   to turn on the heater. It will operate at approximately 33% of full power. To command higher power, increase
   the value of message 0x1072099 byte 1 (it begins with byte 0) which is 3E below.
   Full power is applied when 85 is used as the value for byte 1. The power will vary based upon inlet
   temperature as the PTC elements increase the resistance with higher temperature.

   ID,         Ext,  LEN,D0,D1,D2,D3,D4,D5,D6,D7

   0x100,      False, 0, 00,00,00,00,00,00,00,00

   0x621,      False, 8, 00,40,00,00,00,00,00,00 - keep alive
   0x13FFE060, True,  0, 00,00,00,00,00,00,00,00 - cmd1
   0x10720099, True,  5, 02,3E,00,00,00,00,00,00 - control
   0x102CC040, True,  8, 01,01,CF,0F,00,51,46,60 - cmd2
   0x10242040, True,  1, 00,00,00,00,00,00,00,00 - cmd3
   0x102740CB, True,  3, 2D,00,00,00,00,00,00,00 - cmd4
   0x102740CB, True,  3, 19,00,00,00,00,00,00,00 - cmd5
*/

// CAN bus id's for frames sent to the heater
#define HCAN_WAKEUP       0x100 // wake up the device
#define HCAN_KEEP_ALIVE   0x621 // keep alive message
#define HCAN_CONTROL      0x10720099 // send power control message
#define HCAN_CMD1 0x13FFE060 // dummy message
#define HCAN_CMD2 0x102CC040 // dummy message
#define HCAN_CMD3 0x10242040 // dummy message
#define HCAN_CMD4 0x102740CB // dummy message
#define HCAN_CMD5 0x102740CB // dummy message

// CAN bus id's for frames received from the heater
//TODO: define correct can ID's, mask and masked id's
#define HCAN_STATUS           0x13FFE09D // receive status message             10011111111111110000010011101
#define CAN_MASK                0x0   // mask for above id's                     00000000000
#define CAN_MASKED_ID           0x0   // masked id for id's from 0x258 to 0x268  00000000000

#define MAX_POWER_WATT 6000

bool heater_running  = 0;
bool heater_request = 0;
uint16_t heater_power_request = 0; // value from 0 to 6000 watt
// uint8_t temp_heater; // in degree C
uint16_t heater_maxpower = 4000;
uint8_t heater_setpoint = 70;
uint8_t heater_derating_point = 55;



CAN_FRAME hcan_wakeup; // frame to send wake-up message
CAN_FRAME hcan_control; // frame to send control messages
CAN_FRAME hcan_keepalive; // frame to send heart beat
CAN_FRAME hcan_cmd1; // frame to send cmd1 message
CAN_FRAME hcan_cmd2; // frame to send cmd2 message
CAN_FRAME hcan_cmd3; // frame to send cmd3 message
CAN_FRAME hcan_cmd4; // frame to send cmd4 message
CAN_FRAME hcan_cmd5; // frame to send cmd5 message
CAN_FRAME hcan_incoming; // the frame sent to GEVCU containing status information


//if (status.analogIn[0] != 0) temp_heater = map(constrain(status.analogIn[0], 0, 2100), 0, 2100, 0, 100);

void setup_heater()
{

  if (Can1.init(CAN_BPS_33333))
  {
    Serial.println("Heater CAN initialization completed.\n"); // Initialize CAN1 - Heater CAN
    Can1.setNumTXBoxes(3);
  }
  else Serial.println("Heater CAN initialization (sync) ERROR\n");

  for (int i = 0; i < 3; i++)
  {
    Can1.setRXFilter(i, 0, 0, true);
  }
  for (int i = 3; i < 7; i++)
  {
    Can1.setRXFilter(i, 0, 0, false);
  }
  
  // switch to normal mode on SW-CAN
  digitalWrite(pin_swcan_mode, 1);

  // 0x621, False, 8, 00,40,00,00,00,00,00,00 - keep alive
  hcan_keepalive.length = 8;
  hcan_keepalive.id = HCAN_KEEP_ALIVE;
  hcan_keepalive.extended = 0;
  hcan_keepalive.rtr = 0;
  hcan_keepalive.data.byte[1] = 0x40;

  // 0x13FFE060, True, 0, 00,00,00,00,00,00,00,00 - cmd1
  hcan_cmd1.length = 8;
  hcan_cmd1.id = HCAN_CMD1;
  hcan_cmd1.extended = 1;
  hcan_cmd1.rtr = 0;

  // 0x102CC040, True, 8, 01,01,CF,0F,00,51,46,60 - cmd2
  hcan_cmd2.length = 8;
  hcan_cmd2.id = HCAN_CMD2;
  hcan_cmd2.extended = 1;
  hcan_cmd2.rtr = 0;
  hcan_cmd2.data.byte[0] = 0x01;
  hcan_cmd2.data.byte[1] = 0x01;
  hcan_cmd2.data.byte[2] = 0xCF;
  hcan_cmd2.data.byte[3] = 0x0F;
  hcan_cmd2.data.byte[4] = 0x00;
  hcan_cmd2.data.byte[5] = 0x51;
  hcan_cmd2.data.byte[6] = 0x46;
  hcan_cmd2.data.byte[7] = 0x60;
  // 0x10242040, True, 1, 00,00,00,00,00,00,00,00 - cmd3

  hcan_cmd3.length = 1;
  hcan_cmd3.id = HCAN_CMD3;
  hcan_cmd3.extended = 1;
  hcan_cmd3.rtr = 0;

  // 0x102740CB, True, 3, 2D,00,00,00,00,00,00,00 - cmd4
  hcan_cmd4.length = 3;
  hcan_cmd4.id = HCAN_CMD4;
  hcan_cmd4.extended = 1;
  hcan_cmd4.rtr = 0;
  hcan_cmd4.data.value = 0;
  hcan_cmd4.data.byte[0] = 0x2d;

  // 0x102740CB, True, 3, 19,00,00,00,00,00,00,00 - cmd5
  hcan_cmd5.length = 3;
  hcan_cmd5.id = HCAN_CMD5;
  hcan_cmd5.extended = 1;
  hcan_cmd5.rtr = 0;
  hcan_cmd5.data.value = 0;
  hcan_cmd5.data.byte[0] = 0x19;

  // 0x10720099, True, 5, 02,3E,00,00,00,00,00,00 - control
  hcan_control.length = 5;
  hcan_control.id = HCAN_CONTROL;
  hcan_control.extended = 1;
  hcan_control.rtr = 0;
}

void heater_cansend()
{
  // map requested power (percentage) to valid range of heater (0 - 0x85)
  hcan_control.data.byte[1] = map(constrain(heater_power_request, 0, MAX_POWER_WATT), 0, MAX_POWER_WATT, 0, 0x85);

  Can1.sendFrame(hcan_keepalive);
  Can1.sendFrame(hcan_cmd1);
  Can1.sendFrame(hcan_control);
  Can1.sendFrame(hcan_cmd2);
  Can1.sendFrame(hcan_cmd3);
  Can1.sendFrame(hcan_cmd4);
  Can1.sendFrame(hcan_cmd5);
}

void run_heater() //do this every 60ms
{
  heater_power_request = 0;
  if (heater_request)
  {
    if (!heater_running)
    {
      //Wake up all SW-CAN devices by switching the transceiver to HV mode and sending the command 0x100 and switching the HV mode off again.
      Serial.print("sending wake-up signal to heater");
      digitalWrite(pin_swcan_mode, 0); // set HV mode

      // 0x100, False, 0, 00,00,00,00,00,00,00,00
      hcan_wakeup.length = 0;
      hcan_wakeup.id = HCAN_WAKEUP;
      hcan_wakeup.extended = 0;
      hcan_wakeup.rtr = 0;
      Can1.sendFrame(hcan_wakeup);

      delay(5);

      digitalWrite(pin_swcan_mode, 1); // set normal mode

      heater_running = 1;
    }
    else
    {
      //Calculate the desired output power based on measured temperature.
      if (heater_request && heater_running && (temp_heater <= heater_setpoint) && 0 /*pump q is running*/) //0 to force me to make sure pump q is programmed
      {
        // if below derating temperature, apply maximum power
        if (temp_heater < heater_derating_point)heater_power_request = heater_maxpower;
        // if between derating temp and target temp calculate derating of maximum power
        else heater_power_request = map(temp_heater, heater_setpoint, heater_derating_point, 0, heater_maxpower);
      }
      heater_cansend();
    }
  }
  else
  {
    heater_power_request = 0;
    heater_cansend();
    heater_running = 0;
  }
}
Guest Posts
*
*
* CAPTCHA
Submit