Buon pomeriggio a tutti.
E' da qualche giorno che mi sto scervellando e girovagando su siti, forum per cercare di risolvere un problema.
Sto tendando di costruire un altro datalogger con Arduino Mega ( per ora, poi penso userò un mini), scheda SD, un Orologio ed un convertirore 4..20 mA.
Il "materiale" è il seguente :
Il problema è che non riesco a far funzionare insieme sul bus la scheda SD ed il Convertitore .. Ho collegato in parallelo MISO,MOSI,SCK, mentre due diversi piedini per i rispettivi CS .
L'orologio funziona su bus I2C
Sto provando in tutti i modi ad "accendere" un dispositivo alla volta "spegnendo" prima l'altro, mandando in HIGH quello che non mi serve interrogare e mandando in LOW quello che voglio interrogare.
Nulla da fare.. mi "vede" sempre solo ed esclusivamente la SD e mi registra pure i valori ( che poi io interrogo via seriale da un altro programma che sto facendo con Visual Studio Community, e funziona pure questo).. il problema è che non mi registra il valore corretto perché il "convertitore" non comunica con Arduino.. Ho però notato che se stacco il filo MOSI della SD il convertitore funziona e i valori sono corretti, logicamente però non va la SD. Sto quasi pensando che lo shield SD sia difettoso. Vi allego lo sketch.. so che è incasinato.. anche perché è il frutto di un collage di altri sketch trovati su Internet e modificati a bisogno... considerate pure che non è molto che tento di fare qualcosa con Arduino. Grazie
#include <DS3232RTC.h>
#include <Time.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>
File myFile;
#define chipSelectSD 53 // Piedino SS per la Scheda SD
#define chipSelectSonda 9 // Piednino SS per La scheda mikrobus 4..20 mA
int sceltafrequenza; // prima variabile per sceglere la frequenza di registrazione
int frequenza ; // seconda variabile per sceglere la frequenza di registrazione
long previousminuti = 0; // variabile per memorizzare i minuti precedenti
float minuti; //variabile per conteggiare i minuti
unsigned long secondi; // variabile per contegiare i secondi
String ubicazione = "Ubicazione non definita" ;
String copyright = " Copyright xxxxxxx" ;
String inputString = "";
int loop_current;
int received_data;
// Valori ottenuti dalla calibrazione
const int ADC_4mA = 817.17;
const int ADC_20mA = 4008;
// Valori di Inizio e fondoscala
const int data_min_range = 0;
const int data_max_range = 1023;
void (*software_reboot )(void) = 0; // riavvia Arduino per permettere la riscrittura delle intestazioni su SD
void setup() {
pinMode (chipSelectSD, OUTPUT);
pinMode (chipSelectSonda, OUTPUT);
//setto e resetto i dua canali SPI
digitalWrite(chipSelectSD, LOW);
delay(100);
digitalWrite(chipSelectSD, HIGH);
delay(100);
digitalWrite(chipSelectSonda, LOW);;
delay(100);
digitalWrite(chipSelectSonda, HIGH);
delay(100);
SPI.begin;
Serial.begin(115200);
setSyncProvider(RTC.get); // funzione per prelevare l'ora da RTC
if (timeStatus() != timeSet)
Serial.println("Impossibilitato a sincronizzarsi con RTC");
else
Serial.println("RTC sincronizzato");
Serial.print("Inizializzazione scheda SD ...");
// verifica se la scheda SD è presente e funzionante
if (!SD.begin(chipSelectSD)) {
Serial.println("Scheda SD non funzionante o non presente");
// se non lo e' ferma tutto
digitalWrite(chipSelectSD, HIGH);
return;
}
Serial.println("Scheda di memoria SD inizializzata");
digitalWrite(chipSelectSD, LOW);
File dataFile = SD.open("datalog.txt", FILE_WRITE); // creo ed apro il file datalog.txt
if (dataFile) {
dataFile.print(ubicazione);
dataFile.print(';');
dataFile.print(';');
dataFile.print(';');
dataFile.print(';');
dataFile.print(copyright);
dataFile.println(';');
dataFile.println(';');
dataFile.print("Giorno");
dataFile.print(';');
dataFile.print("Mese");
dataFile.print(';');
dataFile.print("Anno");
dataFile.print(';');
dataFile.print("Orario");
dataFile.print(';');
dataFile.print("Sensore1");
dataFile.println(';');
dataFile.println('\r');
dataFile.close(); // chiudo il file
digitalWrite(chipSelectSD, HIGH); // disabilito la comunicazione SPI per la SD
}
}
void loop() {
digitalWrite(chipSelectSD, HIGH);
//Inserisco la lettura del canale 4..20mA
delay(1000);
digitalWrite(chipSelectSonda, LOW); // abilito la comunicazione SPI per la Sonda
// read the loop current
loop_current = ReadFrom420mA();
// error checking
if (loop_current == -1)
Serial.println("Errore: Circuito aperto");
if (loop_current == -2)
Serial.println("Errore : Corto Circuito");
// All is OK, erwmapping to initial data range
received_data = map(loop_current, ADC_4mA, ADC_20mA, data_min_range, data_max_range);
Serial.print("Valore letto: ");
Serial.println(received_data);
digitalWrite(chipSelectSonda, HIGH); // disabilito la comunicazione SPI per la Sonda
secondi = (millis() / 1000); //Converto in secondi il tempo passato dall'accensione
minuti = secondi / 60; // Converto i secondi in minuti
// cambio del tempo di registrazione in base alla scelta inviata dal programma fatto con Visual Studio
switch (sceltafrequenza) {
case 1:
frequenza = 1;
break;
case 5:
frequenza = 5;
break;
case 10:
frequenza = 10;
break;
case 15:
frequenza = 15;
break;
case 30:
frequenza = 30;
break;
case 60:
frequenza = 60;
break;
}
if (minuti - previousminuti > frequenza ) {
previousminuti = minuti;//Tiene in memoria l'ultimo valore di tempo
registradati(); // Vado a scrivere le registrazioni sula SD
}
// leggi il file su SD con comando su seriale su interrogazione da programma fatto con Visual Studio
while (Serial.available()) {
char c = (char)Serial.read();
if ((c < 48) || (c > 57)) {
return;
}
if (c == 48) {// il numero 0 equivale a 48 in ascii
delay(100);
digitalWrite(chipSelectSD, LOW); // abilito la comunicazione SPI per la SD
myFile = SD.open("datalog.txt");
while (myFile.available())
{
Serial.write(myFile.read()); // invio su seriale i dati registrati/letti sulla SD
}
myFile.close();
digitalWrite(chipSelectSD, HIGH); // disabilito la comunicazione SPI per la SD
// inputString = "";
return;
}
// altre possibili interrogazooni fatta da programma creato su visual Studio
if (c == 57) {// il numero 9 equivale a 57 in ascii
delay(100);
digitalWrite(chipSelectSD, LOW); // abilito la comunicazione SPI per la SD // COMMENTATO PER PROVARE
SD.remove ("datalog.txt"); // cancello il file scrito su SD
digitalWrite(chipSelectSD, HIGH); // disabilito la comunicazione SPI per la SD
delay(50);
software_reboot(); // riavvio arduino per ricreare le Inteestazioni
}
// da Programma fatto con Visula Studio cambio le frequenza di registrazione
if (c == 49) {// il numero 1 equivale a 49 in ascii
delay(100);
Serial.println ("1 minuto ");
sceltafrequenza = 1;
}
if (c == 50) {// il numero 2 equivale a 50 in ascii
delay(100);
Serial.println ("5 minuti");
sceltafrequenza = 5;
}
if (c == 51) {// il numero 3 equivale a 51 in ascii
delay(100);
Serial.println ("10 minuti");
sceltafrequenza = 10;
}
if (c == 52) {// il numero 4 equivale a 52 in ascii
delay(100);
Serial.println ("15 minuti");
sceltafrequenza = 15;
}
if (c == 53) {// il numero 5 equivale a 53 in ascii
delay(100);
Serial.println ("30 minuti");
sceltafrequenza = 30;
}
if (c == 54) {// il numero 6 equivale a 54 in ascii
delay(100);
Serial.println ("60 minuti");
sceltafrequenza = 60;
}
}
}
void registradati(void)
{
int sensor0 = analogRead(0); // legge il sensore analogico
// scrivi su seriale data, ora e lettura degli ingressi Analogici
digitalWrite(chipSelectSD, LOW); // abilito la comunicazione SPI per la SD
File dataFile = SD.open("datalog.txt", FILE_WRITE); // creo ed apro il file datalog.txt
if (dataFile) {
//se il file esiste lo compilo
dataFile.print(day());
dataFile.print(';');
dataFile.print(month());
dataFile.print(';');
dataFile.print(year());
dataFile.print(';');
dataFile.print(hour());
dataFile.print(':');
dataFile.print(minute());
dataFile.print(':');
dataFile.print(second());
dataFile.print(';');
dataFile.print(received_data); // valore in arrivo dallo scheda di conversione 4..20 mA
dataFile.println(';');
dataFile.println('\r');
dataFile.close(); // chiudo il file
digitalWrite(chipSelectSD, HIGH); // disabilito la comunicazione SPI per la SD
}
}
unsigned int get_ADC(void) {
digitalWrite(chipSelectSD, HIGH);
unsigned int result;
unsigned int first_byte;
unsigned int second_byte;
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
digitalWrite(chipSelectSonda, 0); // abilito la comunicazione SPI per la Sonda
first_byte = SPI.transfer(0);
second_byte = SPI.transfer(0);
digitalWrite(chipSelectSonda, 1); // disabilito la comunicazione SPI per la Sonda
SPI.endTransaction();
result = ((first_byte & 0x1F) << 8) | second_byte;
result = result >> 1;
return result;
}
int ReadFrom420mA(void)
{
digitalWrite(chipSelectSD, HIGH);
int result;
int ADC_result;
float ADC_avrg;
for (int i = 0; i < 100; i++) {
ADC_result = get_ADC();
// Measure every 1ms
delay(1);
ADC_avrg = ADC_avrg + ADC_result;
}
result = (int)(ADC_avrg / 100);
if (result < 750) {
return -1;
}
if (result > 4009) {
return -2;
}
return result;
}
Ciao, si funziona da sola . Se però collego anche la shield SD, quest'ultima "prende il controllo del bus " e vedo solo lei.... Se stacco il filo MiSO della SD funziona anche la scheda del convertitore .
Allor, probabilmente, il modulo SD è difettoso ...
... uso normalmente i modulini microSD di Adafruit assieme ad altri devices SPI (anche su Arduno MEGA) e non ho mai avuto problemi.
Guglielmo
P.S.: Ia gestione del pin di CS della SD lasciala fare alla libreria, NON fare tu i digitalWrite() ... la libreria funziona correttamente e gestisce lei il pin !
gpb01: P.S.: Ia gestione del pin di CS della SD lasciala fare alla libreria, NON fare tu i digitalWrite() ... la libreria funziona correttamente e gestisce lei il pin !
..ehm... Si....diciamo che avevo provato ad inserire una marea di Digital Write per "forzare" gli stati dei due CS ... .. avevo anche trovato una possibile soluzione sul forum internazionale ( modificare in file della libreria ) ma non ha funzionato ... Sembra che non stacchi il canale MISO ..bohhhh....
longiarduino:
..ehm... Si....diciamo che avevo provato ad inserire una marea di Digital Write per "forzare" gli stati dei due CS ...
NO, quello della SD lo devi lasciar gestire alla libreria SD, mentre per l'altro sensore, visto che non mi sembra usi una libreria, ma fai tu le letture, ovviamente lo devi gestire.
Ciao, ok Grazie.
Per ora sto tentando brutalmente di risolvere affidandomi più alle conoscenze Hardware da vecchio elettricista quale io sono..
In parole povere ci sto buttando dentro un bel relè comandato da Arduino che mi taglia/chiude il filo MOSI del BUS della scheda SD... soluzione brutta, ma sembra funzionare, ho dovuto inserirci però dei delay per esser sicuro che il contatto sia ben chiuso( essendo una lamella meccanica comandata da una bobina) prima di interrogare la SD .
questa soluzione non è che mi piaccia più di tanto ad esser sincero.. Va beh, la uso solo per fare delle prove, successivamente proverò ad acquistare un'altra shield SD a meno che il problema si a livello software o non hardware della SD..
A proposito di delay.. come avete visto io uso i millis per "temporizzare" le registrazioni su SD, ora mettendoci dei delay, i millis come si comportano? Millis continua a contare anche durante il tempo di delay ?
Ciao
P.S. . dovrò poi fare una bella pulizia dello sketch prima di ripostarlo eventualmente... perché ora è pieno di Digital write a tutta manetta
longiarduino:
A proposito di delay.. come avete visto io uso i millis per "temporizzare" le registrazioni su SD, ora mettendoci dei delay, i millis come si comportano? Millis continua a contare anche durante il tempo di delay ?
Mmmm ... mi sa che non ti è chiaro come funziona millis() e come usarla correttamente ...
... per capire bene come si usa la millis(), prova a leggere prima QUI, poi QUI ed infine leggi anche QUI e QUI ... dovresti trovare delle tecniche interessanti.
In ogni caso, il contatore che è dietro a millis() è controllato da interrupt e quindi, NON viene fermato da nulla se non dalla disabilitazione degli interrupt.
longiarduino:
In parole povere ci sto buttando dentro un bel relè comandato da Arduino che mi taglia/chiude il filo MOSI del BUS della scheda SD...
Occhio perché il bus SPI è un bus piuttosto veloce dove i collegamenti devono essere il più breve possibili (massimo 10 ..20 cm) altrimenti da un'infinità di problemi ... :
Salve,
Non so se il consiglio che le vorrei dare é utile, ma io personalmente (anche se non ho mai provato) se un circuito come il suo non funziona o ha problemi come in questo caso, farei un lavoro di questo tipo:
Dividersi le varie operazioni da fare su vari Arduino, si che ogni Arduino ne debba fare una soltanto (SD, convertitore, input...).
Aggiungerei nel giuoco un ulteriore Arduino, il cui unico scopo é di far comunicare attraverso un bus comune (diciamo via seriale) i vari Arduino a lui subordinati.
Tutti gli Arduino hanno un nome proprio (convertitore 'C', SD 'S'_ capo 'A'...) che va posto all'inizio di ogni messaggio. Ogni Arduino legge il bus appena c'é su qualcosa. La prima cosa che cerca é il suo "nome", che deve essere all'inizio del messaggio. Se lo trova allora continua a leggere, in caso contrario ignora. L'unica cosa che cerca in ogni caso é il carattere terminatore che resetta il primo controllo, così da poter ricevere un nuovo messaggio a lui destinato.
Se il messaggio é errato (il carattere destinatario non corrisponde ad alcun Arduino) allora interviene nuovamente il " capo" a svuotare io bus.
Credo che questo metodo possa andare, certo servono molti componenti, ma é l'unica soluzione che conosco
giovepluvio:
Salve,
Non so se il consiglio che le vorrei dare é utile, ma io personalmente (anche se non ho mai provato) se un circuito come il suo non funziona o ha problemi come in questo caso, farei un lavoro di questo tipo:
Dividersi le varie operazioni da fare su vari Arduino, si che ogni Arduino ne debba fare una soltanto (SD, convertitore, input...).
Aggiungerei nel giuoco un ulteriore Arduino, il cui unico scopo é di far comunicare attraverso un bus comune (diciamo via seriale) i vari Arduino a lui subordinati.
Tutti gli Arduino hanno un nome proprio (convertitore 'C', SD 'S'_ capo 'A'...) che va posto all'inizio di ogni messaggio. Ogni Arduino legge il bus appena c'é su qualcosa. La prima cosa che cerca é il suo "nome", che deve essere all'inizio del messaggio. Se lo trova allora continua a leggere, in caso contrario ignora. L'unica cosa che cerca in ogni caso é il carattere terminatore che resetta il primo controllo, così da poter ricevere un nuovo messaggio a lui destinato.
Se il messaggio é errato (il carattere destinatario non corrisponde ad alcun Arduino) allora interviene nuovamente il " capo" a svuotare io bus.
Credo che questo metodo possa andare, certo servono molti componenti, ma é l'unica soluzione che conosco
Ciao, grazie anche per il tuo interessamento. Diciamo che vorrei evitare di usare più Arduini (..mamma mia come suona male il plurale di Arduino ..) , anche perché il tutto poi dovrà essere alimentato a batteria e panello solare.
Per ora ci ho inserito solo un relè ( lunghezza max fili per ora 15 cm, i classici cavetti per le prove, alla fine sarà tutto molto più corto... 4..5 cm al max.. l'unico collegamento lungo sarà quello dell'anello 4..20mA che arriverà a 5,6 mt.. ma con questo non c'è problema.. se ne fanno anche un 50ina senza problemi .. lavora in corrente impressa ) .
E' persin bello sentir " cantare il relè " ogni minuto ..
Più avanti magari valuterò, sempre che non riesco a risolvere sto problemino con la SD, di usare una EEPROM con I2C come collegamento... si tratta poi solo di registrare, ogni 15 minuti quando il progetto sarà a regime, una decina di valori ( giorno, mese, anno, ore, minuti, secondi e 3 o 4 variabili ), devo solo studiarci su un pò per capire come funzionano le EEPROM ..
Pero ora sembra andare... non mi piace ma funziona abbastanza.. non lo considero risolto però...
Vi allego un paio di schermate del programmino fatto con Visual Studio ed un'altra del File *.csv che crea .
Salve,
Scusate del mio intervento poco opportuno, ho la pessima abitudine di rigirare in modi conosciuti problemi senza documentarmi sulla loro reale soluzione. Mi leggerò con calma i link che mi avete consigliato, così la prossima volta ne saprò qualcosa di più
giovepluvio:
Salve,
Scusate del mio intervento poco opportuno, ho la pessima abitudine di rigirare in modi conosciuti problemi senza documentarmi sulla loro reale soluzione. Mi leggerò con calma i link che mi avete consigliato, così la prossima volta ne saprò qualcosa di più
Ah ma tranquillo che io ho solo da imparare .. e da tutti.... Son molto " improvvisato" in questo campo... basta guardare i miei codici per capirlo ...
Vado molto ( purtroppo) ad improvvisazione, faccio molta fatica a capire la programmazione in generale, ho troppe grosse lacune di elettronica ed informatica.... ho studiato tutt'altro ai tempi della scuola...
Ciao a tutti. Alla fine per risolvere, spero temporaneamente, ho dovuto inserire un relè che mi taglia il "filo" del MISO della Card Reader.
Ho provato mille soluzioni ma senza risultato, probabilmente modulino difettoso... Ne acquisterò un altro appena avrò altro materiale da acquistare. Nel frattempo ho implementato anche un modulino HC-05 e spero, in seguito di riuscire a fare una App Android da usare per leggere i dati registrati sulla SD oltre che con il programmino fatto con Visual Studio Comunity ( anche se a dir la verità ora ho spostato solo le seriali e quindi lo interrogo solo tramite bluetooth.. ) Per ora il collegamento bluetooth risulta funzionante e riesco ad "interrogare" Arduino e fargli inviare le registrazioni anche sulla seriale bluetooth, devo "solo" trovare il modo di fargli creare un file *.CSV con Android, ma questo non è oggetto di questo forum..
Ma accetto suggerimenti....
Per mantenere tutte e due le seriali devo scrivere doppio codice? nel senso riscrivere le stesse istruzioni di codice per entrambi li seriali?
// leggi il file su SD con comando su seriale su interrogazione da programma fatto con Visual Studio
while (Serial.available()) {
char c = (char)Serial.read();
if ((c < 48) || (c > 57)) {
return;
}
if (c == 48) {// il numero 0 equivale a 48 in ascii
delay(100);
digitalWrite(chipSelectSD, LOW); // abilito la comunicazione SPI per la SD
myFile = SD.open("datalog.txt");
while (myFile.available())
{
Serial.write(myFile.read()); // invio su seriale i dati registrati/letti sulla SD
}
myFile.close();
digitalWrite(chipSelectSD, HIGH); // disabilito la comunicazione SPI per la SD
return;
}
// altre possibili interrogazioni fatta da programma creato su visual Studio
if (c == 57) {// il numero 9 equivale a 57 in ascii
delay(100);
digitalWrite(chipSelectSD, LOW); // abilito la comunicazione SPI per la SD
SD.remove ("datalog.txt"); // cancello il file scrito su SD
digitalWrite(chipSelectSD, HIGH); // disabilito la comunicazione SPI per la SD
delay(50);
software_reboot(); // riavvio arduino per ricreare le Inteestazioni
}
Praticamente raddoppiare le istruzioni dopo il while (Serial.available()) etc etc facendone un altro con (Serial1.available()).....
Allego anche schema fatto con Fritzing... spero di non aver fatto errori e troppe ragnatele ma i fili erano già parecchi..
gpb01:
Allor, probabilmente, il modulo SD è difettoso ...
... uso normalmente i modulini microSD di Adafruit assieme ad altri devices SPI (anche su Arduno MEGA) e non ho mai avuto problemi.
Guglielmo
P.S.: Ia gestione del pin di CS della SD lasciala fare alla libreria, NON fare tu i digitalWrite() ... la libreria funziona correttamente e gestisce lei il pin !
Ciao gpb01 , tu acquisti attraverso il sito diretto che mi hai "linkato" ?