HOWTO · Arduino

Arduino Função printf

Pode-se obter a mesma saída que printf() usando a função sprintf() e a função Serial.print().

Nesta página

O ambiente padrão de programação do Arduino não oferece uma chamada printf() portátil que escreva no monitor serial. Alguns núcleos de placa acrescentam seu próprio método Serial.printf(), então consulte a documentação da placa escolhida. Para sketches portáteis, formate o texto em um buffer de caracteres com sprintf() e envie-o com Serial.print() ou Serial.println(). Se você não precisar de uma string de formato, várias chamadas seriais podem montar a mesma mensagem diretamente.

O Arduino oferece printf()?

Não há uma única interface printf() garantida em todas as placas Arduino. Em geral, printf() da biblioteca C escreve em um fluxo de saída padrão, que pode não estar conectado a uma porta serial em um ambiente de microcontrolador. Pode haver um Serial.printf() específico do núcleo, mas sua disponibilidade e os especificadores de formato compatíveis dependem do alvo. Os sketches abaixo usam setup() e loop() e escrevem por meio de Serial; uma pequena implementação substituta de serial no computador permite executar os mesmos exemplos sem uma placa Arduino. Na placa, o núcleo Arduino fornece Serial e o ciclo de vida do sketch.

Formate o texto com sprintf() e envie-o pela serial

Use sprintf() quando a mensagem precisar de marcadores de posição ou preenchimento. A função grava o texto completo em um array de caracteres; em seguida, Serial.println() envia esse texto e uma quebra de linha. Este sketch usa snprintf() para informar ao formatador a capacidade do array e verifica se a mensagem completa cabe antes de enviá-la:

#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() retorna o número de caracteres que escreveria, sem contar o caractere nulo terminador. Se essa quantidade for igual ou maior que a capacidade do array, o sketch não envia uma mensagem parcial. Verifique se a biblioteca C da placa escolhida oferece snprintf() conforme esperado; a disponibilidade e o comportamento das funções de formatação podem variar conforme a placa e o núcleo.

Monte a saída com Serial.print()

Para rótulos e valores simples, chamadas diretas evitam um buffer temporário de formatação. Serial.print() continua na mesma linha; Serial.println() encerra a linha. Este sketch monta a mesma linha com chamadas seriais:

#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%

A implementação substituta de serial no computador reproduz as chamadas usadas aqui para mostrar a linha do sketch sem hardware; ela não é um núcleo Arduino. Na placa, Serial.print(humidity, 1) solicita um dígito após o separador decimal, e a formatação exata disponível depende da implementação de Serial da placa.

Lide com valores de ponto flutuante e limites do buffer

A formatação de valores de ponto flutuante por meio de sprintf() não é uniforme entre os núcleos Arduino: algumas bibliotecas C para sistemas embarcados omitem a conversão de ponto flutuante da E/S formatada para economizar memória de programa. Verifique o núcleo do alvo antes de depender de %f. A forma direta Serial.print(value, digits) é uma alternativa quando o núcleo oferece a implementação usual de Print do Arduino.

Qualquer saída formatada precisa caber no array de caracteres, incluindo o \0 terminador. Quando disponível, use snprintf() com a capacidade real do array e confira o valor de retorno antes de usar o resultado. Se o texto formatado for maior que o array, aumente o buffer ou encurte a mensagem. Um buffer maior consome mais RAM, que é limitada em muitas placas.

Escolha a abordagem certa

Escolha sprintf() ou snprintf() quando uma única string de formato tornar uma mensagem estruturada mais fácil de ler e envie o resultado com Serial.println(). Escolha chamadas de Serial.print() quando precisar apenas combinar alguns rótulos e valores. As duas abordagens enviam texto pela interface serial; nenhuma garante o mesmo suporte à formatação em todas as placas. Confira os métodos específicos do núcleo e o comportamento com valores de ponto flutuante na placa para a qual você compila.