diff --git a/README.md b/README.md index 2417e0e..9f5e290 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,18 @@ This is a very simple tool to limit the Twizy charge current if you don't have an OVMS. -It can currently only limit the charge current to a fixed level (defined in the config file). +It can limit the charge current to a fixed level (defined in the config file) or use a +coded rotary switch or simple DIP switch for dynamic level adjustment. It can signal +the charging state and active throttling by LEDs. + +See [wiring scheme](extras/Wiring.pdf) for an example using a coded rotary switch. The Arduino needs to be connected to the Twizy CAN bus during the charge process to be able to actively overwrite the charge current control frames. -Note: using an interrupt capable CAN shield is highly recommended. +Note: using an interrupt capable CAN shield is highly recommended. No attempt at +reducing the Arduino current consumption is made, include a power switch or fork and +extend the code for sleep mode (and send me a pull request). ## Info diff --git a/TwizyChargeThrottle/TwizyChargeThrottle.ino b/TwizyChargeThrottle/TwizyChargeThrottle.ino index 1f38339..df83ada 100644 --- a/TwizyChargeThrottle/TwizyChargeThrottle.ino +++ b/TwizyChargeThrottle/TwizyChargeThrottle.ino @@ -13,12 +13,18 @@ * https://www.gnu.org/licenses/lgpl.html * */ -#define TWIZY_CT_VERSION "V1.0 (2019-05-10)" +#define TWIZY_CT_VERSION "V2.0 (2019-05-17)" #include #include #include "TwizyChargeThrottle_config.h" +#if TWIZY_DEBUG >= 1 + #define DEBUG1(cmd) cmd +#else + #define DEBUG1(cmd) +#endif + // CAN interface: MCP_CAN CAN(TWIZY_CAN_CS_PIN); @@ -33,12 +39,23 @@ bool charging = false; // Current level: byte level = 0; +// Throttling level: +#ifdef FIXED_LEVEL + const byte throttle = FIXED_LEVEL; +#else + byte throttle = 0; + #define READ_LEVEL() \ + ( digitalRead(IN_LEVEL_B1) \ + | digitalRead(IN_LEVEL_B2) << 1 \ + | digitalRead(IN_LEVEL_B4) << 2) +#endif + #if TWIZY_CAN_IRQ_PIN > 0 -volatile bool msgReceived = false; -void canISR() { - msgReceived = true; -} + volatile bool msgReceived = false; + void canISR() { + msgReceived = true; + } #endif @@ -50,8 +67,8 @@ void setup() { // Init CAN interface: #if TWIZY_CAN_IRQ_PIN > 0 - pinMode(TWIZY_CAN_IRQ_PIN, INPUT); - attachInterrupt(digitalPinToInterrupt(TWIZY_CAN_IRQ_PIN), canISR, FALLING); + pinMode(TWIZY_CAN_IRQ_PIN, INPUT); + attachInterrupt(digitalPinToInterrupt(TWIZY_CAN_IRQ_PIN), canISR, FALLING); #endif while (CAN.begin(MCP_STDEXT, CAN_500KBPS, TWIZY_CAN_MCP_FREQ) != CAN_OK) { @@ -73,10 +90,24 @@ void setup() { CAN.setMode(MCP_NORMAL); + // Init I/O: + + #ifndef FIXED_LEVEL + pinMode(IN_LEVEL_B1, INPUT); + pinMode(IN_LEVEL_B2, INPUT); + pinMode(IN_LEVEL_B4, INPUT); + throttle = READ_LEVEL(); + #endif + + pinMode(OUT_CHARGING_PIN, OUTPUT); + pinMode(OUT_THROTTLING_PIN, OUTPUT); + digitalWrite(OUT_CHARGING_PIN, LOW); + digitalWrite(OUT_THROTTLING_PIN, LOW); + Serial.println(F("Setup done.")); - Serial.print(F("Throttling configured to current level: ")); - Serial.println((char)('0' + TWIZY_CHARGE_THROTTLE)); + Serial.print(F("Throttling to current level: ")); + Serial.println((char)('0' + throttle)); } @@ -84,9 +115,9 @@ void loop() { while (true) { #if TWIZY_CAN_IRQ_PIN > 0 - // Wait for interrupt signal: - while (!msgReceived); - msgReceived = false; + // Wait for interrupt signal: + while (!msgReceived); + msgReceived = false; #endif // Process CAN read buffer: @@ -98,12 +129,20 @@ void loop() { bool _charging = ((msgBuf[1] & 0x60) == 0x20); - #if TWIZY_DEBUG > 0 if (_charging && !charging) - Serial.println(F("Charge START")); + { + digitalWrite(OUT_CHARGING_PIN, HIGH); + #ifndef FIXED_LEVEL + throttle = READ_LEVEL(); + #endif + DEBUG1(Serial.println(F("Charge START"))); + } else if (!_charging && charging) - Serial.println(F("Charge STOP")); - #endif + { + digitalWrite(OUT_CHARGING_PIN, LOW); + digitalWrite(OUT_THROTTLING_PIN, LOW); + DEBUG1(Serial.println(F("Charge STOP"))); + } charging = _charging; level = 0; @@ -117,31 +156,40 @@ void loop() { if (_level == 0xFF) continue; // init phase, skip - if (_level > TWIZY_CHARGE_THROTTLE) + if (throttle != 0 && _level > throttle) { // overwrite: - msgBuf[0] = TWIZY_CHARGE_THROTTLE; + msgBuf[0] = throttle; CAN.sendMsgBuf(0x155, 0, 8, msgBuf); + digitalWrite(OUT_THROTTLING_PIN, HIGH); + } + else + { + digitalWrite(OUT_THROTTLING_PIN, LOW); } #if TWIZY_DEBUG > 1 - if (_level != level) - { - Serial.print(F("Level ")); - if (_level > TWIZY_CHARGE_THROTTLE) { - Serial.print((char)('0' + _level)); - Serial.print('>'); - Serial.println((char)('0' + TWIZY_CHARGE_THROTTLE)); - } else { - Serial.println((char)('0' + _level)); + if (_level != level) + { + Serial.print(F("Level ")); + if (_level > throttle) { + Serial.print((char)('0' + _level)); + Serial.print('>'); + Serial.println((char)('0' + throttle)); + } else { + Serial.println((char)('0' + _level)); + } } - } #endif level = _level; } } + #ifndef FIXED_LEVEL + throttle = READ_LEVEL(); + #endif + } // while (true) } diff --git a/TwizyChargeThrottle/TwizyChargeThrottle_config.h b/TwizyChargeThrottle/TwizyChargeThrottle_config.h index 8694194..d99e466 100644 --- a/TwizyChargeThrottle/TwizyChargeThrottle_config.h +++ b/TwizyChargeThrottle/TwizyChargeThrottle_config.h @@ -6,19 +6,35 @@ #ifndef _TwizyChargeThrottle_config_h #define _TwizyChargeThrottle_config_h -// Set the charge current throttle level here: +// Charge current throttle levels: +// 7 = 35 A = 2,3 kW (full power, no throttling) // 6 = 30 A = 2,1 kW // 5 = 25 A = 1,7 kW // 4 = 20 A = 1,4 kW // 3 = 15 A = 1,0 kW // 2 = 10 A = 0,7 kW // 1 = 5 A = 0,4 kW -#define TWIZY_CHARGE_THROTTLE 5 +// 0 = no throttling + +// If not using a power level input, define a fixed throttling level like this: +// #define FIXED_LEVEL 5 +// If this is defined, the power level inputs will not be used. + +// Power level input: +// Use an 8 position binary coded rotary switch or a 3 pin DIP switch (or similar), +// define the input ports used here (analog ports may be used as well): +#define IN_LEVEL_B1 3 +#define IN_LEVEL_B2 4 +#define IN_LEVEL_B4 5 + +// Status outputs (e.g. LEDs): +#define OUT_CHARGING_PIN 8 +#define OUT_THROTTLING_PIN 9 // Serial debug output level: // 1 = show charge start/stop // 2 = show current level changes -#define TWIZY_DEBUG 2 +#define TWIZY_DEBUG 0 // Serial interface baud rate: #define SERIAL_SPEED 115200 @@ -27,7 +43,7 @@ #define TWIZY_CAN_MCP_FREQ MCP_16MHZ // Set your CAN CS pin number here: -#define TWIZY_CAN_CS_PIN SS +#define TWIZY_CAN_CS_PIN 10 // Set your CAN IRQ pin here (0 = no IRQ): #define TWIZY_CAN_IRQ_PIN 2 diff --git a/extras/Wiring.fzz b/extras/Wiring.fzz new file mode 100644 index 0000000..32c7fe5 Binary files /dev/null and b/extras/Wiring.fzz differ diff --git a/extras/Wiring.pdf b/extras/Wiring.pdf new file mode 100644 index 0000000..65aebc1 Binary files /dev/null and b/extras/Wiring.pdf differ diff --git a/extras/Wiring.png b/extras/Wiring.png new file mode 100644 index 0000000..3d00f03 Binary files /dev/null and b/extras/Wiring.png differ