Login

Everything You Need To Know To Find The Best eltek flatpack2 voltage adjustment

Author: Ada

Oct. 28, 2024

42

0

Communicate and control Eltek Flatpack 2 HE

Code: Select all

If you are looking for more details, kindly visit kelingyizhi.

For more eltek flatpack2 voltage adjustmentinformation, please contact us. We will provide professional answers.

// Include libraries #include <mcp_can.h> #include <SPI.h> #include <Wire.h> enum State_enum { START, SELECT, PLOT, INIT, MAIN, DONE, STOP, END }; // Stated declaration State_enum state; // Constant declaration // newData MASK const uint8_t statusFPMaster = B; const uint8_t statusFPSlave1 = B; const uint8_t statusFPSlave2 = B; const uint8_t statusBMSMain = B; const uint8_t statusBMSHiLo = B; const uint8_t statusBMStemp = B; const uint8_t statusFPall = B; const uint8_t statusAllCAN = B; // stopReason MASK const uint8_t stopDone = B; const uint8_t stopButton = B; const uint8_t stopLowVoltage = B; const uint8_t stopTemperature = B; const uint8_t stopBMS = B; const uint8_t stopWatchdog = B; // chargerState MASK const uint8_t chargerStateCurrentLimiting = B; const uint8_t chargerStateCurrentRegulating = B; const uint8_t chargerStateEndVoltage = B; // Timing constants const uint32_t timePeriod100ms = 100; // Delay 100ms const uint32_t timePeriod1s = ; // Delay, 1s const uint32_t timePeriod3s = ; // Delay 3s const uint32_t timePeriod5s = ; // Delay, 5s const uint32_t timePeriod30s = ; // Delay 30s // Configuration const uint16_t startVoltage = ; // Set start voltage to 43.70 V (divide by 100) const uint16_t initialLimitVoltage = ; // Set switch voltage to 49.00 V (divide by 100), must be lower than end voltage const uint16_t endVoltage = ; // Set end voltage to 50.40 V (divide by 100) const uint16_t overVoltage = ; // Set the overVoltage protection limit at 51.10 V (divide by 100) const uint16_t maxCurrent1x10AAC = 135; // set charge current to 13.5 A (divide by 10) for max 10AAC at 230V const uint16_t maxCurrent1x16AAC = 216; // set charge current to 21.6 A (divide by 10) for max 16AAC at 230V const uint16_t maxCurrent3x16AAC = 600; // set charge current to 60.0 A (divide by 10), no limit, for 3-phase 16A const uint16_t maxCurrent = 700; // Set slave maximum current to 70.0 A (divide by 10) const uint16_t endCurrent = 10; // Set endCurrent to 1.0 A (divide by 10) const uint16_t lowestCellVoltageLimit = ; // Set the lowest voltage acceptable to allow charging const int16_t maxAllowedTemperature = 70; // Set max allowed BMS card temperature const int8_t temperatureCorrection[4] = {1, 5, 0, 1}; // Display commands const uint8_t address = 0x3C; const uint8_t commands = 0x00; const uint8_t onecommand = 0x80; const uint8_t data = 0x40; const uint8_t onedata = 0xC0; // Variable declaration // For FlatPacks uint8_t mainBMS[8]; uint8_t highLowBMS[8]; uint8_t tempBMS[8]; uint16_t measuredMasterCurrent; uint8_t newData = 0; uint8_t stopReason = 0; uint8_t chargerState = 0; // Set pin number const uint8_t SPI_CS_PIN0 = 10; // CAN0, BMS const uint8_t SPI_CS_PIN1 = 15; // CAN1, FlatPack Master (Current limiting) const uint8_t SPI_CS_PIN2 = 14; // CAN2, FlatPack Slave 1 const uint8_t SPI_CS_PIN3 = 16; // CAN3, FlatPack Slave 2 const uint8_t threePhasePIN = 17; // Input PIN for 3-phase detection const uint8_t contactorPIN = 9; // Contactor control and +12V supply to BMS const uint8_t buttonPIN = 8; // Button to select charge current // Set CS pin for CAN-buses MCP_CAN CAN0(SPI_CS_PIN0); MCP_CAN CAN1(SPI_CS_PIN1); MCP_CAN CAN2(SPI_CS_PIN2); MCP_CAN CAN3(SPI_CS_PIN3); // Function declaration // For FlatPack void chargerMain(); void voltageControl(); uint16_t chargeCurrentCalc(); void checkLowestCell(); int16_t checkTemperature(); void updateDisplay(); void plotChargerState(); void stopCharging(); void BMSStopCharging(); void readCAN(); uint16_t readMasterCAN(); uint16_t readSlave1CAN(); uint16_t readSlave2CAN(); void sendCAN(); void sendFlatPackCAN(); void sendMasterCAN(); void sendSlave1CAN(); void sendSlave2CAN(); // HMI void clearDisplay(); void initDisplay(); void plotChar(); void plotText(); void plotValue(); void moveMarker(); uint16_t selectCurrent(); void buttonStopCharging(); // OLED display // Character set for text - stored in program memory const uint8_t CharMap[96][6] PROGMEM = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 32: "Space" { 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00 }, // 33: ! { 0x00, 0x07, 0x00, 0x07, 0x00, 0x00 }, // 34: " { 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00 }, // 35: # { 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00 }, // 36: $ { 0x23, 0x13, 0x08, 0x64, 0x62, 0x00 }, // 37: % { 0x36, 0x49, 0x56, 0x20, 0x50, 0x00 }, // 38: & { 0x00, 0x08, 0x07, 0x03, 0x00, 0x00 }, // 39: ' { 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00 }, // 40: ( { 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00 }, // 41: ) { 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00 }, // 42: * { 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00 }, // 43: + { 0x00, 0x80, 0x70, 0x30, 0x00, 0x00 }, // 44: , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 }, // 45: - { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 }, // 46: . { 0x20, 0x10, 0x08, 0x04, 0x02, 0x00 }, // 47: / { 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00 }, // 48: 0 { 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00 }, // 49: 1 { 0x72, 0x49, 0x49, 0x49, 0x46, 0x00 }, // 50: 2 { 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00 }, // 51: 3 { 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00 }, // 52: 4 { 0x27, 0x45, 0x45, 0x45, 0x39, 0x00 }, // 53: 5 { 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00 }, // 54: 6 { 0x41, 0x21, 0x11, 0x09, 0x07, 0x00 }, // 55: 7 { 0x36, 0x49, 0x49, 0x49, 0x36, 0x00 }, // 56: 8 { 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00 }, // 57: 9 { 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 }, // 58: : { 0x00, 0x40, 0x34, 0x00, 0x00, 0x00 }, // 59: ; { 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 }, // 60: < { 0x14, 0x14, 0x14, 0x14, 0x14, 0x00 }, // 61: = { 0x00, 0x41, 0x22, 0x14, 0x08, 0x00 }, // 62: > { 0x02, 0x01, 0x59, 0x09, 0x06, 0x00 }, // 63: ? { 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00 }, // 64: @ { 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00 }, // 65: A { 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00 }, // 66: B { 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00 }, // 67: C { 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00 }, // 68: D { 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00 }, // 69: E { 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00 }, // 70: F { 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00 }, // 71: G { 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00 }, // 72: H { 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00 }, // 73: I { 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00 }, // 74: J { 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00 }, // 75: K { 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00 }, // 76: L { 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00 }, // 77: M { 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00 }, // 78: N { 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00 }, // 79: O { 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00 }, // 80: P { 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00 }, // 81: Q { 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00 }, // 82: R { 0x26, 0x49, 0x49, 0x49, 0x32, 0x00 }, // 83: S { 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00 }, // 84: T { 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00 }, // 85: U { 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00 }, // 86: V { 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00 }, // 87: W { 0x63, 0x14, 0x08, 0x14, 0x63, 0x00 }, // 88: X { 0x03, 0x04, 0x78, 0x04, 0x03, 0x00 }, // 89: Y { 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00 }, // 90: Z { 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00 }, // 91: [ { 0x02, 0x04, 0x08, 0x10, 0x20, 0x00 }, // 92: backslash { 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00 }, // 93: ] { 0x04, 0x02, 0x01, 0x02, 0x04, 0x00 }, // 94: ^ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x00 }, // 95: _ { 0x00, 0x03, 0x07, 0x08, 0x00, 0x00 }, // 96: ` { 0x20, 0x54, 0x54, 0x78, 0x40, 0x00 }, // 97: a { 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00 }, // 98: b { 0x38, 0x44, 0x44, 0x44, 0x28, 0x00 }, // 99: c { 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00 }, // 100: d { 0x38, 0x54, 0x54, 0x54, 0x18, 0x00 }, // 101: e { 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00 }, // 102: f { 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00 }, // 103: g { 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00 }, // 104: h { 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00 }, // 105: i { 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00 }, // 106: j { 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00 }, // 107: k { 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00 }, // 108: l { 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00 }, // 109: m { 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00 }, // 110: n { 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 }, // 111: o { 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00 }, // 112: p { 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00 }, // 113: q { 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00 }, // 114: r { 0x48, 0x54, 0x54, 0x54, 0x24, 0x00 }, // 115: s { 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00 }, // 116: t { 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00 }, // 117: u { 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00 }, // 118: v { 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00 }, // 119: w { 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 }, // 120: x { 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00 }, // 121: y { 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00 }, // 122: z { 0x00, 0x08, 0x36, 0x41, 0x00, 0x00 }, // 123: { { 0x00, 0x00, 0x77, 0x00, 0x00, 0x00 }, // 124: | { 0x00, 0x41, 0x36, 0x08, 0x00, 0x00 }, // 125: } { 0x00, 0x06, 0x09, 0x06, 0x00, 0x00 }, // 126: degree symbol = '~' { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 } // 127: DEL }; /******** * SETUP * ********/ void setup() { pinMode(buttonPIN, INPUT_PULLUP); pinMode(contactorPIN, OUTPUT); digitalWrite(contactorPIN, LOW); Wire.begin(); initDisplay(); clearDisplay(); //Serial.begin(); while (CAN_OK != CAN0.begin(MCP_STDEXT, CAN_250KBPS, MCP_8MHZ)) // Init car CAN bus : baudrate = 250k { delay(100); } CAN0.init_Mask(0,0,0x07FF); // Init first mask CAN0.init_Filt(0,0,0x); // Init first filter CAN0.init_Filt(1,0,0x); // Init second filter CAN0.init_Mask(1,0,0x07FF); // Init second mask CAN0.init_Filt(2,0,0x); // Init third filter CAN0.init_Filt(3,0,0x); // Init fouth filter CAN0.init_Filt(4,0,0x); // Init fifth filter CAN0.init_Filt(5,0,0x); // Init sixth filter CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP sends acks to received data. while (CAN_OK != CAN1.begin(MCP_STDEXT, CAN_125KBPS, MCP_8MHZ)) // Init FlatPack Master CAN bus : baudrate = 125k { delay(100); } // These are the status messages ( is not current-limiting, is current limiting = busy with walkin, C in input voltage low) CAN1.init_Mask(0,1,0x1FFFFFFF); // Init first mask CAN1.init_Filt(0,1,0x); // Init first filter CAN1.init_Filt(1,1,0x); // Init second filter CAN1.init_Mask(1,1,0x1FFFFFFF); // Init second mask CAN1.init_Filt(2,1,0x); // Init third filter CAN1.init_Filt(3,1,0x); // Init fouth filter CAN1.init_Filt(4,1,0x); // Init fifth filter CAN1.init_Filt(5,1,0x); // Init sixth filter CAN1.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP sends acks to received data. while (CAN_OK != CAN2.begin(MCP_STDEXT, CAN_125KBPS, MCP_8MHZ)) // Init FlatPack Slave 1 CAN bus : baudrate = 125k { delay(100); } // These are the status messages ( is not current-limiting, is current limiting = busy with walkin, C in input voltage low) CAN2.init_Mask(0,1,0x1FFFFFFF); // Init first mask CAN2.init_Filt(0,1,0x); // Init first filter CAN2.init_Filt(1,1,0x); // Init second filter CAN2.init_Mask(1,1,0x1FFFFFFF); // Init second mask CAN2.init_Filt(2,1,0x); // Init third filter CAN2.init_Filt(3,1,0x); // Init fouth filter CAN2.init_Filt(4,1,0x); // Init fifth filter CAN2.init_Filt(5,1,0x); // Init sixth filter CAN2.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP sends acks to received data. while (CAN_OK != CAN3.begin(MCP_STDEXT, CAN_125KBPS, MCP_8MHZ)) // Init FlatPack Slave 2 CAN bus : baudrate = 125k { delay(100); } // These are the status messages ( is not current-limiting, is current limiting = busy with walkin, C in input voltage low) CAN3.init_Mask(0,1,0x1FFFFFFF); // Init first mask CAN3.init_Filt(0,1,0x); // Init first filter CAN3.init_Filt(1,1,0x); // Init second filter CAN3.init_Mask(1,1,0x1FFFFFFF); // Init second mask CAN3.init_Filt(2,1,0x); // Init third filter CAN3.init_Filt(3,1,0x); // Init fouth filter CAN3.init_Filt(4,1,0x); // Init fifth filter CAN3.init_Filt(5,1,0x); // Init sixth filter CAN3.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP sends acks to received data. state = START; } /******* * LOOP * *******/ void loop() { readCAN(); uint16_t measuredMasterVoltage = readMasterCAN(); uint16_t measuredSlave1Voltage = readSlave1CAN(); uint16_t measuredSlave2Voltage = readSlave2CAN(); chargerMain(measuredMasterVoltage, measuredSlave1Voltage, measuredSlave2Voltage); } /************************************************************************ * Sets the output both master and slave. Checks if charging is complete * ************************************************************************/ void chargerMain(uint16_t measuredMasterVoltage, uint16_t measuredSlave1Voltage, uint16_t measuredSlave2Voltage) { static uint16_t startCapacity; static uint16_t selectedMaxCurrent = 0; uint16_t endCapacity; switch (state) { case START: plotText("U:000.0V T:00", 0, 0); plotChar(126, 13, 0); // Degree symbol plotChar('C', 14, 0); plotText("Is:00.0A I:00.0A", 0, 1); plotText("Cs:00.0Ah C:00.0Ah", 0, 2); plotText("Status:", 0, 3); plotChar('*', 0, 4); plotText("IAC=1x10A", 2, 4); plotText("IAC=1x16A", 2, 5); plotText("IAC=3x16A", 2, 6); state = SELECT; break; case SELECT: static uint32_t lastMillisTimer = millis(); // Reset timer selectedMaxCurrent = selectCurrent(); if(selectedMaxCurrent != 0) { state = PLOT; } if((millis() - lastMillisTimer) > timePeriod30s) { selectedMaxCurrent = maxCurrent1x10AAC; state = PLOT; } break; case PLOT: plotText(" ", 0, 4); plotText(" ", 0, 5); plotText(" ", 0, 6); plotValue(selectedMaxCurrent, 10.0, 1, 3, 1); state = INIT; break; case INIT: digitalWrite(contactorPIN, HIGH); // Turn on contactor and +12V supply to BMS sendFlatPackCAN(startVoltage, startVoltage, selectedMaxCurrent); // Send data if((newData & statusAllCAN) == statusAllCAN) // All FlatPacks and BMS are responding { startCapacity = (mainBMS[4] << 8) + mainBMS[5]; // Battery pack capacity plotValue(startCapacity, 10.0, 1, 3, 2); state = MAIN; } break; case MAIN: if((newData & statusAllCAN) == statusAllCAN) // All FlatPacks and BMS are responding { static uint32_t lastMillisDo = millis(); if(millis() - lastMillisDo >= timePeriod1s) { lastMillisDo = millis(); // Reset timer voltageControl(selectedMaxCurrent, measuredMasterVoltage); checkLowestCell(); int16_t maxTemperature = checkTemperature(); updateDisplay(maxTemperature); } if(((measuredMasterVoltage + measuredSlave1Voltage + measuredSlave2Voltage) >= (endVoltage * 3)) && (measuredMasterCurrent <= endCurrent)) // Check if charging is complete { stopReason = stopDone; state = STOP; } } buttonStopCharging(); BMSStopCharging(); break; case STOP: sendFlatPackCAN(startVoltage, startVoltage, endCurrent); // Send data to stop FlatPack power output delay(); endCapacity = (mainBMS[4] << 8) + mainBMS[5]; // Battery pack capacity if(stopReason & stopDone) // Check if battery capacity needs reset { while(!(mainBMS[6] & B)) // Do until battery capacity is reset { sendCAN(); // Reset BMS battery capacity delay(100); readCAN(); // Readback to check reset } } stopCharging(startCapacity, endCapacity); state = END; break; case END: break; default: // Error break; } } /****************************************** * Sets the FP output voltages and current * ******************************************/ void voltageControl(uint16_t selectedMaxCurrent, uint16_t measuredMasterVoltage) { static uint16_t setMasterVoltage = startVoltage; static uint16_t setSlaveVoltage = startVoltage; static uint16_t limitVoltage = initialLimitVoltage; ((setMasterVoltage + 10) < endVoltage) ? setMasterVoltage += 10 : setMasterVoltage = endVoltage; // Increases setMasterVoltage with 100mV if(measuredMasterVoltage >= limitVoltage) { ((setSlaveVoltage + 10) < endVoltage) ? setSlaveVoltage += 10 : setSlaveVoltage = endVoltage; // Increases setSlaveVoltage with 100mV } if(setSlaveVoltage > limitVoltage) { ((limitVoltage + 10) < endVoltage) ? limitVoltage += 10 : limitVoltage = endVoltage; // Increases limitVoltage with 100mV } uint16_t chargeCurrent = chargeCurrentCalc(selectedMaxCurrent); sendFlatPackCAN(setMasterVoltage, setSlaveVoltage, chargeCurrent); // Send new data newData &= ~statusAllCAN; // Reset FlatPack and BMS bits to check if new data is received if(limitVoltage == endVoltage) // Check and set charger state constant voltage { chargerState |= chargerStateEndVoltage; } } /************************************************************************************ * Calculates the max allowed charging current based on highest battery cell voltage * ************************************************************************************/ uint16_t chargeCurrentCalc(uint16_t selectedMaxCurrent) { uint16_t chargeCurrent; uint16_t highestCellVoltage = (highLowBMS[1] << 8) + highLowBMS[2]; // Highest cell voltage const uint16_t highVoltageLowerLimit = ; // Set highest cell lower voltage for start of current limiting, in mV const uint16_t highVoltageUpperLimit = ; // Set highest cell upper voltage for max current limiting, in mV if(highestCellVoltage < highVoltageLowerLimit) { chargeCurrent = selectedMaxCurrent; } else if((highestCellVoltage >= highVoltageLowerLimit) && (highestCellVoltage <= highVoltageUpperLimit)) { //chargeCurrent = selectedMaxCurrent * (highVoltageUpperLimit - highestCellVoltage) / (highVoltageUpperLimit - highVoltageLowerLimit); chargeCurrent = (11L * highestCellVoltage * highestCellVoltage - L * highestCellVoltage + L) / 49; if (chargeCurrent > selectedMaxCurrent) { chargeCurrent = selectedMaxCurrent; } } else { chargeCurrent = 0; } (chargeCurrent < selectedMaxCurrent) ? chargerState |= chargerStateCurrentRegulating : chargerState &= ~chargerStateCurrentRegulating; // Check and set charger state current regulation return chargeCurrent; } /********************************************************************** * Checks that lowest battery cell is above limit, else stops charging * **********************************************************************/ void checkLowestCell() { uint16_t lowestCellVoltage = (highLowBMS[4] << 8) + highLowBMS[5]; // Lowest cell voltage if(lowestCellVoltage < lowestCellVoltageLimit) { state = STOP; // Abort charging stopReason = stopLowVoltage; } } /***************************************************************************************************************** * Finds max temperature after board temperatures have been corrected, checks if below limit, else stops charging * *****************************************************************************************************************/ int16_t checkTemperature() { int16_t maxTemperature = 0; int16_t tempModule; for(int i=0; i<4; i++) { tempModule = (tempBMS[i*2] << 8) + tempBMS[(i*2)+1]; // BMS module card temperature in degree C tempModule = tempModule - temperatureCorrection[i]; // Correction so all boards show the same temperature for the same ambient temperature if(maxTemperature < tempModule) { maxTemperature = tempModule; } } if(maxTemperature > maxAllowedTemperature) { state = STOP; // Abort charging stopReason = stopTemperature; } return maxTemperature; } /*********************************** * Updates display with latest data * ***********************************/ void updateDisplay(int16_t maxTemperature) { uint16_t capacity = (mainBMS[4] << 8) + mainBMS[5]; // Battery pack remaining capacity uint16_t totalBatteryVoltage = (mainBMS[2] << 8) + mainBMS[3]; // Battery pack total voltage plotValue(totalBatteryVoltage, 10.0, 1, 2, 0); plotValue(maxTemperature, 1, 0, 11, 0); plotValue(measuredMasterCurrent, 10.0, 1, 11, 1); plotValue(capacity, 10.0, 1, 12, 2); plotChargerState(); } /********************************** * Blinks charger state on display * **********************************/ void plotChargerState() { static uint8_t flash = 0; if(flash == 0) { if(!chargerState) { plotText("RV", 7, 3); } else if((chargerState & chargerStateCurrentLimiting) && !(chargerState & chargerStateCurrentRegulating)) { plotText("CC", 7, 3); } else if((chargerState & chargerStateCurrentLimiting) && (chargerState & chargerStateCurrentRegulating)) { plotText("CR", 7, 3); } else if(!(chargerState & chargerStateCurrentLimiting) && (chargerState & chargerStateEndVoltage)) { plotText("CV", 7, 3); } else { plotText("EE", 7, 3); } flash = 1; } else { plotText(" ", 7, 3); flash = 0; } } /********************************************** * Stops charging and prints reason on display * **********************************************/ void stopCharging(uint16_t startCapacity, uint16_t endCapacity) { digitalWrite(contactorPIN, LOW); // Turn off contactor and +12V supply to BMS if(stopReason & stopDone) { plotText("Done! ", 0, 5); } else if (stopReason & stopButton) { plotText("Stop! ", 0, 5); } else if (stopReason & stopLowVoltage) { plotText("LowV! ", 0, 5); } else if (stopReason & stopTemperature) { plotText("Temp! ", 0, 5); } else if (stopReason & stopBMS) { plotText("BMS! ", 0, 5); } else if (stopReason & stopWatchdog) { plotText("Wdog! ", 0, 5); } else { plotText("Err! ", 0, 5); } plotValue((endCapacity - startCapacity), 10.0, 1, 6, 5); plotText("Ah", 10, 5); } /*************************************************** * Stops charging if BMS sends charging not allowed * ***************************************************/ void BMSStopCharging() { if(!(mainBMS[6] & B)) { state = STOP; stopReason = stopBMS; } } /********************************************************************************************* * Checks BMS CAN-bus buffer and if new data is available stores it in appropriate data array * *********************************************************************************************/ void readCAN() { uint32_t rxId; uint8_t len; uint8_t rxBuf[8]; if(CAN_MSGAVAIL == CAN0.checkReceive()) // Check if data is coming { CAN0.readMsgBuf(&rxId, &len, rxBuf); // read data, rxId: message ID, ext: flag extended ID, len: data length, rxBuf: data buf rxId &= 0x7FF; // Remove bits outside of the 11-bits ID if(rxId == 0x180) // Main data from BMS { newData |= statusBMSMain; for(int i=0; i<8; i++) { mainBMS[i] = rxBuf[i]; } } if(rxId == 0x181) // Highest and lowest cell data from BMS { newData |= statusBMSHiLo; for(int i=0; i<8; i++) { highLowBMS[i] = rxBuf[i]; } } if(rxId == 0x182) // Temperature data from BMS { newData |= statusBMStemp; for(int i=0; i<8; i++) { tempBMS[i] = rxBuf[i]; } } } } /***************************************************************************************************************************** * Checks FlatPack Master CAN-bus buffer and if new data is available stores it in appropriate variable. Also resets watchdog * *****************************************************************************************************************************/ uint16_t readMasterCAN() { static uint32_t lastMillisWatchDog = millis(); uint32_t rxId; uint8_t len; uint8_t rxBuf[8]; uint16_t measuredMasterVoltage; if(CAN_MSGAVAIL == CAN1.checkReceive()) // Check if data is coming { CAN1.readMsgBuf(&rxId, &len, rxBuf); // Read data, rxId: message ID, ext: flag extended ID, len: data length, rxBuf: data buf rxId &= 0x1FFFFFFF; // Remove bits outside of the 29-bits ID lastMillisWatchDog = millis(); // Reset WatchDog newData |= statusFPMaster; measuredMasterVoltage = (rxBuf[4] << 8) + rxBuf[3]; // The voltage measured at the output in centiVolt measuredMasterCurrent = (rxBuf[2] << 8) + rxBuf[1]; // The current measured at the output in deciAmpere (rxId == 0x) ? chargerState |= chargerStateCurrentLimiting : chargerState &= ~chargerStateCurrentLimiting; // Check and set charger state current limiting } if((newData & statusFPMaster) && (millis() - lastMillisWatchDog >= timePeriod5s) && (state != END)) { lastMillisWatchDog = millis(); // Reset WatchDog newData &= ~statusFPMaster; state = STOP; // Abort charging stopReason = stopWatchdog; //state = START; } return measuredMasterVoltage; } /******************************************************************************************************** * Checks FlatPack Slave 1 CAN-bus buffer and if new data is available stores it in appropriate variable * ********************************************************************************************************/ uint16_t readSlave1CAN() { uint32_t rxId; uint8_t len; uint8_t rxBuf[8]; uint16_t measuredSlave1Voltage; if(CAN_MSGAVAIL == CAN2.checkReceive()) // check if data is coming { CAN2.readMsgBuf(&rxId, &len, rxBuf); // read data, rxId: message ID, ext: flag extended ID, len: data length, rxBuf: data buf newData |= statusFPSlave1; measuredSlave1Voltage = (rxBuf[4] << 8) + rxBuf[3]; // The voltage measured at the output in centiVolt } return measuredSlave1Voltage; } /******************************************************************************************************** * Checks FlatPack Slave 2 CAN-bus buffer and if new data is available stores it in appropriate variable * ********************************************************************************************************/ uint16_t readSlave2CAN() { uint32_t rxId; uint8_t len; uint8_t rxBuf[8]; uint16_t measuredSlave2Voltage; if(CAN_MSGAVAIL == CAN3.checkReceive()) // check if data is coming { CAN3.readMsgBuf(&rxId, &len, rxBuf); // read data, rxId: message ID, ext: flag extended ID, len: data length, rxBuf: data buf newData |= statusFPSlave2; measuredSlave2Voltage = (rxBuf[4] << 8) + rxBuf[3]; // The voltage measured at the output in centiVolt } return measuredSlave2Voltage; } /****************************************** * Sends reset capacity to BMS via CAN-bus * ******************************************/ void sendCAN() { uint8_t reset[1] = {'Z'}; CAN0.sendMsgBuf(0x170, 0, 1, reset); } /*********************************************************** * Sends setVoltage and setCurrent to FlatPacks via CAN-bus * ***********************************************************/ void sendFlatPackCAN(uint16_t setMasterVoltage, uint16_t setSlaveVoltage, uint16_t setCurrent) { sendMasterCAN(setMasterVoltage, setCurrent); sendSlave1CAN(setSlaveVoltage); sendSlave2CAN(setSlaveVoltage); } /***************************************************************** * Sends setVoltage and setCurrent to FlatPack Master via CAN-bus * *****************************************************************/ void sendMasterCAN(uint16_t setVoltage, uint16_t setCurrent) { uint8_t login[8] = {0x14, 0x43, 0x71, 0x03, 0x97, 0x57, 0x00, 0x00}; //this is the serial number of the flatpack followed by two 00 bytes CAN1.sendMsgBuf(0x, 1, 8, login); //send message to log in uint8_t config[8] = {lowByte(setCurrent), highByte(setCurrent), lowByte(setVoltage), highByte(setVoltage), lowByte(setVoltage), highByte(setVoltage), lowByte(overVoltage), highByte(overVoltage)}; // set rectifiers maxCurrent, outputVoltage and OVP CAN1.sendMsgBuf(0x05FF, 1, 8, config); // short walk-in , for long walk-in set //Serial.print(setVoltage); //Serial.print(" "); //Serial.println(setCurrent); } /*************************************************** * Sends setVoltage to FlatPack Slave 1 via CAN-bus * ***************************************************/ void sendSlave1CAN(uint16_t setVoltage) { uint8_t login[8] = {0x15, 0x10, 0x72, 0x00, 0x77, 0x78, 0x00, 0x00}; //this is the serial number of the flatpack followed by two 00 bytes CAN2.sendMsgBuf(0x, 1, 8, login); //send message to log in uint8_t config[8] = {lowByte(maxCurrent), highByte(maxCurrent), lowByte(setVoltage), highByte(setVoltage), lowByte(setVoltage), highByte(setVoltage), lowByte(overVoltage), highByte(overVoltage)}; // set rectifiers maxCurrent, outputVoltage and OVP CAN2.sendMsgBuf(0x05FF, 1, 8, config); // short walk-in , for long walk-in set //Serial.println(setVoltage); } /*************************************************** * Sends setVoltage to FlatPack Slave 2 via CAN-bus * ***************************************************/ void sendSlave2CAN(uint16_t setVoltage) { uint8_t login[8] = {0x14, 0x22, 0x71, 0x14, 0x90, 0x69, 0x00, 0x00}; //this is the serial number of the flatpack followed by two 00 bytes CAN3.sendMsgBuf(0x, 1, 8, login); //send message to log in uint8_t config[8] = {lowByte(maxCurrent), highByte(maxCurrent), lowByte(setVoltage), highByte(setVoltage), lowByte(setVoltage), highByte(setVoltage), lowByte(overVoltage), highByte(overVoltage)}; // set rectifiers maxCurrent, outputVoltage and OVP CAN3.sendMsgBuf(0x05FF, 1, 8, config); // short walk-in , for long walk-in set //Serial.println(setVoltage); } /*************** * Initiate LCD * ***************/ void initDisplay() { Wire.beginTransmission(address); Wire.write(commands); Wire.write(0xA0); // No flip Wire.write(0xAF); // Display on Wire.write(0x40); // Display start at bottom line Wire.write(0x81); // Set contrast Wire.write(0x00); Wire.endTransmission(); } /**************** * Clear the LCD * ****************/ void clearDisplay() { for (int p = 0 ; p < 8; p++) { Wire.beginTransmission(address); Wire.write(commands); Wire.write(0xB0 + p); // Page Wire.write(0x02); // Column low nibble Wire.write(0x10); // Column high nibble Wire.endTransmission(); for (int q = 0 ; q < 5; q++) { Wire.beginTransmission(address); Wire.write(data); for (int i = 0 ; i < 26; i++) { Wire.write(0x00); } Wire.endTransmission(); } } } /***************************************************************** * Plot an ASCII character with bottom left corner at x and row y * *****************************************************************/ void plotChar (uint8_t c, uint8_t x, uint8_t y) { if(x > 20 || y > 7) return; x = (x * 6) + 1; Wire.beginTransmission(address); Wire.write(commands); Wire.write(0xB0 + y); // Page Wire.write(0x00 + ((x+2) & 0x0F)); // Column low nibble Wire.write(0x10 + ((x+2)>>4)); // Column high nibble Wire.endTransmission(); Wire.beginTransmission(address); Wire.write(data); for (int col=0; col<6; col++) { uint8_t bits = pgm_read_byte(&CharMap[c-32][col]); Wire.write(bits); } Wire.endTransmission(); } /**************************************************** * Plot text starting with bottom left corner at x,y * ****************************************************/ void plotText(String textToPlot, uint8_t x, uint8_t y) { int8_t lengthOfString = textToPlot.length(); int8_t characters[lengthOfString + 1]; textToPlot.toCharArray(characters, (lengthOfString + 1)); for (int i=0; i<lengthOfString; i++) { plotChar(characters[i], x, y); x++; } } /******************************************************* * Plot a value starting with bottom left corner at x,y * *******************************************************/ void plotValue(uint16_t valueToPlot, float division, uint8_t decimal, uint8_t x, uint8_t y) { String textToPlot = String(valueToPlot / division, decimal); plotText(textToPlot, x, y); } /************************************************************** * Reads button and moves marker or selects max charge current * **************************************************************/ uint16_t selectCurrent() { static uint32_t lastMillisButton = millis(); static uint8_t buttonPressed = 0; static uint8_t row = 4; uint16_t selectedMaxCurrent = 0; if(digitalRead(buttonPIN) == HIGH) // Button not pressed { lastMillisButton = millis(); // reset timer buttonPressed &= B110; } else if((millis() - lastMillisButton) > timePeriod100ms) // Button pressed for 100ms { buttonPressed |= B011; } if((buttonPressed == B011) && (millis() - lastMillisButton > timePeriod3s)) // Button pressed for 3s -> select current and stop further marker movment { buttonPressed |= B100; plotChar('-', 1, row); if(row == 4) selectedMaxCurrent = maxCurrent1x10AAC; else if (row == 5) selectedMaxCurrent = maxCurrent1x16AAC; else if (row == 6) selectedMaxCurrent = maxCurrent3x16AAC; } if(buttonPressed == B010) // Button released, before timeout, after having been depressed -> move marker { plotChar(' ', 0, row); row = (row>=6) ? 4 : row + 1; plotChar('*', 0, row); buttonPressed &= B101; } return selectedMaxCurrent; } /****************************************** * Stops charging if button is held for 3s * ******************************************/ void buttonStopCharging() { static uint32_t lastMillisButton = millis(); if(digitalRead(buttonPIN) == HIGH) // Button not pressed { lastMillisButton = millis(); // reset timer } else if((millis() - lastMillisButton) > timePeriod3s) // Button pressed for 3s { state = STOP; stopReason = stopButton; } }

ELTEK Flatpack2 48/ (eaton alternative) - Endless Sphere



Searching for a adaptto charger i've came across with this power supply very similar to the Eaton APR48-3G, but a little better IMO.
I made a little comparison with the two power supplies / module rectifiers:

Operating Voltage range: 85-300V AC (ELTEK) --------- 90-300V AC (EATON)

Efficiency (max): 92.5% (ELTEK) ---------- 92.0% (EATON)

Power output: W @ 185-275Vac (ELTEK) ----------- W @ 208-240Vac (EATON)
850W @ 85Vac (ELTEK) ----------------- 900W @ 100Vac (EATON)

Default output voltage: 53.5V (ELTEK) ---------------- 54.5V (EATON)

Adjustable Voltage range: 43.5-57.6V (ELTEK) -------------- 43.0-57.5V (EATON)

Weight: 1.9kg / 4.2lbs (ELTEK) ----------------- 1.7kg / 3.7lbs (EATON)

Dimensions: 109x41.5x327mm / 4.25x1.69x13" (ELTEK) ------------ 130x42x266mm / 5.1x1.6x10.5" (EATON)

here is the datasheet:
They have also a W version:
and a 48v-60v version:

I bought it new for less than 100EUR with shipping from here:

Pictures:

View attachment 6




Pinout:


Type of connectors:


I've flattened some female bullet connectors to power on and to make a charge test:


I didn't try to push more than W from the ELTEk (i've limited the maximum current from power supply in adaptto to 37.4A).
I will try later to see if i can push more power.

According with the datasheet the ELTEK can adjust the voltage output but i don't know how to adjust it (for now). I know that it is possible with a Module Controller that connects via CAN but without it i don't know how.I really appreciate if someone could help with the voltage adjustment.

Here some user guides and tests that i found about the ELTEK:

Best Regards.

Hello guys,Searching for a adaptto charger i've came across with this power supply very similar to the Eaton APR48-3G, but a little better IMO.I made a little comparison with the two power supplies / module rectifiers:Operating Voltage range:--------- 90-300V AC (EATON)Efficiency (max):---------- 92.0% (EATON)Power output:----------- W @ 208-240Vac (EATON)----------------- 900W @ 100Vac (EATON)Default output voltage:---------------- 54.5V (EATON)Adjustable Voltage range:-------------- 43.0-57.5V (EATON)Weight:----------------- 1.7kg / 3.7lbs (EATON)Dimensions:------------ 130x42x266mm / 5.1x1.6x10.5" (EATON)here is the datasheet: View attachment Datasheet Flatpack2 48-.pdf They have also a W version: View attachment Datasheet - Flatpack2 HE Front End Rectifier.pdf and a 48v-60v version: View attachment Datasheet Flatpack2 48-60- HE.pdf from here: http://www.ebay.com/itm/ Pictures:Pinout:Type of connectors:I've flattened some female bullet connectors to power on and to make a charge test:I didn't try to push more than W from the ELTEk (i've limited the maximum current from power supply in adaptto to 37.4A).I will try later to see if i can push more power.According with the datasheet the ELTEK can adjust the voltage output but i don't know how to adjust it (for now). I know that it is possible with a Module Controller that connects via CAN but without it i don't know how.I really appreciate if someone could help with the voltage adjustment.Here some user guides and tests that i found about the ELTEK: https://www.dropbox.com/sh/m9y36nhvzhc3a66/AADRlqkEZEV8RQ81F7SiAED9a?dl=0 Best Regards.

Are you interested in learning more about eltek always on? Contact us today to secure an expert consultation!

Comments

0

0/2000

Guest Posts

If you are interested in sending in a Guest Blogger Submission,welcome to write for us!

Your Name: (required)

Your Email: (required)

Subject:

Your Message: (required)

Join Us