Redirigiendo printf() al puerto serie de mi Arduino.

Por recomendación de surbyte. :wink:

Printf es una función de "stdio" del conjunto "libc", que casualmente, siempre es cargada en todo programa c.
Así pues, poner este "include" en nuestro código, seria redundante e innecesario:
#include <stdio.h>

La función "printf()" utiliza el canal de salida estándar para escribir/imprimir lo que queramos. El problema... es que no me queda claro cual sería la salida estándar en un Arduino.

Por suerte, libc, permite re-definir a nuestro gusto cual va a ser la función que imprimirá cada uno de los caracteres en la salida estándar.
Eso significa, que podríamos hacer que siempre que llamase a la función "printf()", se escriba en un fichero, se imprima en una TFT, se retransmita por rf24, o.... se imprima en el puerto serie. Y es justo eso lo que utilizaremos.

Para re-definir cual será la función de escritura de 'char' de un printf(), utilizaremos "fdevopen()".

int mi_funcion_de_salida_en_puerto_serie( char c, FILE * ){
  Serial.write( c );
  return c;
}

void setup() {
  Serial.begin(115200);
  fdevopen( &mi_funcion_de_salida_en_puerto_serie, 0 );
  printf("Bienvenido a %s!!", "printf");
}

void loop(){}

(OJO, no acepta array de char, necesita recibir char, uno a uno).

Espero sea de ayuda.
JP

Justamente quería que abrieras otro hilo para hacerte esta pregunta?

Lo que explicas hasta ahora esta perfecto y acá viene el motivo real de mi comentario.

Si modificamos "libc" por la versión que contiene soporte para printf, sería posible usar float con printf?

De este modo

printf("Bienvenido a %f", 3.45);

Podría ser más "genérico" el uso de printf si le adjuntáramos cualquier objeto que herede de Print (la base de básicamente todas las librerías de Arduino donde se pueda hacer print).

Aunque veo que la firma de la función debe ser int(char, FILE*); si tan solo hubiera forma de redefinir FILE a cualquier objeto Print (¿tiene sentido intentarlo?), así una sola función se volvería compatible con Serial, Wire, File (librería SD), LiquidCrystal, etc.
¿O será que no hay más remedio que definir una función para cada flujo de salida?

Puff....
No había visto ese comportamiento extraño con los float/double.

surbyte:
Si modificamos "libc" por la versión que contiene soporte para printf, sería posible usar float con printf?

Seguiré buscando una solución. Como dije, soy nuevo en Arduino y he tenido que investigar de cero. Pero parece que he encontrado algo.
Corregirme si digo una barbaridad.

Al parece la mayoría de los Arduinos carecen de FPU (Floating Ppoint Unit) y todos los cálculos float/double se hacen por software.
En el código fuente de los firmware puedo encontrar cosas como estas:

File: hardware/arduino/avr/bootloaders/stk500v2/Makefile
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt

Según parece, se está definiendo deliberadamente unas "printf limitadas" para los Arduinos que carecen de FPU.

Estas placas parecen que tienen FPU:

  • Teensy 3.5
  • LilyPad

O las placas con que usan estos microcontroladores:

  • atmegaXXu2 (atmega32u4)
  • caterina
  • stk500v2
  • stm32f4

Aquí podéis encontrar otras placas que tienen FPU. Dentro del listado buscar la palabra FPU)
https://os.mbed.com/platforms/?form-factor=5

Yo solo tengo unos cuantos Arduino Pro Mini 5v...
Si alguien tiene alguna con FPU, por favor, comenten!
Gracias!

Si todo eso lo se.
Incluso he encontrado alguien que modifica el menú del IDE para justamente usar estos comandos para el averdude y entonces si lo hace pero no logré hacerlo funcionar.
Lean este link no sprintf float formatting... come back five year. Intenté pero no puede modificar mi archivo boards.txt para que figure la modificación propuesta.

Lo que huzo para enviar datos al puerto serie es Serial.Write directamente, me va de maravilla.