Progetto preliminare per un logger subacqueo

Vero, ma avevo già dato la soluzione QUI ... con un piccolo uso maggiore della memoria flash (in tutto 1.5 KB) si aveva anche il float e non serviva fare altro :wink:

E, se proprio si vuole evitare questo, basta passare alla sprintf() due interi (parte intera e parte decimale) ricavati con una banale operazione matematica :slight_smile:

Guglielmo

1 Like

Concordo!
@Etemenanki visto che devi solo visualizzare del testo, potresti usare una libreria che non implementa le API per la grafica.

Ad esempio l'arcinota U8g2, implementa anche la classe U8x8 "text only" che consente un notevole risparmio di RAM visto che non usa un buffer.

Perche' usavo le tre stringhe anche per scrivere sul display, e mi era sembrato meglio usare dei char al posto dei float per fare il refresh delle scritte (il clearDisplay ho letto che e' lento, quindi per cancellare prima scrivo le vecchie in nero e poi scrivo le nuove in bianco e poi salvo le nuove in altre tre stringhe per il prossimo ciclo, nella funzione dispdati) ... se faccio tutta la conversione dentro la sprintf, poi per fare la stessa cosa direttamente con le variabili non convertite e salvare i valori per il ciclo successivo mi servono altre due float ed un'altra int, e credevo che tre stringhe da 5 caratteri tenessero via meno spazio.

L'esempio del file da aggiungere alla piattaforma per far usare alla sprintf anche i float, non porta via ancora piu memoria ?

Questa parte non l'ho capita bene, devo studiarmi meglio l'uso della libreria sd.

Avevo provato anche ad usare un po di flag dentro la sprintf (le "schifezze" da mettere dopo i percento :grin:), ma mi dava sempre degli errori, ma credo di aver fatto casino io li ... avevo anche provato il sistema che menziona Cotestatnt nel post 2 di quell'esempio, con il *10%10, ma probabilmente non avevo usato il corretto tipo di flag ... mi rileggo meglio gli esempi e provo a vedere se ci capisco qualcosa.

Me la sto studiando, sembra un po piu incasinata da capire della adafruit, ma se fa risparmiare memoria e risorse alla MCU, ne vale la pena ... quello che vorrei riuscire a fare al momento, anche in vista delle nuove cose che mi hanno chiesto, e' riuscire a trovare un font che mi permetta di far stare tre righe nell'altezza del display ed occupare tutta la larghezza con 9 caratteri ... la riga piu lunga sarebbe "P xxx.x m", solo nel caso scendessero oltre i 99m, le altre due sono la temperatura, che avrebbe un carattere in meno, ed il numero della lettura, che essendo un'unsigned int al massimo potrebbe arrivare a "L 65535" (65000 letture ad una lettura ogni secondo e mezzo circa fanno piu di 27 ore di logging, direi che possano bastare per una sessione di lavoro :crazy_face:) ... so ovviamente che sara' impossibile trovare un font che usi esattamente questi spazi, e che allo stesso tempo sia il piu leggibile e semplice possibile per risultare anche sulle riprese della camera di navigazione, ma voglio trovare la migliore alternativa (per ora l'unico display che ho in casa e' da 0.96, ne ho ordinato uno da 1.3, ma ancora non e' arrivato, e comunque ha la stessa risoluzione, 128x64)

Ma l'utilizzo di una MCU con poche risorse come il 328 è imperativo?

E' che mi sono rimaste in casa alcune 328PB inutilizzate, mentre delle altre non ne ho piu neppure una, per cui se riuscivo ad utilizzare una di quelle era meglio.

Non pensavo che fare tre cose relativamente semplici come leggere un sensore, scrivere su un display e scrivere su una SD consumasse cosi tanta memoria.

Ho provato a modificarlo per usare la libreria u8g2 (sempre che abbia capito come si usa), e ad usare sprintf con le flag per far fare a lei la conversione, ed ora l'errore e' cambiato, mi dice che sto usando il 93% della memoria ed il 123% dello spazio per le variabili globali :face_with_raised_eyebrow:

pero' questo punto mi viene il dubbio che sia il mio modo di scrivere che non va bene ... voglio dire, io di solito mi scrivo le varie funzioni e poi nel loop le chiamo e basta, nell'ordine che voglio, pero' per farlo devo appunto usare tutte variabili globali, non mi sembrava che le mie impostazioni ne usassero cosi tante (anche perche' rispetto a prima ne ho eliminate alcune), ma forse c'e' qualcos'altro che non afferro ... se spostassi tutto dentro il loop e dichiarassi le variabili solo li dentro, sarebbe meglio o si incasinerebbe tutto di piu ?

Oppure e' colpa di quel "buffer" della u8g2 ?

#include <Wire.h>
#include <SPI.h>
#include <U8g2lib.h>
#include <SD.h>
#include <MS5837.h>

#define OLED_RESET 4
U8G2_SSD1306_128X64_NONAME_F_HW_I2C display(U8G2_R0, /* reset=*/ OLED_RESET);

#define ledp 30
float profon;
float temper;
char strDati[38];
unsigned int lettura = 0;
MS5837 sensor;
File fileDati;

void errore() {
  while (1) {
    digitalWrite(ledp, HIGH);
    delay(250);
    digitalWrite(ledp, LOW);
    delay(250);
  }
}

void leggisens() {
  lettura++;
  for (byte x = 0; x < 4; x++) {
    sensor.read();
    temper += sensor.temperature();
    profon += sensor.depth();
    delay(40);
  }
  temper /= 4;
  profon /= 4;
  sprintf(strDati, "L %u, T %d.%d C, P %d.%d m", lettura, (int)temper, (int)(temper*10)%10, (int)profon, (int)(profon*10)%10);
}

void dispdati() { // scrive i dati sul display
  display.clearBuffer();
  display.setFont(u8g2_font_chargen_92_tf);
  display.setCursor(0, 0);
  display.print(F("L "));
  display.println(lettura);
  display.print(F("T "));
  display.println(temper, 1);
  display.print(F("P "));
  display.print(profon, 1);
  display.sendBuffer();
}

void scrivisd() {
  fileDati = SD.open("data.csv", FILE_WRITE);
  if (fileDati) {
    fileDati.println(strDati);
    fileDati.close();
  digitalWrite(ledp, HIGH);
    delay(50);
    digitalWrite(ledp, LOW);
  }
  else {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println(F("SD ERR"));
    display.display();
    errore();
  }
}

void setup() {
  display.begin(); //inizializza display ?
  pinMode(ledp, OUTPUT);
  digitalWrite(ledp, LOW);
  
  sensor.init();
  if (!sensor.init()) { //sensore ko, blocca
    display.clearBuffer();
    display.setFont(u8g2_font_chargen_92_tf);
    display.setCursor(0, 0);
    display.print("SENS ERR");
    display.sendBuffer();
    errore();
  }
  
  display.clearBuffer();
  display.setFont(u8g2_font_chargen_92_tf);
  display.setCursor(0, 0);
  display.print("ATTENDI");
  display.sendBuffer();
  delay(1000);
}

void loop() {
  leggisens();
  dispdati();
  scrivisd();
  delay(1500);
}

... e niente eh ... la SSD1306Ascii ... proprio non la vuoi usare eh! :roll_eyes: ... è la più ottiimizzata di tutte, inutile che usate altre cose ... io ne avrò provate almeno una decina diverse e, per il solo testo, quella è la più semplice e compatta.

Ti ripeto .. la tua scrivisd() è concettualmente errata, NON si fa così ... si apre il file e si controlla la SD UNA sola volta nel setup() e poi si scrive e si forza la scrittura nel loop().

Guglielmo

:grin: non e' che non la voglio usare, e' che le sto provando un po tutte, ho gia installato pure quella ... stavo provando con la u8g2 perche' aveva un font con delle dimensioni che sembravano le migliori per occupare tutto lo spazio, tutto qui (stasera provo anche la ascii, promesso) ... quello che stavo cercando di capire era il motivo per cui avendo eliminato alcune variabili globali, mi usa piu spazio di prima, tutto qui.

Quella parte non l'ho ancora guardata, intendi che non e' corretto chiuderla dopo ogni scrittura ?

ssd1306

Si, che apri e chiudi a fare la SD? ... perdi solo tempo, aprila nel setup() e verifica che sia a posto, nel loop() fai solo una scrittura e, con l'apposito metodo flush() forzi la scrittura fisica senza dover chiudere e riaprire :wink:

Guglielmo

E' solo che in alcuni esempi dicevano di lasciarla aperta solo se serviva un'elevata velocita' di scrittura, mentre suggerivano di chiudere il file dopo ogni scrittura se la velocita' non era richiesta, dicendo che cosi era piu sicuro che il file non si rovinasse se si spegneva il tutto per errore senza chiuderlo (ma mi accorgo sempre di piu che molti degli esempi in rete non sembrano scritti da gente che se ne intende molto, anche in campo di programmazione, non solo nell'elettronica in genere come gia sapevo).

Quindi e' meglio lasciarlo aperto ? ... un fileDati.flush() dopo il fileDati.println() dovrebbe garantire la scrittura della stringa sulla sd anche senza il close, giusto ?

Sto cercando di capire come funziona la SSD1306ascii, ma le "istruzioni" mi sembrano un po criptiche (e nessuno dei documenti presenti su github mi si apre, quindi ho dovuto cercare altrove) ... dai pochi esempi che ho trovato, sembrerebbe non usare alcun buffer, pero' tutti gli esempi trasformano i dati con strtof prima di inviarli al display con oled.print("stringa") ... oppure non ho capito io ?

EDIT: no, ne ho appena trovato uno che passa al display i dati in forma numerica ... con tutti sti "esempi" uno diverso dall'altro, inizio a non capirci piu un "piffero"

la flush() è fatta apposta per forzare la scrittura fisica :wink:

Ovvio, devi scaricare e scompattare, andare nella cartella della documentazione, andare nella cartella html e quindi aprire "index.html" :grin:

... e tu, difatti, con la sprinf(), li converti tutti in un unica grande stringa :wink:

Comunque accetta anche altri tipi diati ... ovviamente!

Guglielmo

Sto facendo un paio di prove al volo, su wokwi, mi stampa una stringa se glie la passo con le virgolette, mi accetta una variabile, anche con il ,1 per ridurre i decimali, NON mi accetta una combinazione di caratteri e variabile, devo stamparle tre volte per ogni riga (ma quello sarebbe il minimo)

Facendo un po di prove con wokwi e la SSD1306ascii, sono riuscito a tirare fuori questa combinazione, che mi stampa questo sul display (dato che avanzava spazio sotto e non c'era nessun font che mi facesse usare tutto lo spazio, ho aggiunto pure la batteria, per complicarmi la vita, per ora solo fittizia per vedere le posizioni in cui veniva il testo), purtroppo questo e' l'unico font semidecente con quella libreria, ma meglio di nulla ... sempre che poi sul display reale faccia lo stesso :grin:

Wire.begin();     
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
  oled.set400kHz();  
    oled.setFont(fixed_bold10x15);
    oled.clear();
    oled.setCursor(0, 0);
    oled.print("Lett ");
    oled.print(lett);
    oled.setCursor(0, 2);
    oled.print("Temp ");
    oled.print(temp, 1);
    oled.print("C");
    oled.setCursor(0, 4);
    oled.print("Prof ");
    oled.print(prof, 1);
    oled.print("m");
    oled.setFont(font5x7);
    oled.setCursor(60, 7);
    oled.print("BATT 3.65 V");

testdisplaywok

EDIT: ma come mai nel begin richiama ancora Adafruit ?

Ma non basta 23.5 °C ci devi pure scrivere Temp, stessa cosa per 3.65 V, poi la posizione è sempre quella, prima il numero di letture, poi la temperatura e la profondità.

Per i font c'è l'imbarazzo della scelta, c'è da vedere come dici la resa sul display fisico. Per i numeri trovo sia più leggibile il font lcdnums12x16 sette segmenti.

Perché usa internamente una libreria di adafruit.
https://github.com/greiman/SSD1306Ascii/blob/master/src/SSD1306init.h

Ciao.

Abundare est melium quam deficere (specie se non sai a chi va in mano :grin:)

Penso comunque di usare degli oled.print(F("stringhe")) per le parti sempre uguali di testo, dovrebbe risparmiare ancora qualcosina credo.

Per ora, a forza di modifiche (e bestemmie, ma quelle sono gratis :grin:) sono riuscito a farlo compilare senza errori, e con il 76% dello spazio ed il 62% della memoria dinamica occupati, ma tranquilli, riusciro' a sforare di nuovo, che devo aggiungerci ancora altre cose.

Ma per ora pausa, ora di cena.

... più che altro usa delle definizioni che riprende da Adafruit, ma NON usa librerie di Adafuit (non ne include nessuna) ... in pratica ha copiato le costanti di inizializzazione del display dalla libreria di Adafruit. :wink:

this section is based on https://github.com/adafruit/Adafruit_SSD1306

Guglielmo

Immagino che l'OLED tu lo abbia, fatti le prove con un Arduino UNO, così vedi bene la resa dei vari font e scegli il migliore che ... per queste cose, i vari simulatori, lasciano comunque il tempo che trovano.

Guglielmo

Si, lo immaginavo, l'ho usato solo per la comodita' di modificare al volo la posizione iniziale delle righe per avere un'idea di massima degli spazi occupati, poi raffinero' il tutto con un display reale (appena trovo in che scatola l'ho messo :crazy_face:)

Un dubbio (uno a caso nel mucchio :grin:)

Quando si usa l'ide di Arduino, per definire i pin lui fa riferimento ai pin della scheda (ad esempio, per la SPI della Nano, SS=4, MOSI=11, MISO=12, SCK=13), mentre sul chip la numerazione non corrisponde ovviamente(SS=14, MOSI=15, MISO=16, SCK=17), c'e' un modo per "dire" all'IDE che voglio usare un 328PB standalone e quindi i pin che indico sono quelli fisici del chip, oppure bisogna sempre fare la traslazione da pin fisici a pin della scheda, per le dichiarazioni e le funzioni ?

... intanto devi chiarire che "core" intendi usare per il ATmega328PB ... se usi il MiniCore leggi dal penultimo punto in poi della documentazione per avere le indicazioni sui pin.

Guglielmo