mirror of
https://github.com/dexterbg/Twizy-Virtual-BMS.git
synced 2024-11-18 12:33:57 +00:00
- Added BlazejBMS example
This commit is contained in:
parent
365ee37fa2
commit
71550230e7
3 changed files with 553 additions and 0 deletions
421
examples/BlazejBMS/BlazejBMS.ino
Normal file
421
examples/BlazejBMS/BlazejBMS.ino
Normal file
|
@ -0,0 +1,421 @@
|
||||||
|
/**
|
||||||
|
* ==========================================================================
|
||||||
|
* Blazej's Twizy Lead Acid "BMS"
|
||||||
|
* ==========================================================================
|
||||||
|
*
|
||||||
|
* Hardware setup:
|
||||||
|
* - Arduino Nano + NiRen MCP2515_CAN (16 MHz) + relay + power regulator
|
||||||
|
* - HC-06 Bluetooth module (AltSoftSerial pin 8+9)
|
||||||
|
* Sensors:
|
||||||
|
* - 1x LM35D temperature sensor (PORT_TEMP)
|
||||||
|
* - 4x voltage divider at 60/45/30/15 V (PORT_C1…4)
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* - Michael Balzer <dexter@dexters-web.de>
|
||||||
|
* - Błażej Błaszczyk <blazej.blaszczyk@pascal-engineering.com>
|
||||||
|
*
|
||||||
|
* Libraries used:
|
||||||
|
* - TwizyVirtualBMS https://github.com/dexterbg/Twizy-Virtual-BMS
|
||||||
|
* - MCP_CAN https://github.com/coryjfowler/MCP_CAN_lib
|
||||||
|
* - FlexiTimer2 https://github.com/PaulStoffregen/FlexiTimer2
|
||||||
|
* - AltSoftSerial https://github.com/PaulStoffregen/AltSoftSerial
|
||||||
|
*
|
||||||
|
* License:
|
||||||
|
* This is free software under GNU Lesser General Public License (LGPL)
|
||||||
|
* https://www.gnu.org/licenses/lgpl.html
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BLAZEJ_BMS_VERSION "V2.1.0 (2017-07-05)"
|
||||||
|
|
||||||
|
#include "TwizyVirtualBMS_config.h"
|
||||||
|
#include "TwizyVirtualBMS.h"
|
||||||
|
#include "AltSoftSerial.h"
|
||||||
|
#include "BlazejBMS_config.h"
|
||||||
|
|
||||||
|
TwizyVirtualBMS twizy;
|
||||||
|
|
||||||
|
// Bluetooth software serial port:
|
||||||
|
// Note: AltSoftSerial uses fixed pins!
|
||||||
|
// i.e. Arduino Nano: RX = pin 8, TX = pin 9
|
||||||
|
AltSoftSerial bt;
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// State variables
|
||||||
|
//
|
||||||
|
|
||||||
|
float temp = 20.0;
|
||||||
|
|
||||||
|
float
|
||||||
|
vpack = VMAX_DRV;
|
||||||
|
|
||||||
|
float
|
||||||
|
c1 = VMAX_DRV / 4,
|
||||||
|
c2 = VMAX_DRV / 4,
|
||||||
|
c3 = VMAX_DRV / 4,
|
||||||
|
c4 = VMAX_DRV / 4;
|
||||||
|
|
||||||
|
float
|
||||||
|
soc = 99.0;
|
||||||
|
|
||||||
|
float curr = 0.0;
|
||||||
|
|
||||||
|
int drvpwr = MAX_DRIVE_POWER;
|
||||||
|
int recpwr = MAX_RECUP_POWER;
|
||||||
|
|
||||||
|
int chgcur = MAX_CHARGE_CURRENT;
|
||||||
|
|
||||||
|
unsigned long error = TWIZY_OK;
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Callback: handle state transition for BMS
|
||||||
|
// - called by twizyEnterState() after Twizy handling
|
||||||
|
// Note: avoid complex operations, this needs to be fast.
|
||||||
|
//
|
||||||
|
void bmsEnterState(TwizyState currentState, TwizyState newState) {
|
||||||
|
|
||||||
|
// lower soc to prevent immediate charge stop:
|
||||||
|
if (newState == Init) {
|
||||||
|
if (soc > 99) {
|
||||||
|
soc -= 1;
|
||||||
|
twizy.setSOC(soc);
|
||||||
|
twizy.setChargeCurrent(5);
|
||||||
|
Serial.print(F("bmsEnterState: soc lowered to "));
|
||||||
|
Serial.println(soc, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Callback: timer ticker
|
||||||
|
// - called every 10 ms by twizyTicker() after twizy handling
|
||||||
|
// - clockCnt cyclic range: 0 .. 2999 = 30 seconds (reset to 0 on Off/Init)
|
||||||
|
// Note: avoid complex operations, this needs to be fast.
|
||||||
|
//
|
||||||
|
void bmsTicker(unsigned int clockCnt) {
|
||||||
|
|
||||||
|
// full second?
|
||||||
|
if (clockCnt % 100 != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (twizy.state() != Off) {
|
||||||
|
|
||||||
|
Serial.println(F("\nbmsTicker:"));
|
||||||
|
|
||||||
|
error = TWIZY_OK;
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Read stacked cell voltages
|
||||||
|
//
|
||||||
|
|
||||||
|
c1 = analogRead(PORT_C1) / 1024.0 * SCALE_C1; // 60 V
|
||||||
|
c2 = analogRead(PORT_C2) / 1024.0 * SCALE_C2; // 45 V
|
||||||
|
c3 = analogRead(PORT_C3) / 1024.0 * SCALE_C3; // 30 V
|
||||||
|
c4 = analogRead(PORT_C4) / 1024.0 * SCALE_C4; // 15 V
|
||||||
|
|
||||||
|
#if INPUT_CALIBRATION >= 1
|
||||||
|
// raw output for calibration:
|
||||||
|
Serial.print(F("< raw c1 = ")); Serial.println(c1, 2);
|
||||||
|
Serial.print(F("< c2 = ")); Serial.println(c2, 2);
|
||||||
|
Serial.print(F("< c3 = ")); Serial.println(c3, 2);
|
||||||
|
Serial.print(F("< c4 = ")); Serial.println(c4, 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// derive single cell voltages from stacked voltages:
|
||||||
|
vpack = c1;
|
||||||
|
c1 -= c2;
|
||||||
|
c2 -= c3;
|
||||||
|
c3 -= c4;
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Derive SOC from voltage
|
||||||
|
//
|
||||||
|
// - newsoc = SOC in operation mode voltage range
|
||||||
|
// - soc = smoothed operation mode SOC
|
||||||
|
// (used to derive drive & recup power & charge current)
|
||||||
|
//
|
||||||
|
|
||||||
|
float newsoc;
|
||||||
|
|
||||||
|
// voltage range depends on operation mode:
|
||||||
|
if (twizy.state() == Charging) {
|
||||||
|
newsoc = (vpack - VMIN_CHG) / (VMAX_CHG - VMIN_CHG) * 100.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newsoc = (vpack - VMIN_DRV) / (VMAX_DRV - VMIN_DRV) * 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// smooth...
|
||||||
|
if (newsoc < soc) {
|
||||||
|
// slow adaption to lower voltages:
|
||||||
|
soc = ((soc * (SMOOTH_SOC_DOWN-1)) + newsoc) / SMOOTH_SOC_DOWN;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (twizy.state() == Charging) {
|
||||||
|
// fast adaption while charging:
|
||||||
|
soc = ((soc * (SMOOTH_SOC_UP_CHG-1)) + newsoc) / SMOOTH_SOC_UP_CHG;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// slow adaption while driving:
|
||||||
|
soc = ((soc * (SMOOTH_SOC_UP-1)) + newsoc) / SMOOTH_SOC_UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanitize...
|
||||||
|
soc = constrain(soc, 0.0, 100.0);
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Derive power limits & charge current from SOC
|
||||||
|
//
|
||||||
|
|
||||||
|
// scale down drive power for low SOC:
|
||||||
|
// 100% at FULL → 100% at <SOC1> → <LVL2> at <SOC2> → 0% at EMPTY
|
||||||
|
#define SOC2_DRIVE_POWER ((DRV_CUTBACK_LVL2 / 100.0f) * MAX_DRIVE_POWER)
|
||||||
|
if (soc <= DRV_CUTBACK_SOC2) {
|
||||||
|
float factor = soc / DRV_CUTBACK_SOC2;
|
||||||
|
drvpwr = factor * SOC2_DRIVE_POWER;
|
||||||
|
}
|
||||||
|
else if (soc <= DRV_CUTBACK_SOC1) {
|
||||||
|
float factor = ((soc - DRV_CUTBACK_SOC2) / (DRV_CUTBACK_SOC1 - DRV_CUTBACK_SOC2));
|
||||||
|
drvpwr = SOC2_DRIVE_POWER + (factor * (MAX_DRIVE_POWER - SOC2_DRIVE_POWER));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
drvpwr = MAX_DRIVE_POWER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale down recuperation power & charge current for high SOC:
|
||||||
|
// 0% at FULL → 100% at <CHG_CUTBACK_SOC> → 100% at EMPTY
|
||||||
|
if (soc > 99.99) {
|
||||||
|
// stop charge & reduce recuperation at 100% SOC:
|
||||||
|
recpwr = 500; // TODO: should be 0 when driving, but affects D/R change
|
||||||
|
chgcur = 0;
|
||||||
|
}
|
||||||
|
else if (soc >= CHG_CUTBACK_SOC) {
|
||||||
|
// keep min 1000W / 5A below 100% SOC:
|
||||||
|
float factor = ((100 - soc) / (100 - CHG_CUTBACK_SOC));
|
||||||
|
recpwr = 1000 + (factor * (MAX_RECUP_POWER - 1000));
|
||||||
|
chgcur = 5 + (factor * (MAX_CHARGE_CURRENT - 5));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recpwr = MAX_RECUP_POWER;
|
||||||
|
chgcur = MAX_CHARGE_CURRENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// bmsTicker: Check cell voltage difference (min - max)
|
||||||
|
//
|
||||||
|
|
||||||
|
float cmin = min(c1, min(c2, min(c3, c4)));
|
||||||
|
float cmax = max(c1, max(c2, max(c3, c4)));
|
||||||
|
float cdif = cmax - cmin;
|
||||||
|
|
||||||
|
#if INPUT_CALIBRATION >= 1
|
||||||
|
Serial.print(F("> cmin = ")); Serial.println(cmin, 2);
|
||||||
|
Serial.print(F("> cmax = ")); Serial.println(cmax, 2);
|
||||||
|
Serial.print(F("> cdif = ")); Serial.println(cdif, 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (cdif >= VOLT_DIFF_SHUTDOWN) {
|
||||||
|
// cell difference is critical: emergency shutdown
|
||||||
|
Serial.println(F("!!! VOLT_SHUTDOWN"));
|
||||||
|
bt.println(F("!!! VOLT_SHUTDOWN"));
|
||||||
|
error |= TWIZY_SERV_BATT | TWIZY_SERV_STOP;
|
||||||
|
twizy.enterState(Error);
|
||||||
|
}
|
||||||
|
else if (cdif >= VOLT_DIFF_ERROR) {
|
||||||
|
// cell difference is high: set STOP signal, reduce drive power, stop recuperation & charge:
|
||||||
|
Serial.println(F("!!! VOLT_ERROR"));
|
||||||
|
bt.println(F("!!! VOLT_ERROR"));
|
||||||
|
error |= TWIZY_SERV_BATT | TWIZY_SERV_STOP;
|
||||||
|
drvpwr /= 4;
|
||||||
|
recpwr /= 4;
|
||||||
|
chgcur = 0;
|
||||||
|
}
|
||||||
|
else if (cdif >= VOLT_DIFF_WARN) {
|
||||||
|
// cell difference detected: reduce power & charge levels:
|
||||||
|
Serial.println(F("!!! VOLT_WARN"));
|
||||||
|
bt.println(F("!!! VOLT_WARN"));
|
||||||
|
error |= TWIZY_SERV_BATT;
|
||||||
|
drvpwr /= 2;
|
||||||
|
recpwr /= 2;
|
||||||
|
chgcur = min(chgcur, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Read & check battery temperature
|
||||||
|
//
|
||||||
|
|
||||||
|
float newtemp;
|
||||||
|
|
||||||
|
// dual read _seems_ to yield better results (LM35D issue?)
|
||||||
|
newtemp = analogRead(PORT_TEMP);
|
||||||
|
newtemp = BASE_TEMP + analogRead(PORT_TEMP) / 1024.0 * SCALE_TEMP;
|
||||||
|
|
||||||
|
// raw output for calibration:
|
||||||
|
#if INPUT_CALIBRATION >= 1
|
||||||
|
Serial.print(F("< temp = ")); Serial.println(newtemp, 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// smooth...
|
||||||
|
temp = (temp * (SMOOTH_TEMP-1) + newtemp) / SMOOTH_TEMP;
|
||||||
|
|
||||||
|
if (temp > TEMP_SHUTDOWN) {
|
||||||
|
// battery is burning: emergency shutdown
|
||||||
|
Serial.println(F("!!! TEMP_SHUTDOWN"));
|
||||||
|
bt.println(F("!!! TEMP_SHUTDOWN"));
|
||||||
|
error |= TWIZY_SERV_TEMP | TWIZY_SERV_STOP;
|
||||||
|
twizy.enterState(Error);
|
||||||
|
}
|
||||||
|
else if (temp > TEMP_ERROR) {
|
||||||
|
// battery very hot: set STOP signal, stop recuperation, stop charge:
|
||||||
|
Serial.println(F("!!! TEMP_ERROR"));
|
||||||
|
bt.println(F("!!! TEMP_ERROR"));
|
||||||
|
error |= TWIZY_SERV_TEMP | TWIZY_SERV_STOP;
|
||||||
|
drvpwr /= 4;
|
||||||
|
recpwr = 0;
|
||||||
|
chgcur = 0;
|
||||||
|
}
|
||||||
|
else if (temp > TEMP_WARN) {
|
||||||
|
// battery hot, show warning, reduce recuperation, reduce charge current:
|
||||||
|
Serial.println(F("!!! TEMP_WARN"));
|
||||||
|
bt.println(F("!!! TEMP_WARN"));
|
||||||
|
error |= TWIZY_SERV_TEMP;
|
||||||
|
drvpwr /= 2;
|
||||||
|
recpwr /= 2;
|
||||||
|
chgcur = min(chgcur, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Estimate current level
|
||||||
|
//
|
||||||
|
|
||||||
|
if (twizy.state() == Charging) {
|
||||||
|
curr = chgcur;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// OPTION: derive current estimation from voltage difference:
|
||||||
|
//curr = ((newsoc - soc) / 100) * SCALE_CURRENT + OFFSET_CURRENT;
|
||||||
|
//curr = constrain(curr, -500.0, 500.0);
|
||||||
|
curr = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Update Twizy state
|
||||||
|
//
|
||||||
|
|
||||||
|
#if INPUT_CALIBRATION >= 1
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
twizy.setVoltage(vpack, true);
|
||||||
|
twizy.setCurrent(curr);
|
||||||
|
twizy.setTemperature(temp, temp, true);
|
||||||
|
twizy.setSOC(soc);
|
||||||
|
twizy.setPowerLimits(drvpwr, recpwr);
|
||||||
|
twizy.setChargeCurrent(chgcur);
|
||||||
|
twizy.setError(error);
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Output state to serial port
|
||||||
|
//
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.print(F("- volt = ")); Serial.println(vpack, 1);
|
||||||
|
Serial.print(F("- ...c1 = ")); Serial.println(c1, 1);
|
||||||
|
Serial.print(F("- ...c2 = ")); Serial.println(c2, 1);
|
||||||
|
Serial.print(F("- ...c3 = ")); Serial.println(c3, 1);
|
||||||
|
Serial.print(F("- ...c4 = ")); Serial.println(c4, 1);
|
||||||
|
Serial.print(F("- temp = ")); Serial.println(temp, 1);
|
||||||
|
Serial.print(F("- curr = ")); Serial.println(curr, 1);
|
||||||
|
Serial.println();
|
||||||
|
Serial.print(F("- soc% = ")); Serial.println(soc, 1);
|
||||||
|
Serial.print(F("- drvpwr = ")); Serial.println(drvpwr);
|
||||||
|
Serial.print(F("- recpwr = ")); Serial.println(recpwr);
|
||||||
|
Serial.print(F("- chgcur = ")); Serial.println(chgcur);
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// bmsTicker: Output state to bluetooth port
|
||||||
|
//
|
||||||
|
|
||||||
|
bt.print(FS(twizyStateName[twizy.state()]));
|
||||||
|
bt.print(F(" -- "));
|
||||||
|
bt.print(temp, 1); bt.print(F(" °C -- "));
|
||||||
|
bt.print(soc, 1); bt.print(F(" %SOC -- "));
|
||||||
|
bt.println();
|
||||||
|
if (error != TWIZY_OK) {
|
||||||
|
bt.print(F("ERROR: "));
|
||||||
|
bt.println(error & 0x0fff, HEX);
|
||||||
|
}
|
||||||
|
bt.print(vpack, 1); bt.print(F(" V -- "));
|
||||||
|
bt.print(curr, 1); bt.print(F(" A -- "));
|
||||||
|
bt.print(cdif, 1); bt.print(F(" CD"));
|
||||||
|
bt.println();
|
||||||
|
bt.print(c1, 1); bt.print(F(" C1 -- "));
|
||||||
|
bt.print(c2, 1); bt.print(F(" C2 -- "));
|
||||||
|
bt.print(c3, 1); bt.print(F(" C3 -- "));
|
||||||
|
bt.print(c4, 1); bt.print(F(" C4 -- "));
|
||||||
|
bt.println();
|
||||||
|
bt.println();
|
||||||
|
|
||||||
|
|
||||||
|
} // if (twizy.state() != Off)
|
||||||
|
|
||||||
|
} // bmsTicker()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------
|
||||||
|
// SETUP
|
||||||
|
//
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println(F("Blazej-BMS " BLAZEJ_BMS_VERSION));
|
||||||
|
|
||||||
|
bt.begin(BT_BAUD);
|
||||||
|
|
||||||
|
twizy.begin();
|
||||||
|
twizy.attachTicker(bmsTicker);
|
||||||
|
twizy.attachEnterState(bmsEnterState);
|
||||||
|
|
||||||
|
// Init:
|
||||||
|
twizy.setPowerLimits(drvpwr, recpwr);
|
||||||
|
twizy.setChargeCurrent(chgcur);
|
||||||
|
twizy.setSOC(soc);
|
||||||
|
twizy.setTemperature(temp, temp, true);
|
||||||
|
twizy.setVoltage(vpack, true);
|
||||||
|
twizy.setError(error);
|
||||||
|
|
||||||
|
twizy.setSOH(100);
|
||||||
|
twizy.setCurrent(0.0);
|
||||||
|
|
||||||
|
#if TWIZY_CAN_SEND == 0
|
||||||
|
// Dry run:
|
||||||
|
twizy.enterState(Ready);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------
|
||||||
|
// MAIN LOOP
|
||||||
|
//
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
twizy.looper();
|
||||||
|
}
|
||||||
|
|
88
examples/BlazejBMS/BlazejBMS_config.h
Normal file
88
examples/BlazejBMS/BlazejBMS_config.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* ==========================================================================
|
||||||
|
* Blazej's Twizy Lead Acid "BMS": Configuration
|
||||||
|
* ==========================================================================
|
||||||
|
*/
|
||||||
|
#ifndef _BlazejBMS_config_h
|
||||||
|
#define _BlazejBMS_config_h
|
||||||
|
|
||||||
|
// Bluetooth baud rate: (i.e. 57600 / 38400 / 19200 / 9600)
|
||||||
|
#define BT_BAUD 9600
|
||||||
|
|
||||||
|
// Maximum charge current to use [A]:
|
||||||
|
#define MAX_CHARGE_CURRENT 30
|
||||||
|
// Charge current → power drawn from socket:
|
||||||
|
// 35 A = 2,2 kW
|
||||||
|
// 30 A = 2,1 kW
|
||||||
|
// 25 A = 1,7 kW
|
||||||
|
// 20 A = 1,4 kW
|
||||||
|
// 15 A = 1,0 kW
|
||||||
|
// 10 A = 0,7 kW
|
||||||
|
// 5 A = 0,4 kW
|
||||||
|
|
||||||
|
// Maximum driving & recuperation power limits to use [W]:
|
||||||
|
#define MAX_DRIVE_POWER 18000
|
||||||
|
#define MAX_RECUP_POWER 10000
|
||||||
|
|
||||||
|
// Drive power cutback [%]:
|
||||||
|
// (100% at FULL → 100% at <SOC1>% → <LVL2>% at <SOC2>% → 0% at EMPTY)
|
||||||
|
#define DRV_CUTBACK_SOC1 90
|
||||||
|
#define DRV_CUTBACK_SOC2 45
|
||||||
|
#define DRV_CUTBACK_LVL2 50
|
||||||
|
|
||||||
|
// Charge power cutback [%]:
|
||||||
|
// (100% at EMPTY → 100% at <SOC>% → 0% at FULL)
|
||||||
|
#define CHG_CUTBACK_SOC 85
|
||||||
|
|
||||||
|
// Lead acid voltage range for discharging [V]:
|
||||||
|
#define VMIN_DRV (4 * 11.2)
|
||||||
|
#define VMAX_DRV (4 * 13.0)
|
||||||
|
|
||||||
|
// Lead acid voltage range for charging [V]:
|
||||||
|
#define VMIN_CHG (4 * 12.0)
|
||||||
|
#define VMAX_CHG (4 * 14.4)
|
||||||
|
|
||||||
|
// Analog input port assignment:
|
||||||
|
#define PORT_TEMP A0 // temperature sensor LM35D
|
||||||
|
#define PORT_C1 A1 // voltage divider 60 V
|
||||||
|
#define PORT_C2 A2 // voltage divider 45 V
|
||||||
|
#define PORT_C3 A3 // voltage divider 30 V
|
||||||
|
#define PORT_C4 A4 // voltage divider 15 V
|
||||||
|
|
||||||
|
// Set to 1 to enable input port calibration outputs:
|
||||||
|
#define INPUT_CALIBRATION 0
|
||||||
|
|
||||||
|
// Voltage analog input scaling:
|
||||||
|
#define SCALE_C1 (60.0 / 3.8202247191 * 5.0 * 1.02652)
|
||||||
|
#define SCALE_C2 (45.0 / 4.0909090909 * 5.0 * 1.01857)
|
||||||
|
#define SCALE_C3 (30.0 / 3.7918215613 * 5.0 * 1.02534)
|
||||||
|
#define SCALE_C4 (15.0 / 3.8059701492 * 5.0 * 1.02344)
|
||||||
|
|
||||||
|
// Voltage warning/error thresholds [V]:
|
||||||
|
#define VOLT_DIFF_WARN 3.0
|
||||||
|
#define VOLT_DIFF_ERROR 5.0
|
||||||
|
#define VOLT_DIFF_SHUTDOWN 10.0
|
||||||
|
|
||||||
|
// SOC smoothing [samples]:
|
||||||
|
#define SMOOTH_SOC_DOWN 700 // adaption to lower voltage
|
||||||
|
#define SMOOTH_SOC_UP 400 // adaption to higher voltage
|
||||||
|
#define SMOOTH_SOC_UP_CHG 50 // adaption to higher voltage while charging
|
||||||
|
|
||||||
|
// OPTION: Scale voltage to SOC difference to current [A]:
|
||||||
|
//#define SCALE_CURRENT 150
|
||||||
|
//#define OFFSET_CURRENT -70
|
||||||
|
|
||||||
|
// Temperature analog input scaling:
|
||||||
|
// LM35D: +2 .. +100°, 10 mV / °C => 100 °C = 1.0 V
|
||||||
|
#define BASE_TEMP 2.0
|
||||||
|
#define SCALE_TEMP 500.0
|
||||||
|
|
||||||
|
// Temperature smoothing [samples]:
|
||||||
|
#define SMOOTH_TEMP 30
|
||||||
|
|
||||||
|
// Temperature warning/error thresholds [°C]:
|
||||||
|
#define TEMP_WARN 40
|
||||||
|
#define TEMP_ERROR 45
|
||||||
|
#define TEMP_SHUTDOWN 50
|
||||||
|
|
||||||
|
#endif // _BlazejBMS_config_h
|
44
examples/BlazejBMS/TwizyVirtualBMS_config.h
Normal file
44
examples/BlazejBMS/TwizyVirtualBMS_config.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* ==========================================================================
|
||||||
|
* Twizy Virtual BMS: Configuration
|
||||||
|
* ==========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TwizyVirtualBMS_config_h
|
||||||
|
#define _TwizyVirtualBMS_config_h
|
||||||
|
|
||||||
|
// Serial debug output:
|
||||||
|
// Level 0 = none, only output init & error messages
|
||||||
|
// Level 1 = log state transitions & CAN statistics
|
||||||
|
// Level 2 = log CAN frame dumps (10 second interval)
|
||||||
|
#define TWIZY_DEBUG_LEVEL 1
|
||||||
|
|
||||||
|
// Set to 0 to disable CAN transmissions for testing:
|
||||||
|
#define TWIZY_CAN_SEND 1
|
||||||
|
|
||||||
|
// CAN send timing is normally 10 ms (10.000 us).
|
||||||
|
// You may need to lower this if your Arduino is too slow.
|
||||||
|
#define TWIZY_CAN_CLOCK_US 10000
|
||||||
|
|
||||||
|
// VirtualBMS can use Timer1 (16 bit), Timer2 (8 bit) or Timer3 (16bit)
|
||||||
|
// Select Timer2/3 if you need Timer1 for e.g. AltSoftSerial
|
||||||
|
#define TWIZY_USE_TIMER 2
|
||||||
|
|
||||||
|
// Timer2: precise resolutions depend on CPU type & clock frequency
|
||||||
|
// i.e. Arduino Nano 16 MHz: 1000 = 1 ms / 2000 = 0.5 ms / 5000 = 0.2 ms / 10000 = 0.1 ms
|
||||||
|
// Use lowest resolution possible to minimize side effects on AltSoftSerial
|
||||||
|
#define TWIZY_TIMER2_RESOLUTION 1000
|
||||||
|
|
||||||
|
// Set your MCP clock frequency here:
|
||||||
|
#define TWIZY_CAN_MCP_FREQ MCP_16MHZ
|
||||||
|
|
||||||
|
// Set your SPI CS pin number here:
|
||||||
|
#define TWIZY_CAN_CS_PIN 10
|
||||||
|
|
||||||
|
// If you've connected the CAN module's IRQ pin:
|
||||||
|
#define TWIZY_CAN_IRQ_PIN 2
|
||||||
|
|
||||||
|
// Set your 3MW control pin here:
|
||||||
|
#define TWIZY_3MW_CONTROL_PIN 3
|
||||||
|
|
||||||
|
#endif // _TwizyVirtualBMS_config_h
|
Loading…
Reference in a new issue