30 votos

¿Cómo se utiliza la función printf en el STM32?

Estoy intentando averiguar cómo utilizar la función printf para imprimir en el puerto serie.

Mi configuración actual es STM32CubeMX código generado y SystemWorkbench32 con el Tarjeta de descubrimiento STM32F407 .

Veo en stdio.h que el prototipo printf está definido como

int _EXFUN(printf, (const char *__restrict, ...)
               _ATTRIBUTE ((__format__ (__printf__, 1, 2))));

¿Qué significa? ¿Dónde se encuentra exactamente la definición de esta función? ¿Cuál sería el punto general de averiguar cómo utilizar este tipo de función a la salida?

27voto

Wiesław Herr Puntos 405

He conseguido que el primer método de esta página funcione en mi STM32F072.

http://www.openstm32.org/forumthread1055

Como se dice allí,

La forma en que conseguí que printf (y todas las demás funciones stdio orientadas a la consola) funcionara fue creando implementaciones personalizadas de las funciones de E/S de bajo nivel como _read() y _write() .

La biblioteca C de GCC hace llamadas a las siguientes funciones para realizar E/S de bajo nivel:

int _read(int file, char *data, int len)
int _write(int file, char *data, int len)
int _close(int file)
int _lseek(int file, int ptr, int dir)
int _fstat(int file, struct stat *st)
int _isatty(int file)

Estas funciones se implementan dentro de la biblioteca C de GCC como rutinas stub con enlace "débil". Si una declaración de cualquiera de las funciones anteriores aparece en su propio código, su rutina sustituta anulará la declaración en la biblioteca y se utilizará en lugar de la rutina por defecto (no funcional).

He utilizado el STM32CubeMX para configurar la USART1 ( huart1 ) como puerto serie. Como sólo quería printf() Sólo tenía que rellenar el _write() lo que hice de la siguiente manera. Esto se encuentra convencionalmente en syscalls.c .

#include  <errno.h>
#include  <sys/unistd.h> // STDOUT_FILENO, STDERR_FILENO

int _write(int file, char *data, int len)
{
   if ((file != STDOUT_FILENO) && (file != STDERR_FILENO))
   {
      errno = EBADF;
      return -1;
   }

   // arbitrary timeout 1000
   HAL_StatusTypeDef status =
      HAL_UART_Transmit(&huart1, (uint8_t*)data, len, 1000);

   // return # of bytes written - as best we can tell
   return (status == HAL_OK ? len : 0);
}

5voto

Ashish Awaghad Puntos 116

La respuesta de @AdamHaun es todo lo que necesitas, con sprintf() es fácil crear una cadena y luego enviarla. Pero si realmente quieres un printf() de su propia función, entonces Funciones con argumentos variables (va_list) es el camino.

Con va_list una función de impresión personalizada tiene el siguiente aspecto:

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

void vprint(const char *fmt, va_list argp)
{
    char string[200];
    if(0 < vsprintf(string,fmt,argp)) // build string
    {
        HAL_UART_Transmit(&huart1, (uint8_t*)string, strlen(string), 0xffffff); // send message via UART
    }
}

void my_printf(const char *fmt, ...) // custom printf() function
{
    va_list argp;
    va_start(argp, fmt);
    vprint(fmt, argp);
    va_end(argp);
}

Ejemplo de uso:

uint16_t year = 2015;
uint8_t month = 12;
uint8_t day   = 18;
char* date = "date";

// "Today's date: 2015-12-18"
my_printf("Today's %s: %d-%d-%d\r\n", date, year, month, day);

Tenga en cuenta que si bien esta solución le da una función conveniente para utilizar, pero es más lento que el envío de datos en bruto o el uso de incluso sprintf() . Con altas tasas de datos creo que no será suficiente.


Otra opción, y probablemente mejor, es utilizar ST-Link, depurador SWD junto con ST-Link Utility. Y utilizar Printf a través del visor SWO Aquí está el manual de Utilidad ST-Link La parte relevante comienza en la página 31.

El visor de Printf vía SWO muestra los datos de printf enviados desde el objetivo a través de SWO. Permite mostrar alguna información útil sobre el firmware en ejecución.

4voto

_EXFUN es una macro, que probablemente contiene algunas directivas interesantes que indican al compilador que debe comprobar que la cadena de formato es compatible con printf y asegurar que los argumentos de printf coinciden con la cadena de formato.

Para aprender a usar printf, sugiero el página de manual y un poco más de búsqueda en Google. Escribe algunos programas sencillos en C que utilicen printf y ejecútalos en tu ordenador antes de intentar pasar a utilizarlo en el micro.

La pregunta interesante será "¿dónde va el texto impreso?". En un sistema tipo Unix, va a la "salida estándar", pero un microcontrolador no tiene tal cosa. Las librerías de depuración CMSIS pueden enviar el texto impreso al puerto de depuración del brazo, es decir, a tu sesión de gdb u openocd, pero no tengo ni idea de lo que hará SystemWorkbench32.

Si no estás trabajando en un depurador, puede tener más sentido usar sprintf para formatear las cadenas que quieres imprimir y luego enviar esas cadenas a través de un puerto serie o a cualquier pantalla que puedas tener conectada.

Cuidado: printf y su código relacionado son muy grandes. Eso probablemente no importa mucho en un 32F407, pero es un verdadero problema en dispositivos con poca flash.

4voto

RAVI Puntos 25

Si desea un enfoque diferente y no quiere sobrescribir funciones o declarar las suyas propias, puede utilizar simplemente snprintf para archivar el mismo objetivo. Pero no es tan elegante.

char buf[100];
snprintf(buf, 100, "%X %X", val1, val2);
HAL_UART_Transmit(&huart1, (uint8_t*)buf, strlen(buf), 1000);

2voto

Al pacino Puntos 415

Printf() es (normalmente) parte de la biblioteca estándar de C. Si su versión de la biblioteca viene con el código fuente, puede encontrar una implementación allí.

Probablemente sería más fácil utilizar sprintf() para generar una cadena, y luego utilizar otra función para enviar la cadena a través del puerto serie. De esta manera todo el formato difícil se hace por ti y no tienes que hackear la biblioteca estándar.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X