Eu acho que é uma coisa ruim tentar depurar um projeto baseado em microcontrolador usando printf()
.
Entendo que você não tem um local predefinido para saída e que isso pode consumir pinos valiosos. Ao mesmo tempo, vi pessoas consumindo um pino UART TX para enviar para o terminal IDE com uma DEBUG_PRINT()
macro personalizada .
printf
, é claro, todo o código necessário para implementarprintf
será vinculado ao executável. Mas isso é porque o código o usou, não por causa do cabeçalho.Respostas:
Posso apresentar algumas desvantagens do uso de printf (). Lembre-se de que "sistema incorporado" pode variar de algo com algumas centenas de bytes de memória de programa a um sistema completo acionado por QNX RTOS montado em rack com gigabytes de RAM e terabytes de memória não volátil.
Requer algum lugar para enviar os dados. Talvez você já tenha uma porta de depuração ou programação no sistema, talvez não. Se você não o fizer (ou o que você possui não estiver funcionando), não será muito útil.
Não é uma função leve em todos os contextos. Isso pode ser um grande problema se você tiver um microcontrolador com apenas alguns K de memória, porque vincular no printf pode consumir 4K por si só. Se você tem um microcontrolador de 32K ou 256K, provavelmente não é um problema, muito menos se você tiver um grande sistema incorporado.
É pouco ou nenhum uso para encontrar certos tipos de problemas relacionados à alocação ou interrupções de memória e pode alterar o comportamento do programa quando as instruções são incluídas ou não.
É bastante inútil para lidar com coisas sensíveis ao tempo. Você se sairia melhor com um analisador lógico e um osciloscópio ou um analisador de protocolo ou mesmo um simulador.
Se você tem um programa grande e precisa recompilar muitas vezes, à medida que muda as instruções printf e as altera, você pode perder muito tempo.
Para que serve: é uma maneira rápida de gerar dados de forma pré-formatada, para que todo programador C saiba como usar a curva de aprendizado zero. Se você precisar cuspir uma matriz para o filtro Kalman que está depurando, pode ser bom cuspi-lo em um formato que o MATLAB possa ler. Certamente melhor do que procurar os locais de RAM, um de cada vez, em um depurador ou emulador .
Eu não acho que seja uma flecha inútil na aljava, mas deve ser usada com moderação, juntamente com o gdb ou outros depuradores, emuladores, analisadores lógicos, osciloscópios, ferramentas de análise de código estático, ferramentas de cobertura de código e assim por diante.
fonte
printf()
implementações não é segura para threads (ou seja, não re-participante), o que não é um bom negócio, mas é algo a ter em mente ao usá-la em um ambiente multithread.Além de outras respostas, o ato de enviar dados para uma porta a taxas de transmissão serial pode ser simplesmente lento com relação ao tempo de loop e afetar a maneira como o restante do programa funciona (como QUALQUER depuração processo).
Como outras pessoas têm lhe dito, não há nada de "ruim" em usar essa técnica, mas, como muitas outras técnicas de depuração, tem suas limitações. Desde que você conheça e consiga lidar com essas limitações, pode ser um recurso extremamente conveniente para ajudá-lo a corrigir seu código.
Os sistemas embarcados têm uma certa opacidade que, em geral, torna a depuração um pouco problemática.
fonte
Existem dois problemas principais que você encontrará ao tentar usar
printf
em um microcontrolador.Primeiro, pode ser difícil canalizar a saída para a porta correta. Nem sempre. Mas algumas plataformas são mais difíceis que outras. Alguns dos arquivos de configuração podem ser pouco documentados e muitas experiências podem ser necessárias.
O segundo é a memória. Uma
printf
biblioteca completa pode ser GRANDE. Às vezes, você não precisa de todos os especificadores de formato, e versões especializadas podem estar disponíveis. Por exemplo, ostdio.h
fornecido pelo AVR contém três diferentesprintf
tamanhos e funcionalidades.Eu tive um exemplo em que nenhuma biblioteca estava disponível e eu tinha memória mínima. Portanto, não tive escolha a não ser usar uma macro personalizada. Mas o uso de
printf
ou não é realmente um dos que atenderá às suas necessidades.fonte
Para adicionar o que Spehro Pefhany estava dizendo sobre "coisas sensíveis ao tempo": vamos dar um exemplo. Digamos que você tenha um giroscópio a partir do qual o seu sistema embarcado está fazendo 1.000 medições por segundo. Você deseja depurar essas medidas, portanto, é necessário imprimi-las. Problema: imprimi-los faz com que o sistema fique muito ocupado para ler 1.000 medições por segundo, o que faz com que o buffer do giroscópio transborde, o que faz com que dados corrompidos sejam lidos (e impressos). E assim, ao imprimir os dados, você os corrompeu, fazendo pensar que há um erro na leitura dos dados, quando talvez não haja. Um chamado heisenbug.
fonte
A razão maior para não depurar com printf () é que geralmente é ineficiente, inadequado e desnecessário.
Ineficiente: printf () e parentes usam muito flash e RAM em relação ao que está disponível em um pequeno microcontrolador, mas a maior ineficiência está na depuração real. Alterar o que está sendo registrado requer recompilar e reprogramar o destino, o que atrasa o processo. Ele também usa um UART que você poderia estar usando para realizar um trabalho útil.
Inadequado: há tantos detalhes que você pode enviar através de um link serial. Se o programa travar, você não sabe exatamente onde, apenas a última saída concluída.
Desnecessário: Muitos microcontroladores podem ser depurados remotamente. JTAG ou protocolos proprietários podem ser usados para pausar o processador, espiar registros e RAM e até alterar o estado do processador em execução sem precisar recompilar. É por isso que os depuradores são geralmente uma maneira melhor de depurar do que as instruções de impressão, mesmo em um PC com muito espaço e energia.
É lamentável que a plataforma de microcontrolador mais comum para iniciantes, o Arduino, não tenha um depurador. O AVR suporta depuração remota, mas o protocolo debugWIRE da Atmel é proprietário e não documentado. Você pode usar uma placa de desenvolvedor oficial para depurar com o GDB, mas se tiver, provavelmente não está mais preocupado com o Arduino.
fonte
printf () não funciona por si só. Ele chama muitas outras funções e, se você tiver pouco espaço na pilha, poderá não ser capaz de usá-lo para depurar problemas próximos ao seu limite de pilha. Dependendo do compilador e do microcontrolador, a string de formato também pode ser colocada na memória, em vez de referenciada no flash. Isso pode aumentar significativamente se você apimentar seu código com instruções printf. Esse é um grande problema no ambiente do Arduino - iniciantes que usam dezenas ou centenas de instruções printf repentinamente se deparam com problemas aparentemente aleatórios porque estão substituindo sua pilha pela pilha.
fonte
Mesmo se alguém quiser cuspir dados em alguma forma de console de registro, a
printf
função geralmente não é uma maneira muito boa de fazer isso, pois ela precisa examinar a sequência de formato passada e analisá-la em tempo de execução; mesmo que o código nunca use outro especificador de formato%04X
, o controlador geralmente precisará incluir todo o código necessário para analisar seqüências de formato arbitrárias. Dependendo do controlador exato em uso, pode ser muito mais eficiente usar código como:Em alguns microcontroladores PIC,
log_hexi32(l)
provavelmente levaria 9 instruções e poderia levar 17 (sel
estiver no segundo banco), enquantolog_hexi32p(&l)
levaria 2. Alog_hexi32p
função em si poderia ser escrita para ter cerca de 14 instruções, de modo que se pagaria se chamada duas vezes .fonte
Um ponto que nenhuma das outras respostas mencionou: Em um micro básico (IE, há apenas o loop main () e talvez alguns ISRs em execução a qualquer momento, não um sistema operacional multi-threaded) se ele travar / parar / ficar preso em um loop, sua função de impressão simplesmente não acontecerá .
Além disso, as pessoas disseram "não use printf" ou "stdio.h ocupa muito espaço", mas não tem muita alternativa - o embedded.kyle faz menção a alternativas simplificadas, e esse é exatamente o tipo de coisa que você provavelmente deveria ser normalmente, em um sistema embarcado básico. Uma rotina básica para extrair alguns caracteres do UART pode ser alguns bytes de código.
fonte