Salve a tutti,ho in seguente problema che mi sta facendo impazzire da circa una settimana (purtroppo non sono molto bravo nella programmazione,e mi perdo facilmente in un bicchiere d'acqua!! =( )
Devo realizzare un semplice data logger,in cui i dati provenienti da un sensore adxl335 (accelerometro),dovranno essere scritti in tempi rapidissimi su una sd. Ho impostato la cosa cosi',i dati (valori dell'accelerazione,e quelli provenienti da un RTC) vengono prima immagazinati in un variabile chiamata BUFFER di tipo STRING e poi scritti su sd. Il problema si pone,quando tento di scrivere le variabili "ax,ay,ay" che sono relative all'accelerazione gravitazionale proveniente dal sensore,che devono essere di tipo FLOAT,nel BUFFER dichiarato come STRING. L'errore e' quello di "Ambiguita' dei tipi" Ho letto in rete che il problema e' facilmente risolvibile tramite la funzione dtostrf () ,ma non essendo molto bravo,non so come modificare la sintassi del mio sketch,nonostante abbia letto 100mila volte,la sintassi della funziona sopra riportata!Qualcuno potrebbe aiutarmi gentilmente?Credo che la cosa sia davvero stupida per che programma da piu tempo.Grazie mille.(nel frattempo mi sono procurato manuali e risorse riguardo la programmazione in c" Di seguito allego lo sketch in questione
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
#include "ADXL335.h"
ADXL335 accelerometer;
RTC_DS1307 RTC;
File Dati; // La variabile di tipo file che useremo per il log
const int chipSelect =10;
String Buffer=""; // qui ci mettiamo i dati da scrivere per ogni log
void setup ()
{
Serial.begin(9600);
Wire.begin(); // inizializziamo la libreria WIRE per usare
RTC.begin(); //il Real Time clock basato su ds1307
accelerometer.begin();
if (! RTC.isrunning())
{
Serial.println("RTC NON STA FUNZIONANDO");
RTC.adjust (DateTime(__DATE__, __TIME__)); //imposta ora e data
}
Serial.print("\nSto verificando la presenza della scheda..\n");
pinMode(10, OUTPUT); // fa funzionare la sdlib
if (!SD.begin(chipSelect))
{
Serial.println("SD card non trovata");
return;
}
else
{
Serial.println("Scheda inserita e funzionante");
Serial.println();
}
}
void loop ()
{
Buffer=""; // Nuovo giro, stringa vuota!
int x;
int y;
int z;
float ax,ay,az;
DateTime now = RTC.now(); // leggiamo l'ora
accelerometer.getXYZ(&x,&y,&z);
accelerometer.getAcceleration(&ax,&ay,&az);
Buffer+=String(x);
Buffer+=",";
Buffer+=String(y);
Buffer+=",";
Buffer+=String(z);
Buffer+=('\t');
Buffer+=String(ax);
Buffer+=",";
Buffer+=String(ay);
Buffer+=",";
Buffer+=String(az);
Buffer+=('\t');
Buffer +=(now.day()); // Componiamo la data AAAA/MM/GG
Buffer +=('/');
Buffer +=(now.month());
Buffer +=('/');
Buffer +=(now.year());
Buffer +=('\t');
Buffer +=(now.hour());
Buffer +=(':');
Buffer +=(now.minute());
Buffer +=(':');
Buffer +=(now.second());
Buffer +=('\t'); // tab per separare i campi
Dati = SD.open("datalog.txt", FILE_WRITE); // apriamo il file in scrittura
if (Dati)
{
Dati.println(Buffer); // Scriviamo in un sol colpo i dati sul file
Dati.close(); // chiudiamo e trasferiamo su SD
Serial.print("Dati rilevati \t");
Serial.println(Buffer);
}
else
{
Serial.println("Errore nell'apertura di datalog.txt");
}
delay (10000); // cadenza dellascrittura dei dati
}
Si quei link li avevo gia' visti! Ecco per esempio ho letto una soluzione interessante in questo topic scritta da Astrobreed:
Purtroppo in wiring non supporta i float, inoltre la printf e sprintf sono lentissime in esecuzione e occupano da sole quasi 2k byte di memoria flash.
La soluzione è convertire il flot in due interi, uno per la parte intera tramite cast, e uno per la parte decimale moltiplicata per una idonea potenza di dieci, poi si applica la itoa() ai due interi e si concatenano le due stringhe in una sola, quest'ultima operazione è fattibile tramite la sprintf se non ci sono problemi di occupazione memoria e velocità di esecuzione.
Ogni volta che vuoi scrivere un record sul file, carichi i dati dentro i campi della struttura e poi chiedi alla
libreria sdfat di scrivere byte dopo byte a partire dall'indirizzo di &frecord.
Il secondo record nel file si trova nrecord * sizeof(frecord).
Per leggere fai la stessa cosa.
Però il file non sarà in codifica ASCII e non potrai visionarlo con l'editor, al massimo con un editor
esadecimale. La soluzione potrebbe allora essere un programmino in C sul pc che legge il file
e lo trasforma in una rappresentazione comprensibile agli umani, e perché no anche nel formato
foglio di calcolo o altro.
Si, almeno che non hai voglia di scaricarti il repository da GitHub e ricompilare i sorgenti dell'IDE in attesa della improbabile 1.0.6.
~~Anzi meglio della 1.5.6r2 è la Nigthly Build --> http://arduino.cc/en/Main/Software#toc4~~ Li sei sicuro che ci sia la correzione.
ARDUINO 1.5.3 BETA 2013.08.30
Added support for floating point numbers in String class (Tevin Zhang, SebiTimeWaster)
P.S.
Se scarichi la 1.5.6r2, sappi che dalle preferenze puoi attivare i numeri di riga, inoltre hai i menu degli sketch e delle librerie a scorrimento (se fossero tanti), ecc ecc
Dopo che la provi non torni più indietro.
si ho scaricato proprio quella (e' la versione beta) ora provo ad installarla su un altro pc,perche' a quanto pare le due versioni non possono essere installate sullo stesso pc" Ho paura di perdere tutti gli sketch.Ora faccio una prova installadolo su un altro pc e vedo come va.Intanto grazie mille,speriamo di risolvere visto che e' una settimana che sto sbattendo la testa!
Non scaricare la versione installer ma solo la versione zip.
L'IDE 1.0.5 e l'IDE 1.5.6 possono coesistere sullo stesso PC perché hanno file preference diversi, però solo una istallata dall'installer e l'altra in zip, comunque meglio tutte in zip con link sul desktop.
Io ne ho 4 tutte in zip e funzionano tutte. (tranne che mi ritrovo le stesse preferenze in 3 versioni, ma funzionano)
Ho: 1.0.5 liscia, 1.5.6r2 liscia, 1.5.5 con nuova toolchain e core aggiuntivi (devo passarli sulla 1.5.6.), nigthly build di pochi giorni fa.
mooger:
La soluzione è convertire il flot in due interi, uno per la parte intera tramite cast, e uno per la parte decimale moltiplicata per una idonea potenza di dieci, poi si applica la itoa() ai due interi e si concatenano le due stringhe in una sola ...
... attraverso la funzione strcat() che fa parte di string.h che a sua volta fa parte della libreria AVR libc ... automaticamnete inclusa dallIDE ! ] ] ]
Così eviti di usare software in BETA e non ti mangi 2KB con la sprintf() ] ] ]
Sto provando anche snprintf,siccome mi serve un sistema molto performante in termini di velocita' di acquisizione tra le due quale mi consiglieresti? (intendo tra strcat() e snprintf ()
/**
* Il programma permette di inviare via seriale
* byte dopo byte il contenuto di un oggetto di
* tipo DataBlock.
* Si può fare di più, ad esempio si può inviare qualunque oggetto di qualunque tipo via seriale
* byte dopo byte.
*/
/**
* Per ricevere i dati da un microcontroller o computer
* e sufficiente creare lo stesso sketch ma al posto di:
* Serial.write(*ptrTo);
* ci mettiamo:
* if (Serial.available() > 0) {
* *ptrTo = Serial.read();
* }
* L'obbiettivo è di leggere i dati e salvarli nell'oggetto dataBlock
* PS: non testata la lettura
*/
/*
tipo di struttura per collezionare dati
per poi spedirli via seriale byte per byte
*/
typedef struct
{
float arg0;
float arg1;
float arg2;
byte arg3;
byte arg4;
byte arg5;
uint32_t arg6;
} DataBlock;
// global variable
bool alredySend; // false per inviare i dati
DataBlock dataBlock; // oggetto dataBlock da spedire
void setup()
{
alredySend = false;
delay(2000);
Serial.begin(115200);
// carica dati a caso nell'oggetto dataBlock
dataBlock.arg0 = 152.24;
dataBlock.arg1 = 489.569;
dataBlock.arg2 = 100.029;
dataBlock.arg3 = 49; // un byte 1
dataBlock.arg4 = 50; // un byte 2
dataBlock.arg5 = 51; // un byte 3
dataBlock.arg6 = 456898; // 32 bit
}
void loop()
{
if (alredySend == false) {
uint8_t *ptrTo = (uint8_t *)&dataBlock;
for (uint8_t i = 0; i < sizeof(dataBlock); i++) {
Serial.write(*ptrTo); // spedisce il dato puntato da ptrTo
ptrTo++; // punto al prossimo byte
}
alredySend = true; // i dati sono stati spediti
}
}
Anziché convertire da float ad intero e spedire i dati come stringhe, si spedisce
byte per byte il contenuto di una porzione di memoria RAM in cui ci abbiamo messo
la nostra collezione di dati come appunto è dataBlock.
A me serve una cosa semplice di facile implementazione,in quanto sono alle prime armi con la programmazione.
Per adesso ho usato il metodo snprintf(). Lo sketch viene compilato,ma sulla seriale mi da i valori del sensore sballati,cosi' come i valori del rtc : ecco un esempio:
Dati rilevati -15744 g,15821 g,28832 g 16003:-32768:16300
ecco il codice,dove sbaglio?
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
#include <SPI.h>
#include "ADXL335.h"
ADXL335 accelerometer;
RTC_DS1307 RTC;
File Dati; // La variabile di tipo file che useremo per il log
const int chipSelect =10;
char buffer[70];
void setup ()
{
Serial.begin(9600);
Wire.begin(); // inizializziamo la libreria WIRE per usare
RTC.begin(); //il Real Time clock basato su ds1307
accelerometer.begin();
if (! RTC.isrunning())
{
Serial.println("RTC NON STA FUNZIONANDO");
//LA SEGUENTE ISTRUZIONE SERVE SOLO PER REGOLARE L'OROLOGIO.ATTIVARE SOLO SE NECESSARIO.
// RTC.adjust (DateTime(__DATE__, __TIME__)); //imposta ora e data
}
Serial.print("\nSto verificando la presenza della scheda..\n");
pinMode(10, OUTPUT); // fa funzionare la sdlib
if (!SD.begin(chipSelect))
{
Serial.println("SD card non trovata");
return;
}
else
{
Serial.println("Scheda inserita e funzionante");
Serial.println();
}
}
void loop ()
{
float ax,ay,az;
DateTime now = RTC.now(); // leggiamo l'ora
snprintf(buffer,70,"\t%d g,%d g,%d g\t%02d:%02d:%02d\t",ax,ay,az,now.hour(),now.minute(),now.second());
Dati = SD.open("datalog.txt", FILE_WRITE); // apriamo il file in scrittura
if (Dati)
{
Dati.println(buffer); // Scriviamo in un sol colpo i dati sul file
Dati.close(); // chiudiamo e trasferiamo su SD
Serial.print("Dati rilevati \t");
Serial.println(buffer);
}
else
{
Serial.println("Errore nell'apertura di datalog.txt");
}
delay (0); // cadenza dellascrittura dei dati
}
Aggiornamento ho modificato il codice come segue:
In pratica ho scomposto la parte decimale e quella intera delle variabili float (ax e ay) in due variabili intere,dopodiche convertite in stringhe tramite la funziona ITOA.Ho due problemi.
In caso di valori negativi tipo -1,43,visualizzo 1,-43! Altro problema,ho provato a concatenare le stringhe tramite la funzione strcat(),ma ottengi l'output:
0,13g 0,31gDati rilevati 000
23
Qual e' la sintessi esatta di strcat?
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
#include <SPI.h>
#include "ADXL335.h"
ADXL335 accelerometer;
RTC_DS1307 RTC;
File Dati; // La variabile di tipo file che useremo per il log
const int chipSelect =10;
static char axb[100];
static char ayb[100];
static float ax,ay,az;
unsigned long time; // serve per misurare il tempo di esecuzione
void setup ()
{
Serial.begin(9600);
Wire.begin(); // inizializziamo la libreria WIRE per usare
RTC.begin(); //il Real Time clock basato su ds1307
accelerometer.begin();
if (! RTC.isrunning())
{
Serial.println("RTC NON STA FUNZIONANDO");
}
Serial.print("\nSto verificando la presenza della scheda..\n");
pinMode(10, OUTPUT); // fa funzionare la sdlib
if (!SD.begin(chipSelect))
{
Serial.println("SD card non trovata");
return;
}
else
{
Serial.println("Scheda inserita e funzionante");
Serial.println();
}
}
void loop ()
{
// MISURO IL TEMPO DI ESECUZIONE
Serial.print("Time: ");
time = millis();
//prints time since program started
Serial.println(time);
DateTime now = RTC.now(); // leggiamo l'ora
accelerometer.getAcceleration(&ax,&ay,&az);
int Hix=ax;
int Lox = ax*100-Hix*100;
itoa(Hix,axb,10);
Serial.print(Hix);
Serial.print(",");
itoa(Hix,axb,10);
Serial.print(Lox);
Serial.print("g");
Serial.print("\t");
int Hiy=ay;
int Loy = ay*100-Hiy*100;
itoa(Hiy,ayb,10);
Serial.print(Hiy);
Serial.print(",");
itoa(Hiy,ayb,10);
Serial.print(Loy);
Serial.print("g");
Dati = SD.open("datalog.txt", FILE_WRITE); // apriamo il file in scrittura
if (Dati)
{
Dati.println(strcat(axb,ayb)); // Scriviamo in un sol colpo i dati sul file
Dati.close(); // chiudiamo e trasferiamo su SD
Serial.print("Dati rilevati \t");
Serial.println(strcat(axb,ayb));
}
else
{
Serial.println("Errore nell'apertura di datalog.txt");
}
delay (0); // cadenza dellascrittura dei dati
Serial.println(time);
}