Mercurial > public > ostc4
comparison Discovery/Src/bonex_mini.c @ 38:5f11787b4f42
include in ostc4 repository
| author | heinrichsweikamp |
|---|---|
| date | Sat, 28 Apr 2018 11:52:34 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 37:ccc45c0e1ea2 | 38:5f11787b4f42 |
|---|---|
| 1 /////////////////////////////////////////////////////////////////////////////// | |
| 2 /// -*- coding: UTF-8 -*- | |
| 3 /// | |
| 4 /// \file Discovery/Src/bonex_mini.c | |
| 5 /// \brief voltage to battery percentage based on bonex.c for BIS PCB | |
| 6 /// \author Heinrichs Weikamp gmbh | |
| 7 /// \date 26-March-2017 | |
| 8 /// | |
| 9 /// \details | |
| 10 /// | |
| 11 /// $Id$ | |
| 12 /////////////////////////////////////////////////////////////////////////////// | |
| 13 /// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh | |
| 14 /// | |
| 15 /// This program is free software: you can redistribute it and/or modify | |
| 16 /// it under the terms of the GNU General Public License as published by | |
| 17 /// the Free Software Foundation, either version 3 of the License, or | |
| 18 /// (at your option) any later version. | |
| 19 /// | |
| 20 /// This program is distributed in the hope that it will be useful, | |
| 21 /// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 22 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 23 /// GNU General Public License for more details. | |
| 24 /// | |
| 25 /// You should have received a copy of the GNU General Public License | |
| 26 /// along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 27 ////////////////////////////////////////////////////////////////////////////// | |
| 28 /* | |
| 29 ============================================================================== | |
| 30 ##### CAN data ##### | |
| 31 ============================================================================== | |
| 32 [..] is stored static in BONEX_CAN_Config | |
| 33 see example CAN_Networking for STM32303C_EVAL | |
| 34 | |
| 35 */ | |
| 36 | |
| 37 /* Includes ------------------------------------------------------------------*/ | |
| 38 #include "bonex_mini.h" | |
| 39 | |
| 40 /* Private variables ---------------------------------------------------------*/ | |
| 41 | |
| 42 enum | |
| 43 { | |
| 44 TYPE_ECOS = 0, | |
| 45 TYPE_RS = 1, | |
| 46 TYPE_MAX | |
| 47 }; | |
| 48 | |
| 49 const uint16_t loadVoltageInverted[TYPE_MAX][21] = | |
| 50 { | |
| 51 { // ECOS | |
| 52 0 | |
| 53 }, | |
| 54 { // RS | |
| 55 38000, // 0% >= index *5 ist Ergebnis Kapazit�t | |
| 56 38875, // 5% | |
| 57 39750, // 10% | |
| 58 40625, | |
| 59 41500, | |
| 60 42050, | |
| 61 42600, | |
| 62 43150, | |
| 63 43700, | |
| 64 44250, | |
| 65 44800, | |
| 66 45350, | |
| 67 45900, | |
| 68 46450, | |
| 69 47000, // 70% | |
| 70 47550, // 75% | |
| 71 48100, | |
| 72 48450, // 85% | |
| 73 48800, | |
| 74 49150, | |
| 75 49500, //100% , index = 20 | |
| 76 } | |
| 77 }; | |
| 78 | |
| 79 | |
| 80 uint8_t BONEX_mini_ResidualCapacityVoltageBased(float voltage_V, uint16_t ageInMilliSecondsSinceLast) | |
| 81 { | |
| 82 static uint8_t capacityStorage = 0; | |
| 83 static uint32_t voltage_mV_storage_32bit = 0; | |
| 84 static uint16_t storageCounter = 0; | |
| 85 | |
| 86 uint16_t voltage_mV = (uint16_t)(1000 * voltage_V); | |
| 87 | |
| 88 uint8_t calcNow = 0; | |
| 89 | |
| 90 if(ageInMilliSecondsSinceLast < 2000) | |
| 91 { | |
| 92 voltage_mV_storage_32bit += voltage_mV; | |
| 93 storageCounter++; | |
| 94 } | |
| 95 else | |
| 96 { | |
| 97 storageCounter = 0; | |
| 98 voltage_mV_storage_32bit = 0; | |
| 99 } | |
| 100 | |
| 101 | |
| 102 if(storageCounter >= 600) | |
| 103 { | |
| 104 voltage_mV_storage_32bit /= storageCounter; | |
| 105 voltage_mV = (uint16_t)voltage_mV_storage_32bit; | |
| 106 storageCounter = 1; | |
| 107 voltage_mV_storage_32bit = voltage_mV; | |
| 108 calcNow = 1; | |
| 109 } | |
| 110 else if(storageCounter == 1) // value immediately but not called after 600 counter ;-) | |
| 111 { | |
| 112 voltage_mV = (uint16_t)voltage_mV_storage_32bit; | |
| 113 calcNow = 1; | |
| 114 } | |
| 115 | |
| 116 if(calcNow) | |
| 117 { | |
| 118 for(int i = 20; i>=0; i--) | |
| 119 { | |
| 120 if(voltage_mV >= loadVoltageInverted[1][i]) | |
| 121 { | |
| 122 capacityStorage = i*5; | |
| 123 break; | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 return capacityStorage; | |
| 129 } | |
| 130 | |
| 131 /* | |
| 132 | |
| 133 uint8_t BONEX_mini_ResidualCapacityVoltageBased(float voltage_V, uint16_t ageInMilliSecondsSinceLast) | |
| 134 { | |
| 135 static uint8_t capacityStorage = 0; | |
| 136 static uint16_t voltage_mV_storage[5] = {0,0,0,0,0}; // number six is used directly from voltage_mV | |
| 137 | |
| 138 uint32_t voltage_mV = (uint32_t)(1000 * voltage_V); | |
| 139 | |
| 140 | |
| 141 // if necessary reset container and return actual voltage_V as capacity | |
| 142 if(ageInMilliSecondsSinceLast > 2000) | |
| 143 { | |
| 144 capacityStorage = 0; | |
| 145 for(int i = 0; i<5; i++) | |
| 146 { | |
| 147 voltage_mV_storage[i] = 0; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 // find storage container or, if full, use it as number six and recalc voltage_mV based on those six values | |
| 152 int ptr = -1; | |
| 153 do | |
| 154 { | |
| 155 ptr++; | |
| 156 } while ((ptr < 5) && voltage_mV_storage[ptr] != 0); | |
| 157 | |
| 158 if(ptr == 5) | |
| 159 { | |
| 160 for(int i = 0; i<5; i++) | |
| 161 { | |
| 162 voltage_mV += voltage_mV_storage[i]; | |
| 163 voltage_mV_storage[i] = 0; | |
| 164 } | |
| 165 voltage_mV += 3; | |
| 166 voltage_mV /= 6; | |
| 167 capacityStorage = 0; | |
| 168 } | |
| 169 else | |
| 170 { | |
| 171 voltage_mV_storage[ptr] = voltage_mV; | |
| 172 } | |
| 173 | |
| 174 // calc result if update necessary | |
| 175 if(capacityStorage == 0) | |
| 176 { | |
| 177 for(int i = 20; i>=0; i--) | |
| 178 { | |
| 179 if(voltage_mV >= loadVoltageInverted[1][i]) | |
| 180 { | |
| 181 capacityStorage = i*5; | |
| 182 break; | |
| 183 } | |
| 184 } | |
| 185 } | |
| 186 return capacityStorage; | |
| 187 } | |
| 188 | |
| 189 #define ECOS_VMAX 290 | |
| 190 #define ECOS_VMIN 195 | |
| 191 #define ECOS_STEP 5 | |
| 192 | |
| 193 #define RS_VMAX 500 | |
| 194 #define RS_VMIN 360 | |
| 195 #define RS_STEP 5 | |
| 196 | |
| 197 #define ECOS_LENGTH (((ECOS_VMAX - ECOS_VMIN) / ECOS_STEP) + 1) | |
| 198 #define RS_LENGTH (((RS_VMAX - RS_VMIN) / RS_STEP) + 1) | |
| 199 #define MAX_LENGTH (ECOS_LENGTH>RS_LENGTH? ECOS_LENGTH:RS_LENGTH) | |
| 200 | |
| 201 | |
| 202 typedef struct | |
| 203 { | |
| 204 uint8_t load[3]; | |
| 205 } load; | |
| 206 | |
| 207 | |
| 208 const int32_t currentMaxLoad[TYPE_MAX] = { 17000,14000}; | |
| 209 const int32_t currentPartialLoad[TYPE_MAX] = { 1000, 1000}; | |
| 210 const uint16_t voltageCharged[TYPE_MAX] = { 280, 480}; | |
| 211 const uint16_t voltageMax[TYPE_MAX] = { ECOS_VMAX, RS_VMAX}; | |
| 212 const uint16_t voltageMin[TYPE_MAX] = { ECOS_VMIN, RS_VMIN}; | |
| 213 const uint8_t voltageSteps[TYPE_MAX] = { ECOS_STEP, RS_STEP}; | |
| 214 const uint8_t length[TYPE_MAX] = { ECOS_LENGTH, RS_LENGTH}; | |
| 215 | |
| 216 | |
| 217 | |
| 218 | |
| 219 | |
| 220 const uint8_t loadVoltage[TYPE_MAX][MAX_LENGTH][3] = | |
| 221 { | |
| 222 { | |
| 223 // ECOS | |
| 224 // no,teil,voll | |
| 225 { 0, 5, 0}, // voltageMin 19.5 | |
| 226 { 0, 5, 0}, // voltageMin + 0.5V | |
| 227 { 0, 5, 0}, // 20.5 | |
| 228 { 5, 5, 5}, // 21 | |
| 229 { 5, 5, 5}, // 21.5 | |
| 230 { 5, 10, 10}, // 22 | |
| 231 { 5, 10, 15}, // 22.5 | |
| 232 { 10, 15, 30}, // 23 | |
| 233 { 20, 30, 45}, // 23.5 | |
| 234 { 30, 40, 60}, // 24 | |
| 235 { 40, 50, 65}, // 24.5 | |
| 236 { 50, 60, 75}, // 25 | |
| 237 { 60, 70, 80}, // 25.5 | |
| 238 { 70, 80, 85}, // 26 | |
| 239 { 80, 90, 85}, // 26.5 | |
| 240 { 85, 90, 90}, // 27 | |
| 241 { 90, 95, 90}, // 27.5 | |
| 242 { 95, 95, 95}, // 28 | |
| 243 {100,100,100}, // 28.5 | |
| 244 {100,100,100}, // voltageMax 29 | |
| 245 }, | |
| 246 { | |
| 247 // RS | |
| 248 // no,teil,voll | |
| 249 { 0, 0, 0}, // voltageMin 36 V | |
| 250 { 2, 0, 2}, // voltageMin + 0.5V | |
| 251 { 5, 0, 5}, // 37 | |
| 252 { 5, 2, 5}, // | |
| 253 { 5, 5, 5}, // 38 | |
| 254 { 5, 5, 10}, // | |
| 255 { 5, 5, 15}, // 39 | |
| 256 { 7, 7, 17}, // | |
| 257 { 10, 10, 20}, // 40 | |
| 258 { 15, 12, 27}, // | |
| 259 { 20, 15, 35}, // 41 | |
| 260 { 27, 22, 42}, // | |
| 261 { 35, 30, 50}, // 42 | |
| 262 { 42, 37, 55}, // | |
| 263 { 50, 45, 60}, // 43 | |
| 264 { 55, 50, 67}, // | |
| 265 { 60, 55, 75}, // 44 | |
| 266 { 67, 57, 80}, // | |
| 267 { 75, 60, 85}, // 45 | |
| 268 { 77, 65, 87}, // | |
| 269 { 80, 70, 90}, // 46 | |
| 270 { 85, 75, 90}, // | |
| 271 { 90, 80, 90}, // 47 | |
| 272 { 92, 85, 92}, // | |
| 273 { 95, 90, 95}, // 48 | |
| 274 { 95, 92, 97}, // | |
| 275 { 95, 95,100}, // 49 | |
| 276 { 97, 97,100}, // | |
| 277 {100,100,100} // 50 | |
| 278 } | |
| 279 }; | |
| 280 | |
| 281 | |
| 282 void BONEX_calc_new_ResidualCapacity(uint8_t *residualC, uint32_t voltage_mV, int32_t current_mA, uint8_t scooterType) // as in BIS | |
| 283 { | |
| 284 uint8_t actualLoad = 0; | |
| 285 uint8_t remainder = 0; | |
| 286 uint32_t voltagePointer = 0; | |
| 287 | |
| 288 if(voltage_mV == 0) | |
| 289 return; | |
| 290 | |
| 291 if(scooterType >= TYPE_MAX) | |
| 292 return; | |
| 293 | |
| 294 if(voltage_mV < (voltageMin[scooterType] * 100)) | |
| 295 { | |
| 296 *residualC = 0; | |
| 297 return; | |
| 298 } | |
| 299 else | |
| 300 if(voltage_mV >= (voltageMax[scooterType] * 100)) | |
| 301 { | |
| 302 *residualC = 100; | |
| 303 return; | |
| 304 } | |
| 305 else // check if charged and reset residualC for further calculation | |
| 306 if(voltage_mV >= (voltageCharged[scooterType] * 100)) | |
| 307 { | |
| 308 *residualC = 100; | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 // define the line we are working | |
| 313 if(current_mA >= currentMaxLoad[scooterType]) | |
| 314 actualLoad = 2; | |
| 315 else | |
| 316 if(current_mA >= currentPartialLoad[scooterType]) | |
| 317 actualLoad = 1; | |
| 318 else | |
| 319 actualLoad = 0; | |
| 320 | |
| 321 voltagePointer = (voltage_mV - ((uint32_t)(voltageMin[scooterType])) * 100) / (voltageSteps[scooterType] * 100); | |
| 322 | |
| 323 // should be checked with if(... >= voltageMax) but for safety | |
| 324 if(voltagePointer >= length[scooterType]) | |
| 325 { | |
| 326 *residualC = 100; | |
| 327 return; | |
| 328 } | |
| 329 | |
| 330 if(loadVoltage[scooterType][voltagePointer][actualLoad] < *residualC) | |
| 331 *residualC = loadVoltage[scooterType][voltagePointer][actualLoad]; | |
| 332 else if(loadVoltage[scooterType][voltagePointer][actualLoad] >= (*residualC + 20)) | |
| 333 *residualC = loadVoltage[scooterType][voltagePointer][actualLoad]; | |
| 334 | |
| 335 // steps of 5 | |
| 336 remainder = (*residualC)%5; | |
| 337 if(remainder) | |
| 338 *residualC += (5 - remainder); | |
| 339 | |
| 340 // safety | |
| 341 if(*residualC > 100) | |
| 342 *residualC = 100; | |
| 343 | |
| 344 return; | |
| 345 } | |
| 346 */ | |
| 347 |
