/* * Lipo-Wächter als Jeti Sensor nach einer Idee von Volker Keck * Die die Zellenspannungen eines Lipos werden der Reihe nach gemessen und * die Zelle mit der geringsten Spannung festgestellt. Die Gesamtspannung, * die Nummer und Spannung der schwächsten Zelle werden via Jeti EX-Protokoll * an den Sender übermittelt. Zusätzlich bedient das Programm auch die Jetibox. */ /* * ******************************************************************* Jeti Sensor EX Telemetry C++ Library Copyright (C) 2017 Bernd Wokoeck *** Extended notice on additional work and copyrights, see header of JetiExProtocol.cpp *** Wiring: Arduino Mini TXD-Pin 0 <-- Receiver "Ext." input (orange cable) Ressources: Uses built in UART of Arduini Mini Pro 328 Version history: 0.90 11/22/2015 created 0.95 12/23/2015 new sample sensors for GPS and date/time 0.96 02/21/2016 comPort number as optional parameter for Teensy in Start(...) sensor device id as optional parameter (SetDeviceId(...)) 0.99 06/05/2016 max number of sensors increased to 32 (set MAX_SENSOR to a higher value in JetiExProtocol.h if you need more) bug with TYPE_6b removed DemoSensor delivers 18 demo values now 1.00 01/29/2017 Some refactoring: - Bugixes for Jetibox keys and morse alarms (Thanks to Ingmar !) - Optimized half duplex control for AVR CPUs in JetiExHardwareSerialInt class (for improved Jetibox key handling) - Reduced size of serial transmit buffer (128-->64 words) - Changed bitrates for serial communication for AVR CPUs (9600-->9800 bps) - EX encryption removed, as a consequence: new manufacturer ID: 0xA409 *** Telemetry setup in transmitter must be reconfigured (telemetry reset) *** - Delay at startup increased (to give receiver more init time) - New HandleMenu() function in JetiexSensor.ini (including more alarm test) - JETI_DEBUG and BLOCKING_MODE removed (cleanup) 1.0.1 02/15/2017 Support for ATMega32u4 CPU in Leonardo/Pro Micro GetKey routine optimized 1.02 03/28/2017 New sensor memory management. Sensor data can be located in PROGMEM 1.03 07/14/2017 Allow all jetibox key combinations (thanks to ThomasL) Disable RX at startup to prevent reception of receiver identification or other junk chars Send dictionary already in serial initialization for the 1st time in order to improve behaviour on telemetry reset 1.04 07/18/2017 dynamic sensor de-/activation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************/ #include "JetiExProtocol.h" #include JetiExProtocol jetiEx; enum { ID_VGES = 1, ID_VMIN, ID_NMIN, ID_VMAX, ID_NMAX, }; JETISENSOR_CONST sensors[] PROGMEM = { // id name unit data type precision 0->0, 1->0.0, 2->0.00 { ID_VGES, "V-gesamt", "V", JetiSensor::TYPE_14b, 2 }, { ID_VMIN, "V-min", "V", JetiSensor::TYPE_14b, 2 }, { ID_NMIN, "Nr-min", "Z", JetiSensor::TYPE_14b, 0 }, { ID_VMAX, "V-max", "V", JetiSensor::TYPE_14b, 2 }, { ID_NMAX, "Nr-max", "Z", JetiSensor::TYPE_14b, 0 }, 0 // end of array }; // symbolische Namen für Ausgänge #define po_sensor 3 // Anschluss für robbe Anlage #define po_led 13 // = interne LED // ******* Programm steuernde Konstanten und Variablen, diese sind jeweils anzupassen // Widerstände der Spannungsteiler // 1 1 2 2 3 3 4 4 5 5 6 6 const float r_st[] = {23, 47, 101, 47, 226, 47, 223, 47, 231, 33, 470, 47}; //const float r_st[] = {1.49, 4.62, 9.91, 5.47, 463, 161.3, 21.84, 4.645, 47.75, 7.90, 219, 32.3}; // Warnschwelle, ab der der Pin D1 auf low gesetzt wird float u_warn = 3.3; // verwendete Referenzspannung für ADC (leider nicht immer wirklich 3,3 bzw. 5,0 V) const float u_ref = 3.2; //3.26; // Testausgabe const char test = 'j'; // bei j erfolgt serielle Testausgabe // ******* Ende der Programmsteuernden Definitionen // ADC-Werte an den Zellen 1 - 6 (Pin A0 bis A5) int adc[6]; // Spannungswerte der Spannungsteiler an den einzelnen Zellen float u_st[6]; // Berechnete Gesamtspannung an den einzelnen Zellen float u_ges[6]; // Zellenspannungen der Zellen 1 - 6 float u_z[6]; // sonstige Definitionen float f_ges; // Faktor für Berechnung der Gesamtspannung an den einzelnen Zellen float u_min; // kleinste ermittelte Zellenspannung float u_max; // größte ermittelte Zellenspannung int i_min; // Index zu u_min int i_max; // Indes zu u_max float adc_faktor; // Faktor zur Umrechnung des ADC-Wertes int i; // Index für For-Schleife int d_level; // down Level Jetibox Eingabe int jeti_umin; // u_min für Jetiprotokoll int jeti_umax; // u_max für Jetiprotokoll int jeti_uges; // u_ges für Jetiprotokoll float jetibox_uges; // u_ges für Jetiboxausgabe static char zeile [17]; // Puffer für Jetiboxausgabe char hife[17]; // Hilfsfeld zur Character Aufbereitung Messwerte // Initialisierungsroutine void setup() { jetiEx.Start( "LiPo-Guard", sensors ); jetiEx.Start( NULL, NULL, JetiExProtocol::SERIAL2 ); jetiEx.SetJetiboxText( JetiExProtocol::LINE1, "Lipo-Guard" ); jetiEx.SetJetiboxText( JetiExProtocol::LINE2, "HE FW V1" ); d_level = 0; pinMode(po_led,OUTPUT); // LED zur Statusanzeige pinMode(po_sensor,OUTPUT); // Pin für robbe Sensor digitalWrite (po_led, LOW); // LED ausschalten digitalWrite (po_sensor, HIGH); // Sensorpin einschalten adc_faktor = u_ref/1023; // Faktor zu Umrechnung des ADC-Wertes in Spannung EEPROM.get(0, u_warn); } // Steuerschleife void loop() { for (i = 0; i < 6; i++) // schleife für alle 6 Spannungsteiler { adc[i] = analogRead(i); // ADC-Wert aktueller Spannungsteiler u_st[i] = adc[i] * adc_faktor; // = Spannung aktueller Spannungsteiler int i2 = i*2; // Index für Spannungsteiler berechnen f_ges = (r_st[i2] + r_st[i2+1])/r_st[i2+1]; // = Faktor für Berechnung Gesamtspannung an aktueller Zelle u_ges[i] = u_st[i] * f_ges; // Gesamtspannung an aktueller Zelle if (i == 0) { u_z[i]=u_ges[i]; // Zellenspannung erste Zelle u_min = u_ges[i]; // erste ist erst mal niedrigste u_max = u_ges[i]; // erste ist auch erst mal höchste i_min = 1; } else { u_z[i] = u_ges[i]-u_ges[i-1]; // Zellenspannung an aktueller Zelle } if (adc[i] < 10) { // beim Duemilanove kommen sporadisch ganz kleine Werte statt 0 break; } if (u_z[i] < u_min) // kleinste Zellenspannung ermitteln { u_min = u_z[i]; // u_min versorgen i_min = i+1; // Zellennummer versorgen } if (u_z[i] > u_max) // höchste Zellenspannung ermitteln { u_max = u_z[i]; // u_min versorgen i_max = i+1; // Zellennummer versorgen } } // next for if (u_min <= u_warn) { // u_warn erreicht oder unterschritten digitalWrite (po_led, HIGH); // interne LED einschalten digitalWrite (po_sensor, LOW); // Sensorpin auf 0 V /* Achtung: Wenn man den SetJetiAlarm für die Jetibox absetzt, dann funktioniert anschließend die Anzeige der Telementriewerte im Sender nicht mehr. Es werden nur noch Striche und keine Werte mehr angezeigt. In der Jetibox-Emulation kommen die Werte jedoch richtig an. Wenn Senderanzeige genutzt werden soll, muss der SetJetiAlarm auskommentiert werden!!! Grund ist unklar??? */ // jetiEx.SetJetiAlarm( 'U' ); // Alarm "U" } else { digitalWrite (po_led, LOW); // interne LED ausschalten digitalWrite (po_sensor, HIGH); // Sensorpin auf VCC } jeti_umin = (u_min + 0.005) * 100; jeti_umax = (u_max + 0.005) * 100; i = i-1; jeti_uges = (u_ges[i] +0.005) * 100; jetibox_uges = u_ges[i]; jetiEx.SetSensorValue( ID_VGES, jeti_uges ); jetiEx.SetSensorValue( ID_VMIN, jeti_umin ); jetiEx.SetSensorValue( ID_NMIN, i_min ); jetiEx.SetSensorValue( ID_VMAX, jeti_umax ); jetiEx.SetSensorValue( ID_NMAX, i_max ); jetiEx.DoJetiSend(); if (d_level == 2) { jetibox_ausgabe_L2 (); } jetibox_eingabe(); } // Ende void loop // Jetibox Eingabe bearbeiten void jetibox_eingabe () { uint8_t c = jetiEx.GetJetiboxKey(); if (c == 0) return; if (c == 0xb0 ) //runter { d_level++; if (d_level == 2) { jetibox_ausgabe_L2 (); } if (d_level >= 3) { jetibox_ausgabe_L3 (); } } if (c == 0xe0 ) // rechts { u_warn = u_warn + 0.1; EEPROM.put(0, u_warn); jetibox_ausgabe_L3(); } if (c == 0x70 ) // links { u_warn = u_warn - 0.1; EEPROM.put(0, u_warn); jetibox_ausgabe_L3 (); } if (c == 0xd0 ) // rauf { d_level--; if (d_level < 0) d_level = 0; if (d_level == 2) { jetibox_ausgabe_L2(); } if (d_level >= 3) { jetibox_ausgabe_L3(); } } } void jetibox_ausgabe_L2 () { dtostrf(u_ges[i], 4, 2, hife); sprintf(zeile, "Uges: %s V", hife); jetiEx.SetJetiboxText( JetiExProtocol::LINE1, zeile ); dtostrf(u_min,3,2,hife); sprintf(zeile, "Umin: %s V (%d)", hife, i_min); jetiEx.SetJetiboxText( JetiExProtocol::LINE2, zeile ); } void jetibox_ausgabe_L3 () { dtostrf(u_warn, 3, 1, hife); sprintf(zeile, "< SW: %s V >", hife); jetiEx.SetJetiboxText( JetiExProtocol::LINE2, zeile ); sprintf(zeile, " ^"); jetiEx.SetJetiboxText( JetiExProtocol::LINE1, zeile); d_level = 3; }