Code for the Battery MBED

Dependencies:   NRF2401P mbed-rtos mbed

Committer:
dontknowhow
Date:
Fri Jun 12 14:37:27 2015 +0000
Revision:
0:3d91ae4fc885
Version 1, work in progress

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dontknowhow 0:3d91ae4fc885 1 #include "mbed.h"
dontknowhow 0:3d91ae4fc885 2 #include "rtos.h"
dontknowhow 0:3d91ae4fc885 3 #include "NRF2401P.h"
dontknowhow 0:3d91ae4fc885 4
dontknowhow 0:3d91ae4fc885 5 #define BATTERY_ID "123"
dontknowhow 0:3d91ae4fc885 6
dontknowhow 0:3d91ae4fc885 7 #define CAPACITY 3600 //in Joules (=1000mAh)
dontknowhow 0:3d91ae4fc885 8
dontknowhow 0:3d91ae4fc885 9 #define STORAGE_READINGS 200 //86400
dontknowhow 0:3d91ae4fc885 10
dontknowhow 0:3d91ae4fc885 11 #define READING_INTERVAL 1.0
dontknowhow 0:3d91ae4fc885 12
dontknowhow 0:3d91ae4fc885 13 #define IDLING_POWER 0.001 // 1mW
dontknowhow 0:3d91ae4fc885 14
dontknowhow 0:3d91ae4fc885 15 // Three different Modes, as explained in the Wiki.
dontknowhow 0:3d91ae4fc885 16 #define IDLING 1
dontknowhow 0:3d91ae4fc885 17 #define CHARGING 2
dontknowhow 0:3d91ae4fc885 18 #define POWERING 3
dontknowhow 0:3d91ae4fc885 19
dontknowhow 0:3d91ae4fc885 20 Serial pc(USBTX, USBRX); // tx, rx
dontknowhow 0:3d91ae4fc885 21
dontknowhow 0:3d91ae4fc885 22 // ADC inputs
dontknowhow 0:3d91ae4fc885 23 AnalogIn bat_v(PTB0);
dontknowhow 0:3d91ae4fc885 24 AnalogIn bat_i(PTB1);
dontknowhow 0:3d91ae4fc885 25
dontknowhow 0:3d91ae4fc885 26 // The ADC measurements are run by a ticker
dontknowhow 0:3d91ae4fc885 27 Ticker get_stats_tick;
dontknowhow 0:3d91ae4fc885 28
dontknowhow 0:3d91ae4fc885 29 // structure for storing our data.
dontknowhow 0:3d91ae4fc885 30 typedef struct {
dontknowhow 0:3d91ae4fc885 31 float voltage; // instantaneous voltage in V
dontknowhow 0:3d91ae4fc885 32 float current; // instantaneous current in A
dontknowhow 0:3d91ae4fc885 33 float power; // instantaneous power in W
dontknowhow 0:3d91ae4fc885 34
dontknowhow 0:3d91ae4fc885 35 double energy; // total energy into & out of battery in J
dontknowhow 0:3d91ae4fc885 36 double c_count; // total current in & out "Coulomb count"
dontknowhow 0:3d91ae4fc885 37
dontknowhow 0:3d91ae4fc885 38 float charge; // estimated charge as a percentage
dontknowhow 0:3d91ae4fc885 39 int capacity; // estimated capacity in mJ
dontknowhow 0:3d91ae4fc885 40
dontknowhow 0:3d91ae4fc885 41 int powers[STORAGE_READINGS]; // array to hold powers in mW
dontknowhow 0:3d91ae4fc885 42 int voltages[STORAGE_READINGS]; // array to hold voltages in mV
dontknowhow 0:3d91ae4fc885 43 int currents[STORAGE_READINGS]; // array to hold currents in uA
dontknowhow 0:3d91ae4fc885 44
dontknowhow 0:3d91ae4fc885 45 unsigned int readings; // count of readings taken
dontknowhow 0:3d91ae4fc885 46 float idling_time; // time spent idling
dontknowhow 0:3d91ae4fc885 47
dontknowhow 0:3d91ae4fc885 48 char mode; // current mode of operation
dontknowhow 0:3d91ae4fc885 49 bool new_data; // indicates fresh data ready to be processed,
dontknowhow 0:3d91ae4fc885 50 // flag set to true by get_stats()
dontknowhow 0:3d91ae4fc885 51
dontknowhow 0:3d91ae4fc885 52 } stats_t;
dontknowhow 0:3d91ae4fc885 53
dontknowhow 0:3d91ae4fc885 54 // global variable for use in ticker
dontknowhow 0:3d91ae4fc885 55 stats_t stats;
dontknowhow 0:3d91ae4fc885 56
dontknowhow 0:3d91ae4fc885 57 // Debug function for printing to a serial port
dontknowhow 0:3d91ae4fc885 58 void print_stats(Serial *out, stats_t *stats);
dontknowhow 0:3d91ae4fc885 59
dontknowhow 0:3d91ae4fc885 60 // Use the ADC0
dontknowhow 0:3d91ae4fc885 61 void get_stats(stats_t *stats);
dontknowhow 0:3d91ae4fc885 62
dontknowhow 0:3d91ae4fc885 63 // wrapper function, this is called by the ticker.
dontknowhow 0:3d91ae4fc885 64 void get_stats_w(){
dontknowhow 0:3d91ae4fc885 65 get_stats( &stats );
dontknowhow 0:3d91ae4fc885 66 }
dontknowhow 0:3d91ae4fc885 67
dontknowhow 0:3d91ae4fc885 68 // used for initializing the structure
dontknowhow 0:3d91ae4fc885 69 void reset_stats(stats_t *stats);
dontknowhow 0:3d91ae4fc885 70
dontknowhow 0:3d91ae4fc885 71 // seperate thread for communication
dontknowhow 0:3d91ae4fc885 72 void comms_thread(void const *args);
dontknowhow 0:3d91ae4fc885 73
dontknowhow 0:3d91ae4fc885 74 int main() {
dontknowhow 0:3d91ae4fc885 75
dontknowhow 0:3d91ae4fc885 76 // start the comms thread
dontknowhow 0:3d91ae4fc885 77 Thread thread(comms_thread);
dontknowhow 0:3d91ae4fc885 78
dontknowhow 0:3d91ae4fc885 79 // start taking measurements
dontknowhow 0:3d91ae4fc885 80 get_stats_tick.attach(&get_stats_w, READING_INTERVAL);
dontknowhow 0:3d91ae4fc885 81
dontknowhow 0:3d91ae4fc885 82 // initialiye the stats structure
dontknowhow 0:3d91ae4fc885 83 reset_stats(&stats);
dontknowhow 0:3d91ae4fc885 84
dontknowhow 0:3d91ae4fc885 85 while(true){
dontknowhow 0:3d91ae4fc885 86
dontknowhow 0:3d91ae4fc885 87 // get stats has supplied some new data, analyse it.
dontknowhow 0:3d91ae4fc885 88 if(stats.new_data){
dontknowhow 0:3d91ae4fc885 89
dontknowhow 0:3d91ae4fc885 90 // add the current values to the storage array
dontknowhow 0:3d91ae4fc885 91 stats.powers[stats.readings - 1] = (int)( stats.power * 1000.0 );
dontknowhow 0:3d91ae4fc885 92 stats.voltages[stats.readings - 1] = (int)( stats.voltage * 1000.0 );
dontknowhow 0:3d91ae4fc885 93 stats.currents[stats.readings - 1] = (int)( stats.current * 1000.0 * 1000.0);
dontknowhow 0:3d91ae4fc885 94
dontknowhow 0:3d91ae4fc885 95 // evaluate the current mode by looking at the current
dontknowhow 0:3d91ae4fc885 96 if( abs(stats.power)< IDLING_POWER){
dontknowhow 0:3d91ae4fc885 97 stats.mode = IDLING;
dontknowhow 0:3d91ae4fc885 98 } else if (stats.power < 0){
dontknowhow 0:3d91ae4fc885 99 stats.mode = CHARGING;
dontknowhow 0:3d91ae4fc885 100 } else{
dontknowhow 0:3d91ae4fc885 101 stats.mode = POWERING;
dontknowhow 0:3d91ae4fc885 102 }
dontknowhow 0:3d91ae4fc885 103
dontknowhow 0:3d91ae4fc885 104 // measure the time spent idling
dontknowhow 0:3d91ae4fc885 105 if(stats.mode==IDLING)
dontknowhow 0:3d91ae4fc885 106 stats.idling_time += READING_INTERVAL;
dontknowhow 0:3d91ae4fc885 107
dontknowhow 0:3d91ae4fc885 108 // Coulomb counting and total energy in/out
dontknowhow 0:3d91ae4fc885 109 stats.c_count += stats.current * READING_INTERVAL;
dontknowhow 0:3d91ae4fc885 110 stats.energy += stats.power * READING_INTERVAL;
dontknowhow 0:3d91ae4fc885 111
dontknowhow 0:3d91ae4fc885 112 // estimating SOC
dontknowhow 0:3d91ae4fc885 113 // http://liionbms.com/php/wp_soc_estimate.php
dontknowhow 0:3d91ae4fc885 114
dontknowhow 0:3d91ae4fc885 115 if(stats.voltage > 3.5){ // Voltage Conversion
dontknowhow 0:3d91ae4fc885 116 stats.charge = (stats.voltage - 3.5) * 0.1f + 0.9f;
dontknowhow 0:3d91ae4fc885 117 }
dontknowhow 0:3d91ae4fc885 118 else if(stats.voltage < 3.0){ // Voltage Conversion
dontknowhow 0:3d91ae4fc885 119 stats.charge = (stats.voltage - 3.0) * 0.1f;
dontknowhow 0:3d91ae4fc885 120 }
dontknowhow 0:3d91ae4fc885 121 else{ // Coulomb Counting
dontknowhow 0:3d91ae4fc885 122 stats.charge = stats.c_count / stats.capacity;
dontknowhow 0:3d91ae4fc885 123 }
dontknowhow 0:3d91ae4fc885 124
dontknowhow 0:3d91ae4fc885 125 // data has been analysed, reset flag
dontknowhow 0:3d91ae4fc885 126 stats.new_data = false;
dontknowhow 0:3d91ae4fc885 127 }
dontknowhow 0:3d91ae4fc885 128
dontknowhow 0:3d91ae4fc885 129
dontknowhow 0:3d91ae4fc885 130 if(stats.readings>=STORAGE_READINGS){ // We have reached the maximum amount of readings, start again!
dontknowhow 0:3d91ae4fc885 131
dontknowhow 0:3d91ae4fc885 132 reset_stats(&stats);
dontknowhow 0:3d91ae4fc885 133 }
dontknowhow 0:3d91ae4fc885 134
dontknowhow 0:3d91ae4fc885 135
dontknowhow 0:3d91ae4fc885 136
dontknowhow 0:3d91ae4fc885 137 }
dontknowhow 0:3d91ae4fc885 138 }
dontknowhow 0:3d91ae4fc885 139
dontknowhow 0:3d91ae4fc885 140
dontknowhow 0:3d91ae4fc885 141 void comms_thread(void const *args){
dontknowhow 0:3d91ae4fc885 142
dontknowhow 0:3d91ae4fc885 143 // set up nrf radio communication
dontknowhow 0:3d91ae4fc885 144 long long addr1=0xAB12CD; // setup address - any 5 byte number - same as RX
dontknowhow 0:3d91ae4fc885 145 int channel = 52; // [0-126] setup channel, must be same as RX
dontknowhow 0:3d91ae4fc885 146 bool txOK;
dontknowhow 0:3d91ae4fc885 147 char msg[32];
dontknowhow 0:3d91ae4fc885 148 char ackData[32];
dontknowhow 0:3d91ae4fc885 149 char len;
dontknowhow 0:3d91ae4fc885 150
dontknowhow 0:3d91ae4fc885 151 // Setup
dontknowhow 0:3d91ae4fc885 152 NRF2401P nrf1(PTD2, PTD3, PTD1, PTA13, PTD0); //mosi, miso, sclk, csn, ce)
dontknowhow 0:3d91ae4fc885 153
dontknowhow 0:3d91ae4fc885 154 nrf1.quickTxSetup(channel, addr1); // sets nrf24l01+ as transmitter
dontknowhow 0:3d91ae4fc885 155
dontknowhow 0:3d91ae4fc885 156 Timer att_t; // timer for sending attention commands
dontknowhow 0:3d91ae4fc885 157 Timer out_t; // timer for timeouts
dontknowhow 0:3d91ae4fc885 158
dontknowhow 0:3d91ae4fc885 159
dontknowhow 0:3d91ae4fc885 160
dontknowhow 0:3d91ae4fc885 161 att_t.start();
dontknowhow 0:3d91ae4fc885 162
dontknowhow 0:3d91ae4fc885 163 char c = '0';
dontknowhow 0:3d91ae4fc885 164 float voltage, current, voltage_r, current_r;
dontknowhow 0:3d91ae4fc885 165 while(true){
dontknowhow 0:3d91ae4fc885 166
dontknowhow 0:3d91ae4fc885 167 // listen to pc serial for debugging
dontknowhow 0:3d91ae4fc885 168 if(pc.readable())
dontknowhow 0:3d91ae4fc885 169 c = pc.getc();
dontknowhow 0:3d91ae4fc885 170
dontknowhow 0:3d91ae4fc885 171 if(c=='p'){
dontknowhow 0:3d91ae4fc885 172 print_stats(&pc, &stats);
dontknowhow 0:3d91ae4fc885 173 }
dontknowhow 0:3d91ae4fc885 174 if(c=='g'){
dontknowhow 0:3d91ae4fc885 175 get_stats(&stats);
dontknowhow 0:3d91ae4fc885 176 }
dontknowhow 0:3d91ae4fc885 177 if(c=='r'){
dontknowhow 0:3d91ae4fc885 178 voltage_r = bat_v.read();
dontknowhow 0:3d91ae4fc885 179 current_r = bat_i.read();
dontknowhow 0:3d91ae4fc885 180
dontknowhow 0:3d91ae4fc885 181 // formulas based on empirical measurements
dontknowhow 0:3d91ae4fc885 182 voltage = 10.6 * voltage_r - 4.14f;
dontknowhow 0:3d91ae4fc885 183 current = -1.7574 * current_r + 1.248;
dontknowhow 0:3d91ae4fc885 184
dontknowhow 0:3d91ae4fc885 185 pc.printf("Voltage: %1.3f Current: %1.3f AN0: %1.3f AN1: %1.3f\r\n", voltage, current, voltage_r, current_r);
dontknowhow 0:3d91ae4fc885 186 }
dontknowhow 0:3d91ae4fc885 187 c = '0';
dontknowhow 0:3d91ae4fc885 188
dontknowhow 0:3d91ae4fc885 189 if(att_t.read()>1.0f){
dontknowhow 0:3d91ae4fc885 190 // Send Attention command to locker every second
dontknowhow 0:3d91ae4fc885 191
dontknowhow 0:3d91ae4fc885 192 strcpy (msg, "AT");
dontknowhow 0:3d91ae4fc885 193 txOK = nrf1.transmitData(msg,strlen(msg));
dontknowhow 0:3d91ae4fc885 194
dontknowhow 0:3d91ae4fc885 195
dontknowhow 0:3d91ae4fc885 196 while(att_t.read()<2.0f){
dontknowhow 0:3d91ae4fc885 197 if (nrf1.isAckData()) {
dontknowhow 0:3d91ae4fc885 198 len= nrf1.getRxData(ackData); // len is number of bytes in ackData
dontknowhow 0:3d91ae4fc885 199 ackData[len] = '\0';
dontknowhow 0:3d91ae4fc885 200
dontknowhow 0:3d91ae4fc885 201
dontknowhow 0:3d91ae4fc885 202
dontknowhow 0:3d91ae4fc885 203 if (strcmp(ackData, "HELLO") == 0){
dontknowhow 0:3d91ae4fc885 204
dontknowhow 0:3d91ae4fc885 205
dontknowhow 0:3d91ae4fc885 206
dontknowhow 0:3d91ae4fc885 207 sprintf(msg, "%s1",BATTERY_ID);
dontknowhow 0:3d91ae4fc885 208
dontknowhow 0:3d91ae4fc885 209 txOK = nrf1.transmitData(msg,strlen(msg));
dontknowhow 0:3d91ae4fc885 210
dontknowhow 0:3d91ae4fc885 211
dontknowhow 0:3d91ae4fc885 212 }
dontknowhow 0:3d91ae4fc885 213
dontknowhow 0:3d91ae4fc885 214 break;
dontknowhow 0:3d91ae4fc885 215 }
dontknowhow 0:3d91ae4fc885 216 }
dontknowhow 0:3d91ae4fc885 217
dontknowhow 0:3d91ae4fc885 218 att_t.reset();
dontknowhow 0:3d91ae4fc885 219 }
dontknowhow 0:3d91ae4fc885 220
dontknowhow 0:3d91ae4fc885 221 Thread::wait(20);
dontknowhow 0:3d91ae4fc885 222 }
dontknowhow 0:3d91ae4fc885 223 }
dontknowhow 0:3d91ae4fc885 224
dontknowhow 0:3d91ae4fc885 225 // reset and initialize the structure
dontknowhow 0:3d91ae4fc885 226 void reset_stats(stats_t *stats){
dontknowhow 0:3d91ae4fc885 227
dontknowhow 0:3d91ae4fc885 228 stats->readings = 0;
dontknowhow 0:3d91ae4fc885 229 stats->energy = 0;
dontknowhow 0:3d91ae4fc885 230 stats->c_count = 0;
dontknowhow 0:3d91ae4fc885 231 stats->idling_time = 0.0;
dontknowhow 0:3d91ae4fc885 232 stats->capacity = CAPACITY;
dontknowhow 0:3d91ae4fc885 233 stats->new_data = false;
dontknowhow 0:3d91ae4fc885 234
dontknowhow 0:3d91ae4fc885 235 for( int i=0; i<STORAGE_READINGS; i++){
dontknowhow 0:3d91ae4fc885 236 stats->powers[i] = 0;
dontknowhow 0:3d91ae4fc885 237 stats->voltages[i] = 0;
dontknowhow 0:3d91ae4fc885 238 stats->currents[i] = 0;
dontknowhow 0:3d91ae4fc885 239 }
dontknowhow 0:3d91ae4fc885 240
dontknowhow 0:3d91ae4fc885 241 }
dontknowhow 0:3d91ae4fc885 242
dontknowhow 0:3d91ae4fc885 243 // print some data
dontknowhow 0:3d91ae4fc885 244 void print_stats(Serial *out, stats_t *stats){
dontknowhow 0:3d91ae4fc885 245 out->printf("\r\n\r\n");
dontknowhow 0:3d91ae4fc885 246 for(int i = 0; i < stats->readings; i++){
dontknowhow 0:3d91ae4fc885 247 //out->printf("Reading %3d: Voltage: %dmV Current: %duA Power: %dmW \r\n", i, stats->voltages[i], stats->currents[i], stats->powers[i]);
dontknowhow 0:3d91ae4fc885 248 }
dontknowhow 0:3d91ae4fc885 249 out->printf("\r\n");
dontknowhow 0:3d91ae4fc885 250 out->printf("V: %1.2fV I: %1.2fmA Power: %1.0fmW \r\n", stats->voltage, stats->current * 1000, stats->power * 1000);
dontknowhow 0:3d91ae4fc885 251 out->printf("Mode: %d \r\n", stats->mode);
dontknowhow 0:3d91ae4fc885 252 out->printf("Energy: %1.3fJ \r\n", stats->energy);
dontknowhow 0:3d91ae4fc885 253 out->printf("Coulomb C: %1.3fC \r\n", stats->c_count);
dontknowhow 0:3d91ae4fc885 254 out->printf("Time: %1.3f s \r\n", stats->readings * READING_INTERVAL);
dontknowhow 0:3d91ae4fc885 255 out->printf("Readings: %d \r\n", stats->readings);
dontknowhow 0:3d91ae4fc885 256 out->printf("Interval: %1.3fs \r\n", READING_INTERVAL);
dontknowhow 0:3d91ae4fc885 257 out->printf("Idling t: %ds \r\n", stats->idling_time);
dontknowhow 0:3d91ae4fc885 258 out->printf("Est Charge: %.0f%% \r\n", stats->charge * 100);
dontknowhow 0:3d91ae4fc885 259
dontknowhow 0:3d91ae4fc885 260 }
dontknowhow 0:3d91ae4fc885 261
dontknowhow 0:3d91ae4fc885 262 // every second, read the adc and save it in the structure
dontknowhow 0:3d91ae4fc885 263 void get_stats(stats_t *stats){
dontknowhow 0:3d91ae4fc885 264
dontknowhow 0:3d91ae4fc885 265 if(stats->new_data){ // ERROR: stats have not been processed
dontknowhow 0:3d91ae4fc885 266 pc.printf("ERROR: stats not processed\r\n");
dontknowhow 0:3d91ae4fc885 267 }
dontknowhow 0:3d91ae4fc885 268
dontknowhow 0:3d91ae4fc885 269 //average over 10 readings
dontknowhow 0:3d91ae4fc885 270 float current_r = 0;
dontknowhow 0:3d91ae4fc885 271 float voltage_r = 0;
dontknowhow 0:3d91ae4fc885 272
dontknowhow 0:3d91ae4fc885 273 for(int i = 0; i<10; i++){
dontknowhow 0:3d91ae4fc885 274 voltage_r += bat_v.read();
dontknowhow 0:3d91ae4fc885 275 current_r += bat_i.read();
dontknowhow 0:3d91ae4fc885 276 //pc.printf("%1.3f %1.3f \r\n",voltage_r, current_r);
dontknowhow 0:3d91ae4fc885 277 }
dontknowhow 0:3d91ae4fc885 278
dontknowhow 0:3d91ae4fc885 279
dontknowhow 0:3d91ae4fc885 280 current_r /= 10.0;
dontknowhow 0:3d91ae4fc885 281 voltage_r /= 10.0;
dontknowhow 0:3d91ae4fc885 282
dontknowhow 0:3d91ae4fc885 283 stats->voltage = 10.6f * voltage_r - 4.14f;
dontknowhow 0:3d91ae4fc885 284 stats->current = -1.7574f * current_r + 1.252f;
dontknowhow 0:3d91ae4fc885 285
dontknowhow 0:3d91ae4fc885 286 stats->power = stats->voltage * stats->current;
dontknowhow 0:3d91ae4fc885 287
dontknowhow 0:3d91ae4fc885 288 stats->readings++;
dontknowhow 0:3d91ae4fc885 289
dontknowhow 0:3d91ae4fc885 290 stats->new_data = true;
dontknowhow 0:3d91ae4fc885 291 }