Jumping Jack Flash weblog

PinguiLogger – registrazione corrente e tensione con board Pinguino

Posted in hardware, Programmazione by jumpjack on 12 febbraio 2013

Sta per vedere la luce il mio PinguiLogger🙂 , un aggeggino che permette di registrare correnti fino a 70 A e tensioni fino a 60V su scheda SD, per analizzare cosa combina il mio scooter elettrico.

Al momento il listato C è già pronto e funzionante su scheda Arduino, anche se si limita a registrare i dati senza elaborarli, quindi registra solo valori compresi tra 0 e 1023 da due sensori di corrente e da due partitori di tensione 1:21, creando un file .CSV; poi bisogna importare il file in Excel e fare i dovuti calcoli.

I campi registrati nel file sono:

  • tempo (millisecondi)
  • riferimento 1
  • corrente 1
  • tensione 1
  • riferimento 2
  • corrente 2
  • tensione 2

Il “riferimento” è il pin di riferimento dei sensori di corrente, il cui valore dovrebbe servire, se ho ben capito, a indicare a quale valore del pin di output corrisponde una corrente nulla (perchè immagino che il “punto 0″ dipenda dalla tensione effettiva di alimentazione”, ma devo ancora studiare bene la faccenda…

Il sensore usato è un ACS709 comprato su Robot Italy per 10 euro, che dovrebbe misurare da -70A a + 70A… quindi non capisco come mai vada in saturazione sul mio scooteronzolo da 1500W/60V, che non dovrebbe succhiare più di 25 A…. Uno dei primi misteri da indagare!

Però mi sono accorto che è molto scomodo dover aspettare di tornare a casa per leggere i dati sulla schedina, urge un display in tempo reale; infatti, ho già predisposto la scatola del PinguiLogger per il display del nokia 3110/5110, (costo: meno di 10 dollari, quindi 7 euro)  che ho già equipaggiato con piedini e fili vari, pronto per essere installato.

Al momento lo sto studiando su Arduino, dove l’utilizzo è talmente banale da non essere nemmeno divertente: carichi la libreria LCD5110Graph, inizializzi il display con:

  • LCD5110 myGLCD(3,4,5,6,7);
  • extern uint8_t SmallFont[];
  • myGLCD.InitLCD();
  • myGLCD.setFont(SmallFont);

e poi basta usare:

  • myGLCD.print(“PinguiLogger”, CENTER, 0);

per scrivere qualcosa al centro dello schermo,

  •  myGLCD.print(“(Ciao!”, x,y);

per scriverlo dove ci pare,

  • myGLCD.drawRect(28, 18, 56, 28);

per disegnare un rettangolo, e

  • myGLCD.drawLine(a,b,c,d);

per disegnare una riga.

La più importante è la riga iniziale, che dice ad Arduino quali pin usare del display (che a proposito è basato su un chiop Philips PCD8544) :

  • LCD5110 myGLCD(3,4,5,6,7);

Da notare che la libreria va aggiornata per supportare correttamente tutte le schede Arduino, scrivendo questo:

#if defined(__AVR__)
    #if defined(ARDUINO) && ARDUINO >= 100
        #include "Arduino.h"
    #else
        #include "WProgram.h"
    #endif
#else
    #include "WProgram.h"
#endif

al posto del semplice:

#include "WProgram.h"

originale.

Il logger si chiama però PinguiLogger perchè gira su una scheda Pinguino MICRO: compatibile con Arduino, ma grande un terzo e dotata di slot SD card integrato (=tanti sbattimenti in meno):

Quello che devo scoprire ora è se posso caricare direttamente la libreria nell’IDE Pinguino e usare gli stessi comandi di Arduino, o dover impazzire in altri modi; immagino sia più probabile la seconda possibilità, quindi intanto sto anche cercando librerie LCD per Pinguino:

http://wiki.pinguino.cc/index.php/LibLcd

Il codice attuale:

/*      ----------------------------------------------------------------------------
   FILE:       PinguiLogger.pde
   PROJECT:    Pinguino Current/Voltage logger
   PURPOSE:    Log current and voltage from photovoltaic systems or electric vehicles.
   PROGRAMER:  Jumpjack
   BOARD:      PIC32-PINGUINO-MICRO
   FIRST RELEASE: 20/Jan/2013
   LAST RELEASE:  20/Jan/2013
    ----------------------------------------------------------------------------
   Based on previous Pinguino IDE DataLogger example
   ----------------------------------------------------------------------------
*/

#define BUFFER_SIZE 32  // Size of read buffer - arbitrary length,
                        // try changing it to improve efficiency

#define CURRENT1 A0 // Current sensor 1 = CON2-16
#define VOLTAGE1 A1 // Voltage sensor 1 = CON2-15
#define CURRENT2 A2 // Current sensor 2 = CON2-14
#define VOLTAGE2 A3 // Voltage sensor 2 = CON2-13                        
#define REFERENCE1 4 // Reference 1 = CON2-12                        
#define REFERENCE2 5 // Reference 2 = CON2-11                        

#define SDCS_PIN 40      // The pin for the SD Card select line: 8 for OTG, 40 for MICRO

   u16      i, lines_total, bytes_to_write, bytes_written, bytes_read;
   u32      bytes_total;
   u8       filename[]  = "datalog1.csv";       // should include full path to file

   FIL      fil;                                                        // File object
   FRESULT  res,        rc;
   DWORD    file_size;
   u8       read_buffer[BUFFER_SIZE];
 long currentTime;
 long cloopTime;
 int TIME_INTERVAL_MS;
 TIME_INTERVAL_MS = 1;

   u8  buffer[40]  = "";    // arbitary value of 40 for length of character array
                              // needs to be large enough for maximum line length
   u8  temp[13]    = "";    // temporary variable used for int to char conversions
                              // needs to be large enough for maximum string length
                              // generated by sprintf() statements below

void setup()
{

/* ********************************************** */
/* Header code to communicate with user */
    pinMode(10, OUTPUT); // Red 
    pinMode(32, OUTPUT); // Green

    digitalWrite(10,HIGH);  // Red on
    digitalWrite(32,LOW); 
    delay(3000); // Allow user to connect serialmonitor.
    digitalWrite(10,LOW); // Red off, Green on: board ready and running.
    digitalWrite(32,HIGH); 

    //CDC.println("Presst ENTER to start original program.");
     // while (CDC.getKey() != '\n\r');                        // wait for RETURN key to start
/* ********************************************** */    

 /*Sprintf(temp, "Ref1;Cur1;Volt1;Ref2;Cur2,Volt2;Time\n");
 strcat(buffer, temp);   
 bytes_to_write = strlen(buffer);         /
 SD.mount(SDCS_PIN);           
 res = SD.open(&fil, filename, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
 if (!res){
      file_size = fil.fsize;     
      SD.seek(&fil,file_size);   
      rc = SD.write(&fil, buffer, bytes_to_write, &bytes_written);             
      SD.flush(&fil);                                                          
      SD.close(&fil);         
      SD.unmount(); 
 } else {
 CDC.println("Errore nello scrivere l'intestazione.");
 }*/

}

void loop()
{
  // CDC.println("\n\r*** Press RETURN to add data to data file.");
  // while (CDC.getKey() != '\n');
  // CDC.println("ok.");                                         // wait for RETURN key to start

/*      ----------------------------------------------------------------------------
   Insert temperature measurement code here if required
   If the 18b20.c library functions are used then a variable t of data type
   TEMPERATURE will need to be declared.

   see //examples/6.Sensors/DS18B20/temp18b20.pde
      for code for a single onewire temperature measurement.
        ---------------------------------------------------------------------------*/

/*      Assemble data in buffer with data items separated by comma, i.e. CSV data.

   If the board has full RTCC capability then the data logged is :-
      Reference:         e.g. T0
      Day:                       e.g. Mon
      Date:                      e.g. 16-Jan-2012
      Time:                      e.g. 13:15:12
      Temperature: e.g. 12.34  
   i.e. "T#,ddd,dd-mmm-yyyy,hh:mm:ss,##.##"

   If the datafile is opened with a spreadsheet which is set to recognise CSV data, and
   possibly also to detect special numbers, each data item should appear in a separate
   column, although some data items may be automatically converted e.g. the date may be
   displayed as, say, 16/01/12 if the spreadsheets default date formate is dd/mm/yy. */

   Sprintf(temp, "T%d;", millis());  // converts y to a string T#,
   strcat(buffer, temp);      // adds T#, to buffer

#if (defined(PIC32_PINGUINO) || defined (PIC32_PINGUINO_OTG))
   Sprintf(temp, "%3s;", Day[curDate.wday]);            // converts wday to a string ddd,
   strcat(buffer, temp);      // adds ddd, to buffer
   Sprintf(temp, "%02d-%3s-%04d;", curDate.mday, Month[curDate.mon], curDate.year+2000);                
   strcat(buffer, temp);      // adds dd-mmm-yyyy, to buffer
   Sprintf(temp, "%02d:%02d:%02d;", curTime.hour, curTime.min, curTime.sec);            
   strcat(buffer, temp);      // adds HH:MM:SS, to buffer
#endif

// ***************** ADD CURRENT/VOLTAGE MEASUREMENTS *******************
 Sprintf (buffer, "%d;%d;%d;%d;%d;%d;\n", analogRead(REFERENCE1),analogRead(CURRENT1), analogRead(VOLTAGE1), analogRead(REFERENCE2),analogRead(CURRENT2), analogRead(VOLTAGE2));
 strcat(buffer, temp);  
// **********************************************************************

/* At this point buffer contains the comma separated data terminated by a
   new line (line feed) character (and of course a NULL)                      */
   bytes_to_write = strlen(buffer);         //  number of Bytes To be Written
   SD.mount(SDCS_PIN);           //     Allocate file structure

/* Open existing file or new file if file does not already exist */
   res = SD.open(&fil, filename, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
   if (!res){
      file_size = fil.fsize;     // Get existing file size
      SD.seek(&fil,file_size);   // Set R/W pointer to end of file for APPEND

/* ************ Timing ************* */
  currentTime = millis();
  cloopTime = currentTime;
   while (currentTime <= (cloopTime + (TIME_INTERVAL_MS*1000))) {
    currentTime = millis();  // Wait until defined time is elpased.
   }

/*      ******** Write data to file ********** */
      rc = SD.write(&fil, buffer, bytes_to_write, &bytes_written);              // write new data to file
      SD.flush(&fil);                                                           // flush any data in cache to file
                                 // to avoid data loss from loss of power etc
                                 // only required if not closing file
      SD.close(&fil);            //     Included for safety to ensure file properly closed
      SD.unmount();              //     in case user removes card instead of proceeding.

/*      If all bytes written display data written on terminal */
      if (bytes_to_write == bytes_written){                                                                     // check that all bytes written to file
         CDC.printf("*** New data added ***\r\n%s", buffer);    // prints out buffer
      }
      else {
         CDC.printf("\n\r*** Not all data written ***\n\r", filename);
      }

   }
   else {
      CDC.printf("\n\r*** File %s", filename);
      CDC.println(" not found or card not in reader (on write) ***");
   }
}

3 Risposte

Subscribe to comments with RSS.

  1. simone said, on 14 febbraio 2013 at 18:00

    il sensore di corrente ti va in saturazione perche’ di default ha una massima corrente di 50A , per misurare correnti piu’ alte devi aggiungere una resistenza al pcb. Il fatto che il tuo motore sia 1500w non vuol dire che all’ avvio o in salita le correnti non siano molto piu’ elevate , inoltre 1500W e’ la potenza in uscita , la corrente utilizzata dipende dall’ efficienza del motore , se ad esempio hai un motore da 1500W con rendimento del 50% vuol dire che a monte devono essergli forniti 3000W di elettricita’


Puoi inserire un commento qui sotto; diventerà visibile dopo la moderazione dell'amministratore

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: