Supongo que es malo intentar depurar un proyecto basado en microcontrolador usando printf()
.
Puedo entender que no tiene un lugar predefinido para la salida, y que podría consumir pines valiosos. Al mismo tiempo, he visto a personas consumir un pin UART TX para enviar al terminal IDE con una DEBUG_PRINT()
macro personalizada .
printf
, por supuesto, todo el código que se necesita para implementarprintf
se vincula al ejecutable. Pero eso es porque el código lo usó, no por el encabezado.Respuestas:
Puedo encontrar algunas desventajas de usar printf (). Tenga en cuenta que el "sistema integrado" puede variar desde algo con unos pocos cientos de bytes de memoria de programa a un sistema QNX RTOS montado en bastidor con gigabytes de RAM y terabytes de memoria no volátil.
Requiere un lugar para enviar los datos. Tal vez ya tenga un puerto de depuración o programación en el sistema, tal vez no. Si no lo hace (o el que tiene no funciona) no es muy útil.
No es una función ligera en todos los contextos. Esto podría ser un gran problema si tiene un microcontrolador con solo unos pocos K de memoria, porque el enlace en printf podría consumir 4K por sí mismo. Si tiene un microcontrolador de 32K o 256K, probablemente no sea un problema, y mucho menos si tiene un gran sistema integrado.
Es de poca o ninguna utilidad para encontrar ciertos tipos de problemas relacionados con la asignación de memoria o las interrupciones, y puede cambiar el comportamiento del programa cuando se incluyen o no declaraciones.
Es bastante inútil para lidiar con cosas sensibles al tiempo. Sería mejor con un analizador lógico y un osciloscopio o un analizador de protocolos, o incluso un simulador.
Si tiene un gran programa y tiene que volver a compilar muchas veces a medida que cambia las declaraciones de printf y las cambia, podría perder mucho tiempo.
Para qué es bueno, es una forma rápida de generar datos de forma preformateada que todo programador de C sabe usar: curva de aprendizaje cero. Si necesita escupir una matriz para el filtro de Kalman que está depurando, puede ser bueno escupirlo en un formato que MATLAB pueda leer. Ciertamente mejor que mirar las ubicaciones de RAM una a la vez en un depurador o emulador .
No creo que sea una flecha inútil en el carcaj, pero debe usarse con moderación, junto con gdb u otros depuradores, emuladores, analizadores lógicos, osciloscopios, herramientas de análisis de código estático, herramientas de cobertura de código, etc.
fuente
printf()
implementaciones no son seguras para subprocesos (es decir, no son reentrantes), lo que no es un factor decisivo, sino algo a tener en cuenta al usarlo en un entorno de subprocesos múltiples.Además de algunas otras buenas respuestas, el acto de enviar datos a un puerto a velocidades de transmisión en serie puede ser francamente lento con respecto a su tiempo de bucle y tener un impacto en la forma en que funciona el resto del programa (al igual que CUALQUIER depuración proceso).
Como otras personas le han estado diciendo, no hay nada "malo" en usar esta técnica, pero tiene, como muchas otras técnicas de depuración, sus limitaciones. Siempre que sepa y pueda lidiar con estas limitaciones, puede ser una ayuda extremadamente conveniente ayudarlo a obtener su código correcto.
Los sistemas integrados tienen una cierta opacidad que, en general, hace que la depuración sea un problema.
fuente
Hay dos problemas principales con los que se encontrará tratando de usar
printf
en un microcontrolador.Primero, puede ser una molestia canalizar la salida al puerto correcto. No siempre. Pero algunas plataformas son más difíciles que otras. Algunos de los archivos de configuración pueden estar mal documentados y puede ser necesaria mucha experimentación.
El segundo es la memoria. Una
printf
biblioteca completa puede ser GRANDE. Sin embargo, a veces no necesita todos los especificadores de formato y pueden estar disponibles versiones especializadas. Por ejemplo, elstdio.h
proporcionado por AVR contiene tres diferentesprintf
de diferentes tamaños y funcionalidades.Tuve una instancia en la que no había una biblioteca disponible y tenía una memoria mínima. Así que no tuve más remedio que usar una macro personalizada. Pero el uso de
printf
o no es realmente uno de los que se ajustará a sus requisitos.fuente
Para agregar a lo que Spehro Pefhany estaba diciendo sobre "cosas sensibles al tiempo": tomemos un ejemplo. Digamos que tiene un giroscopio desde el cual su sistema integrado está tomando 1,000 mediciones por segundo. Desea depurar estas medidas, por lo que debe imprimirlas. Problema: imprimirlos hace que el sistema esté demasiado ocupado para leer 1,000 mediciones por segundo, lo que hace que el búfer del giroscopio se desborde, lo que hace que los datos corruptos se lean (e impriman). Entonces, al imprimir los datos, los ha corrompido, haciéndole pensar que hay un error en la lectura de los datos cuando tal vez en realidad no lo hay. Un llamado heisenbug.
fuente
La razón más importante para no depurar con printf () es que generalmente es ineficiente, inadecuado e innecesario.
Ineficiente: printf () y sus familiares usan mucho flash y RAM en relación con lo que está disponible en un microcontrolador pequeño, pero la mayor ineficiencia está en la depuración real. Cambiar lo que se está registrando requiere volver a compilar y reprogramar el objetivo, lo que ralentiza el proceso. También usa un UART que de otro modo podría estar usando para hacer un trabajo útil.
Inadecuado: solo hay tantos detalles que puede generar a través de un enlace en serie. Si el programa se cuelga, no sabes exactamente dónde, solo la última salida que se completó.
Innecesario: muchos microcontroladores se pueden depurar de forma remota. Se pueden usar protocolos JTAG o patentados para pausar el procesador, echar un vistazo a los registros y la RAM, e incluso alterar el estado del procesador en ejecución sin tener que volver a compilar. Esta es la razón por la cual los depuradores son generalmente una mejor manera de depurar que imprimir declaraciones, incluso en una PC con toneladas de espacio y potencia.
Es lamentable que la plataforma de microcontroladores más común para los novatos, Arduino, no tenga un depurador. El AVR admite la depuración remota, pero el protocolo debugWIRE de Atmel es propietario e indocumentado. Puede usar una placa de desarrollo oficial para depurar con GDB, pero si lo tiene, probablemente ya no esté demasiado preocupado por Arduino.
fuente
printf () no funciona por sí solo. Llama a muchas otras funciones, y si tiene poco espacio de pila, es posible que no pueda usarlo para depurar problemas cercanos a su límite de pila. Dependiendo del compilador y el microcontrolador, la cadena de formato también se puede colocar en la memoria, en lugar de hacer referencia desde flash. Esto puede agregarse significativamente si sazona su código con declaraciones printf. Este es un gran problema en el entorno de Arduino: los principiantes que usan docenas o cientos de declaraciones printf de repente se encuentran con problemas aparentemente aleatorios porque están sobrescribiendo su montón con su pila.
fuente
Incluso si uno quiere escupir datos en alguna forma de consola de registro, la
printf
función generalmente no es una muy buena forma de hacerlo, ya que necesita examinar la cadena de formato pasada y analizarla en tiempo de ejecución; incluso si el código nunca usa otro especificador de formato que no sea%04X
, el controlador generalmente necesitará incluir todo el código que se requeriría para analizar cadenas de formato arbitrario. Dependiendo del controlador exacto que uno esté usando, puede ser mucho más eficiente usar código como:En algunos microcontroladores PIC,
log_hexi32(l)
probablemente tomaría 9 instrucciones y podría tomar 17 (sil
está en el segundo banco), mientraslog_hexi32p(&l)
que tomaría 2. Lalog_hexi32p
función en sí podría escribirse para tener aproximadamente 14 instrucciones de largo, por lo que se pagaría sola si se llama dos veces .fuente
Un punto que ninguna de las otras respuestas ha mencionado: en un micro básico (IE solo hay el bucle main () y quizás un par de ISR en ejecución en cualquier momento, no un sistema operativo de subprocesos múltiples) si se bloquea / detiene / obtiene atrapado en un bucle, su función de impresión simplemente no sucederá .
Además, la gente ha dicho "no use printf" o "stdio.h ocupa mucho espacio", pero no tiene mucha alternativa: embedded.kyle menciona alternativas simplificadas, y ese es exactamente el tipo de cosas que probablemente debería ser haciendo, por supuesto, en un sistema embebido básico. Una rutina básica para arrojar algunos caracteres fuera del UART podría ser unos pocos bytes de código.
fuente