Code for the Battery MBED

Dependencies:   NRF2401P mbed-rtos mbed

Revision:
0:3d91ae4fc885
diff -r 000000000000 -r 3d91ae4fc885 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Jun 12 14:37:27 2015 +0000
@@ -0,0 +1,291 @@
+#include "mbed.h"
+#include "rtos.h"
+#include "NRF2401P.h"
+
+#define BATTERY_ID "123"
+
+#define CAPACITY 3600 //in Joules (=1000mAh)
+
+#define STORAGE_READINGS 200 //86400
+
+#define READING_INTERVAL 1.0
+
+#define IDLING_POWER 0.001  // 1mW 
+
+// Three different Modes, as explained in the Wiki.
+#define IDLING 1
+#define CHARGING 2
+#define POWERING 3
+
+Serial pc(USBTX, USBRX); // tx, rx
+
+// ADC inputs
+AnalogIn bat_v(PTB0);
+AnalogIn bat_i(PTB1);
+
+// The ADC measurements are run by a ticker
+Ticker get_stats_tick;
+
+// structure for storing our data.
+typedef struct {
+    float voltage;  // instantaneous voltage in V
+    float current;  // instantaneous current in A
+    float power;    // instantaneous power in W
+    
+    double energy;    // total energy into & out of battery in J    
+    double c_count;   // total current in & out "Coulomb count"
+    
+    float charge;   // estimated charge as a percentage
+    int capacity;   // estimated capacity in mJ
+    
+    int powers[STORAGE_READINGS];   // array to hold powers in mW
+    int voltages[STORAGE_READINGS];   // array to hold voltages in mV
+    int currents[STORAGE_READINGS];   // array to hold currents in uA
+    
+    unsigned int readings;      // count of readings taken
+    float idling_time;          // time spent idling
+    
+    char mode;      // current mode of operation
+    bool new_data;  // indicates fresh data ready to be processed,
+                    //  flag set to true by get_stats()
+    
+} stats_t;
+
+// global variable for use in ticker
+stats_t stats;
+
+// Debug function for printing to a serial port
+void print_stats(Serial *out, stats_t *stats);
+
+// Use the ADC0
+void get_stats(stats_t *stats);
+
+// wrapper function, this is called by the ticker.
+void get_stats_w(){
+    get_stats( &stats );    
+}
+
+// used for initializing the structure
+void reset_stats(stats_t *stats);
+
+// seperate thread for communication
+void comms_thread(void const *args);
+
+int main() {
+    
+    // start the comms thread    
+    Thread thread(comms_thread);
+    
+    // start taking measurements
+    get_stats_tick.attach(&get_stats_w, READING_INTERVAL);
+    
+    // initialiye the stats structure
+    reset_stats(&stats);
+            
+    while(true){
+        
+        // get stats has supplied some new data, analyse it.
+        if(stats.new_data){
+            
+            // add the current values to the storage array       
+            stats.powers[stats.readings - 1] = (int)( stats.power * 1000.0 );
+            stats.voltages[stats.readings - 1] = (int)( stats.voltage * 1000.0 );
+            stats.currents[stats.readings - 1] = (int)( stats.current * 1000.0 * 1000.0);
+            
+            // evaluate the current mode by looking at the current
+            if( abs(stats.power)< IDLING_POWER){
+                stats.mode = IDLING;
+            } else if (stats.power < 0){
+                stats.mode = CHARGING;
+            } else{
+                stats.mode = POWERING;
+            }    
+            
+            // measure the time spent idling
+            if(stats.mode==IDLING)
+                stats.idling_time += READING_INTERVAL;
+                           
+            // Coulomb counting and total energy in/out
+            stats.c_count += stats.current * READING_INTERVAL;
+            stats.energy += stats.power * READING_INTERVAL;
+            
+            // estimating SOC
+            // http://liionbms.com/php/wp_soc_estimate.php
+            
+            if(stats.voltage > 3.5){ // Voltage Conversion
+                stats.charge = (stats.voltage - 3.5) * 0.1f + 0.9f;
+            }
+            else if(stats.voltage < 3.0){ // Voltage Conversion
+                stats.charge = (stats.voltage - 3.0) * 0.1f;
+            }
+            else{   // Coulomb Counting
+                stats.charge = stats.c_count / stats.capacity;
+            }
+            
+            // data has been analysed, reset flag
+            stats.new_data = false;
+        }
+        
+        
+        if(stats.readings>=STORAGE_READINGS){   // We have reached the maximum amount of readings, start again!
+        
+            reset_stats(&stats);
+        }
+        
+
+       
+    }
+}
+
+
+void comms_thread(void const *args){
+    
+    // set up nrf radio communication 
+    long long addr1=0xAB12CD; // setup address - any 5 byte number - same as RX
+    int channel = 52;  // [0-126] setup channel, must be same as RX
+    bool txOK;
+    char msg[32];
+    char ackData[32];
+    char len;
+     
+     // Setup 
+    NRF2401P nrf1(PTD2, PTD3, PTD1, PTA13, PTD0); //mosi, miso, sclk, csn, ce)
+    
+    nrf1.quickTxSetup(channel, addr1); // sets nrf24l01+ as transmitter
+     
+    Timer att_t;   // timer for sending attention commands
+    Timer out_t;   // timer for timeouts
+    
+    
+    
+    att_t.start();
+    
+    char c = '0';
+    float voltage, current, voltage_r, current_r;
+    while(true){   
+        
+        // listen to pc serial for debugging
+        if(pc.readable())
+            c = pc.getc();
+            
+        if(c=='p'){
+            print_stats(&pc, &stats);
+        }
+        if(c=='g'){
+            get_stats(&stats);
+        }
+        if(c=='r'){
+            voltage_r = bat_v.read();
+            current_r = bat_i.read();
+            
+            // formulas based on empirical measurements
+            voltage = 10.6 * voltage_r - 4.14f; 
+            current = -1.7574 * current_r + 1.248;
+                    
+            pc.printf("Voltage: %1.3f Current: %1.3f AN0: %1.3f AN1: %1.3f\r\n", voltage, current, voltage_r, current_r); 
+        }
+        c = '0';
+        
+        if(att_t.read()>1.0f){
+            // Send Attention command to locker every second
+            
+            strcpy (msg, "AT"); 
+            txOK = nrf1.transmitData(msg,strlen(msg));
+            
+         
+            while(att_t.read()<2.0f){
+                if (nrf1.isAckData()) { 
+                    len= nrf1.getRxData(ackData); // len is number of bytes in ackData
+                    ackData[len] = '\0';
+                    
+                    
+                    
+                    if (strcmp(ackData, "HELLO") == 0){
+                                       
+                            
+                        
+                        sprintf(msg, "%s1",BATTERY_ID);
+                         
+                        txOK = nrf1.transmitData(msg,strlen(msg));
+                     
+                        
+                    }
+                    
+                    break;
+                }
+            }
+            
+            att_t.reset();
+        }
+        
+      Thread::wait(20);  
+    }
+}
+
+// reset and initialize the structure
+void reset_stats(stats_t *stats){
+   
+    stats->readings = 0;
+    stats->energy = 0;
+    stats->c_count = 0;
+    stats->idling_time = 0.0;
+    stats->capacity = CAPACITY;    
+    stats->new_data = false;
+    
+    for( int i=0; i<STORAGE_READINGS; i++){
+        stats->powers[i] = 0;
+        stats->voltages[i] = 0;
+        stats->currents[i] = 0;        
+    }
+
+}
+
+// print some data
+void print_stats(Serial *out, stats_t *stats){
+    out->printf("\r\n\r\n");
+    for(int i = 0; i < stats->readings; i++){
+        //out->printf("Reading %3d: Voltage: %dmV Current: %duA Power: %dmW \r\n", i, stats->voltages[i], stats->currents[i], stats->powers[i]);         
+    }
+    out->printf("\r\n");
+    out->printf("V: %1.2fV I: %1.2fmA Power: %1.0fmW \r\n", stats->voltage, stats->current * 1000, stats->power * 1000);
+    out->printf("Mode:       %d \r\n", stats->mode);
+    out->printf("Energy:     %1.3fJ \r\n", stats->energy);
+    out->printf("Coulomb C:  %1.3fC \r\n", stats->c_count);
+    out->printf("Time:       %1.3f s \r\n", stats->readings * READING_INTERVAL);
+    out->printf("Readings:   %d \r\n", stats->readings);
+    out->printf("Interval:   %1.3fs \r\n", READING_INTERVAL);
+    out->printf("Idling t:   %ds \r\n", stats->idling_time); 
+    out->printf("Est Charge: %.0f%% \r\n", stats->charge * 100); 
+ 
+}
+
+// every second, read the adc and save it in the structure
+void get_stats(stats_t *stats){
+    
+    if(stats->new_data){ // ERROR: stats have not been processed
+        pc.printf("ERROR: stats not processed\r\n");        
+    }
+    
+    //average over 10 readings
+    float current_r = 0;
+    float voltage_r = 0;
+    
+    for(int i = 0; i<10; i++){
+        voltage_r += bat_v.read();
+        current_r += bat_i.read();
+        //pc.printf("%1.3f %1.3f \r\n",voltage_r, current_r);
+    }
+    
+    
+    current_r /= 10.0;
+    voltage_r /= 10.0;
+    
+    stats->voltage = 10.6f * voltage_r - 4.14f;  
+    stats->current = -1.7574f * current_r + 1.252f;
+    
+    stats->power = stats->voltage * stats->current;
+    
+    stats->readings++;    
+        
+    stats->new_data = true;            
+}
\ No newline at end of file