Problema di memoria con array

Buonasera!

Sono piuttosto nuova del mondo Arduino e della programmazione, ma sto lavorando per un progetto di tesi con una stampante termica, e ho un problema mooolto importante di dimensioni di sketch.

In breve: il mio progetto utilizza una mini printer termica (di Adafruit) per stampare delle "lettere" di un linguaggio visivo rappresentate da file bitmap. Per essere stampati, questi file bitmap sono stati trasformati tutti in grandi array, incorporati nello sketch e richiamati con PROGMEM (devo dire però che non so bene come funzioni nemmeno questa cosa), quindi da quello che ho capito sono sulla memoria flash di Arduino.
Ogni file contiene questa stringa

static PROGMEM prog_uchar A_data[] = {

e poi tutti i pixel tipo 0x00 per il bianco e 0xFF per il nero

Il problema è che non ci stanno tutti i 26 file che mi servono, ma solo una decina! E non mi è possibile ridurre più di tanto il numero dei pixel, perché quelli bianchi sarebbero sempre comunque più o meno lo stesso numero, visto che ogni lettera incorpora la spaziatura da sinistra per essere centrata, e insomma un sacco di spazio è buttato via per questo.

C'è un modo per salvare questi array da qualche altra parte, anche sul pc, e richiamarli in un altro modo?
Ho cercato qualche informazione sulle memorie esterne, ma non ho nessuna esperienza in campo e mi servirebbe capire cosa fare =( mi servirebbero più o meno altri 50.000 bytes...

Grazie mille in anticipo per qualsiasi suggerimento!

Non puoi salvarle su una memoria sd esterna?

È quello che sto chiedendo, perché non ho mai usato memorie esterne con Arduino e non so nemmeno da dove cominciare, mi dispiace per l'ignoranza.
Si possono salvare su sd tutti gli array e ripescarli?
Come funziona? Come li richiamo poi?

Ora lo sketch, per esempio, usa questa riga per mandare il file alla stampante

#include "C.h"
printer.printBitmap(C_width, C_height, C_data);

E poi nel file .h è contenuta questa riga

static PROGMEM prog_uchar C_data[] = {

ecc.

Se fosse possibile potrei richiamarli anche dal computer, perché comunque la stampante deve essere sempre collegata a un pc, nel mio progetto...

Non ho ancora usato le memorie esterne io, però esiste la libreria SD SD - Arduino Reference e ci sono molti tutorials online (per fare un lettore micro sd casalingo)..

In teoria si può fare, puoi inviare i dati dal PC e leggerli con arduino, ovviamente non devi spedire tutti i dati e poi usarli per stampare perché altrimenti sei punto e capo. Quindi li devi processare a poco a poco, man mano che arrivano i dati li processi e li stampi.

Purtroppo non conosco il codice che stai usando e quindi non sono in grado di suggerirti modifiche e adattamenti.
C'è un modo per visionare il codice interno della funzione printer.printBitmap() o in generale alla classe printer.

Ciao.

Anche dalla SD, non saprei proprio cosa sostituire, se nel file dell'array, nella libreria della stampante o nello sketch...

MauroTec, sono andata a cercare nella libreria (Adafruit thermal) e ho trovato questa parte

void Adafruit_Thermal::printBitmap(
 int w, int h, const uint8_t *bitmap, bool fromProgMem) {
  int rowBytes, rowBytesClipped, rowStart, chunkHeight, x, y, i;

  rowBytes        = (w + 7) / 8; // Round up to next byte boundary
  rowBytesClipped = (rowBytes >= 48) ? 48 : rowBytes; // 384 pixels max width

  for(i=rowStart=0; rowStart < h; rowStart += 255) {
    // Issue up to 255 rows at a time:
    chunkHeight = h - rowStart;
    if(chunkHeight > 255) chunkHeight = 255;

    writeBytes(18, 42, chunkHeight, rowBytesClipped);

    for(y=0; y < chunkHeight; y++) {
      for(x=0; x < rowBytesClipped; x++, i++) {
        PRINTER_PRINT(fromProgMem ? pgm_read_byte(bitmap + i) : *(bitmap+i));
      }
      i += rowBytes - rowBytesClipped;
    }
    timeoutSet(chunkHeight * dotPrintTime);
  }
  prevByte = '\n';
}

void Adafruit_Thermal::printBitmap(int w, int h, Stream *stream) {
  int rowBytes, rowBytesClipped, rowStart, chunkHeight, x, y, i, c;

  rowBytes        = (w + 7) / 8; // Round up to next byte boundary
  rowBytesClipped = (rowBytes >= 48) ? 48 : rowBytes; // 384 pixels max width

  for(rowStart=0; rowStart < h; rowStart += 255) {
    // Issue up to 255 rows at a time:
    chunkHeight = h - rowStart;
    if(chunkHeight > 255) chunkHeight = 255;

    writeBytes(18, 42, chunkHeight, rowBytesClipped);

    for(y=0; y < chunkHeight; y++) {
      for(x=0; x < rowBytesClipped; x++) {
        while((c = stream->read()) < 0);
        PRINTER_PRINT((uint8_t)c);
      }
      for(i = rowBytes - rowBytesClipped; i>0; i--) {
        while((c = stream->read()) < 0);
      }
    }
    timeoutSet(chunkHeight * dotPrintTime);
  }
  prevByte = '\n';
}

void Adafruit_Thermal::printBitmap(Stream *stream) {
  uint8_t  tmp;
  uint16_t width, height;

  tmp    =  stream->read();
  width  = (stream->read() << 8) + tmp;

  tmp    =  stream->read();
  height = (stream->read() << 8) + tmp;

  printBitmap(width, height, stream);
}

E forse la parte interessante è questa

PRINTER_PRINT(fromProgMem ? pgm_read_byte(bitmap + i) : *(bitmap+i));

E se passassi ad Arduino MEGA?
--> http://arduino.cc/en/Main/ArduinoBoardMega2560

Hai visto proprio bene, la funzione printBitMap() prende l'argomento bool fromProgMem, che deve essere true per prelevare il dato dalla flash. Mentre se fromProgMem è false il dato viene preso dalla ram.

Non so a che livello che si con la programmazione, mi sembra che con il C/C++ te la cavi, mi serve per adattare il modo di esprimermi.

Su arduino serve un buffer dati di n byte (n da stabilire), il codice resta in ascolto sulla seriale quando arrivano dati li inserisci nel buffer, se il buffer si riempie o se viene ricevuto il fine trasmissione il codice smette di ascoltare sulla seriale e inizia a processare i dati prelevandoli ad uno ad uno e stampandoli con printBitMap(, , , false) (nota l'ultimo argomento false). Nota che quando il buffer si riempie (sicuramente si riempe) bisogna spedire al PC un codice che per il programma che gira sul pc vuol dire "arduino è occupato, smetto di iniviare dati".

Quindi tra arduino e PC si instaura una corrispondenza busy/ready.

Ti consiglio di prendere confidenza con l'invio e ricezione dati tra PC e arduino. Partendo dagli esempi di codice presente nell'ide già ti fai una idea, modificandoli prendi confidenza.

Quanto descritto però richiede un programma lato PC che dialoghi con arduino e che comprenda il meccanismo busy/ready, quindi il programma lo devi scrivere e molti usano Processing di cui però conosco solo il nome. :stuck_out_tongue:

Ciao.

Penso che anche con un semplice programmino (lato PC) che scriva sulla seriale i valori dell'array con un divisore ,come "%" per dire , e che copi solo una determinata quantità di dati immagazzinabili da Arduino te la possa cavare. Lato Arduino invece penso tu possa fare uno sketch che faccia i seguenti step :

  1. Controlla l'ingresso del segnale
  2. Inizializza l'array
  3. Divide ogni segmento con il divisore "%"
  4. Lo salva nell'array
  5. Stampa ciò che ha ricevuto
  6. Cancella il contenuto attuale dell'array
  7. Invia il segnale "Ready" al PC
  8. Ricomincia step 1

Non so se potrebbe funzionare ma, se così fosse, lato PC te la potresti cavare anche con un semplice programmino in C. :wink:

MA

MasterArchi:
... con un divisore ,come "%" per dire ...

... emm ... quello si chiama "modulo" e calcola i resto di una divisione tra interi ... :roll_eyes:

Guglielmo

gpb01:

MasterArchi:
... con un divisore ,come "%" per dire ...

... emm ... quello si chiama "modulo" e calcola i resto di una divisione tra interi ... :roll_eyes:

Guglielmo

Si, ma in uscita nel seriale non c'è un'espressione

:grin: :grin: :grin: ahhhhh... quindi tu intendevi un "carattere separatore" ... XD XD XD

... ok, allora ci siamo, ma fai il favore, lascia stare la parola "divisore" che ricorda tanto le operazioni matematiche e usa "carattere separatore" che almeno non si rischia la confusione ... :wink:

Guglielmo

gpb01:
:grin: :grin: :grin: ahhhhh... quindi tu intendevi un "carattere separatore" ... XD XD XD

... ok, allora ci siamo, ma fai il favore, lascia stare la parola "divisore" che ricorda tanto le operazioni matematiche e usa "carattere separatore" che almeno non si rischia la confusione ... :wink:

Esattamente, scusate l'errore non ricordavo il termine esatto XD
Comunque, come struttura del programma sta bene?

MA

Mah ... io concordo con PaoloP :

PaoloP:
E se passassi ad Arduino MEGA?
--> http://arduino.cc/en/Main/ArduinoBoardMega2560

... visto che deve mettere in PROGMEM 50 KBytes ... quella è la scheda adatta ... senza tanti giri strani :wink:

Guglielmo

Guglielmo hai il link di quella MEGA (compatibile) ma con dimensioni della UNO?
Forse potrebbe interessargli.

PaoloP:
Guglielmo hai il link di quella MEGA (compatibile) ma con dimensioni della UNO?
Forse potrebbe interessargli.

Certo ... eccola QUI :smiley:

Guglielmo

Ok ragazzi grazie a tutti... preferirei evitare di comprare un'altra scheda però la soluzione software sembra complicata, perché io di programmazione non ne so ancora abbastanza :confused:

Potrei provare, da quello che ho capito, a usare Processing ad esempio per mandare un solo array alla volta ad Arduino, come lo sto usando per mandare l'informazione sul tasto premuto. Avete qualche link / guida da consigliarmi sull'invio e ricezione dati tra PC e Arduino?