HOWTO · Arduino

Funzione printf di Arduino

Si può ottenere lo stesso output di printf() usando la funzione sprintf() e la funzione Serial.print().

In questa pagina

L’ambiente di programmazione standard di Arduino non offre una chiamata printf() portabile che scriva sul monitor seriale. Alcuni core per schede aggiungono il proprio metodo Serial.printf(), quindi consulta la documentazione della scheda che hai scelto. Per scrivere sketch portabili, formatta il testo in un buffer di caratteri con sprintf() e invialo con Serial.print() o Serial.println(). Se non ti serve una stringa di formato, puoi comporre lo stesso messaggio direttamente con più chiamate seriali.

Arduino offre printf()?

Non esiste un’unica interfaccia printf() garantita su tutte le schede Arduino. La funzione printf() della libreria C scrive normalmente su un flusso di output standard, che in un ambiente a microcontrollore potrebbe non essere collegato a una porta seriale. Può essere disponibile un metodo Serial.printf() specifico del core, ma la sua disponibilità e gli specificatori di formato supportati dipendono dalla scheda. Gli sketch qui sotto usano setup() e loop() e scrivono tramite Serial; un piccolo sostituto seriale lato host permette di eseguire gli stessi esempi senza una scheda Arduino. Sulla scheda, il core Arduino fornisce Serial e il ciclo di vita dello sketch.

Formattare il testo con sprintf() e inviarlo tramite la seriale

Usa sprintf() quando un messaggio richiede segnaposto o spaziatura. La funzione scrive il testo completo in un array di caratteri; poi Serial.println() invia quel testo seguito da un terminatore di riga. Questo sketch usa snprintf() per passare al formattatore la capacità dell’array e controlla che il messaggio completo vi entri prima di inviarlo:

#include <cstdio>

#ifdef ARDUINO
#include <Arduino.h>
#else
class HostSerial {
 public:
  void begin(unsigned long) {}
  void println(const char* text) { std::puts(text); }
};
HostSerial Serial;
#endif

void setup() {
  Serial.begin(9600);
  char buffer[32];
  const int value = 42;
  const int length = std::snprintf(buffer, sizeof(buffer), "The answer is: %d", value);
  if (length >= 0 && static_cast<unsigned int>(length) < sizeof(buffer)) {
    Serial.println(buffer);
  }
}

void loop() {}

#ifndef ARDUINO
int main() {
  setup();
  return 0;
}
#endif
The answer is: 42

snprintf() restituisce il numero di caratteri che avrebbe scritto, senza contare il carattere nullo terminatore. Se tale numero è maggiore o uguale alla capacità dell’array, lo sketch non invia un messaggio incompleto. Verifica che la libreria C della scheda scelta fornisca snprintf() con il comportamento previsto: disponibilità e comportamento delle funzioni di formattazione possono variare in base alla scheda e al core. Le etichette visibili nei blocchi di codice e nell’output restano in inglese, perché questi blocchi sono mantenuti identici all’originale.

Comporre l’output con Serial.print()

Per semplici etichette e valori, le chiamate dirette evitano un buffer temporaneo per il testo formattato. Serial.print() continua sulla stessa riga; Serial.println() la termina. Questo sketch compone la stessa riga con chiamate seriali:

#include <cstdio>

#ifdef ARDUINO
#include <Arduino.h>
#else
class HostSerial {
 public:
  void begin(unsigned long) {}
  void print(const char* text) { std::printf("%s", text); }
  void print(int value) { std::printf("%d", value); }
  void print(double value, int digits) { std::printf("%.*f", digits, value); }
  void println(const char* text) { std::printf("%s\n", text); }
};
HostSerial Serial;
#endif

void setup() {
  Serial.begin(9600);
  const int temperature = 25;
  const double humidity = 60.5;
  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print(" C, Humidity: ");
  Serial.print(humidity, 1);
  Serial.println("%");
}

void loop() {}

#ifndef ARDUINO
int main() {
  setup();
  return 0;
}
#endif
Temperature: 25 C, Humidity: 60.5%

Il sostituto lato host riproduce le chiamate usate qui, così è possibile mostrare la riga dello sketch senza hardware; non è un core Arduino. Sulla scheda, Serial.print(humidity, 1) richiede una cifra dopo il separatore decimale, mentre il formato esatto supportato dipende dall’implementazione di Serial della scheda.

Gestire i valori in virgola mobile e i limiti del buffer

La formattazione dei valori in virgola mobile tramite sprintf() non è uniforme tra i core Arduino: alcune librerie C per sistemi embedded omettono la conversione dei valori float dalle funzioni di I/O formattato per risparmiare memoria del programma. Verifica il core di destinazione prima di affidarti a %f. La forma diretta Serial.print(value, digits) è un’alternativa quando il core supporta la consueta implementazione Arduino di Print.

Qualsiasi output formattato deve entrare nel relativo array di caratteri, compreso il terminatore \0. Quando disponibile, usa snprintf() con la capacità effettiva dell’array e controllane il valore restituito prima di usare il risultato. Se il testo formattato è più lungo dell’array, aumenta la dimensione del buffer oppure abbrevia il messaggio. Un buffer più grande consuma più RAM, una risorsa limitata su molte schede.

Scegliere l’approccio giusto

Scegli sprintf() o snprintf() quando un’unica stringa di formato rende più leggibile un messaggio strutturato, poi invia il risultato con Serial.println(). Scegli le chiamate a Serial.print() quando devi solo concatenare poche etichette e valori. Entrambi gli approcci inviano testo tramite l’interfaccia seriale; nessuno garantisce un supporto identico alla formattazione su ogni scheda. Verifica i metodi specifici del core e il comportamento dei valori in virgola mobile per la scheda per cui compili.