Ich denke, es ist eine schlechte Sache, ein Mikrocontroller-basiertes Projekt mit zu debuggen printf()
.
Ich kann verstehen, dass Sie keinen vordefinierten Ort für die Ausgabe haben und dass dieser wertvolle Stifte verbrauchen könnte. Gleichzeitig habe ich gesehen, dass Leute einen UART-TX-Pin für die Ausgabe an das IDE-Terminal mit einem benutzerdefinierten DEBUG_PRINT()
Makro verwenden.
printf
natürlich den gesamten Code verwenden, der zur Implementierung benötigt wird,printf
wird er mit der ausführbaren Datei verknüpft. Aber das liegt daran, dass der Code es verwendet hat, nicht an der Kopfzeile.Antworten:
Ich kann mit ein paar Nachteilen der Verwendung von printf () kommen. Denken Sie daran, dass "eingebettetes System" von einigen hundert Byte Programmspeicher bis hin zu einem vollwertigen QNX-RTOS-System für den Rack-Einbau mit Gigabyte RAM und Terabyte nichtflüchtigem Speicher reichen kann.
Zum Senden der Daten ist ein Ort erforderlich. Vielleicht haben Sie bereits einen Debug- oder Programmierport auf dem System, vielleicht auch nicht. Wenn Sie dies nicht tun (oder derjenige, den Sie haben, funktioniert nicht), ist es nicht sehr praktisch.
Es ist keine einfache Funktion in allen Kontexten. Dies kann eine große Sache sein, wenn Sie einen Mikrocontroller mit nur wenigen KB Arbeitsspeicher haben, da das Verknüpfen in printf möglicherweise 4 KB allein aufzehrt. Wenn Sie einen 32K- oder 256K-Mikrocontroller haben, ist dies wahrscheinlich kein Problem, geschweige denn, wenn Sie über ein großes Embedded-System verfügen.
Das Auffinden bestimmter Probleme im Zusammenhang mit der Speicherzuweisung oder Interrupts ist wenig oder gar nicht sinnvoll und kann das Verhalten des Programms ändern, wenn Anweisungen enthalten sind oder nicht.
Es ist ziemlich nutzlos für den Umgang mit zeitkritischen Sachen. Mit einem Logikanalysator und einem Oszilloskop oder einem Protokollanalysator oder sogar einem Simulator sind Sie besser dran.
Wenn Sie ein großes Programm haben und viele Male neu kompilieren müssen, während Sie printf-Anweisungen ändern, können Sie viel Zeit verschwenden.
Wofür es gut ist - es ist eine schnelle Möglichkeit, Daten auf eine vorformatierte Weise auszugeben, mit der jeder C-Programmierer die Null-Lernkurve zu verwenden weiß. Wenn Sie eine Matrix für den Kalman-Filter ausspucken müssen, den Sie debuggen, ist es möglicherweise hilfreich, sie in einem Format auszuspucken, das MATLAB einlesen kann. Dies ist sicherlich besser, als die RAM-Speicherorte einzeln in einem Debugger oder Emulator zu betrachten .
Ich denke nicht, dass es ein nutzloser Pfeil im Köcher ist, aber er sollte sparsam zusammen mit GDB oder anderen Debuggern, Emulatoren, Logikanalysatoren, Oszilloskopen, statischen Code-Analyse-Tools, Code-Coverage-Tools usw. verwendet werden.
quelle
printf()
Implementierungen sind nicht thread-sicher (dh nicht re-entrant), was kein Deal Killer ist, aber etwas, das Sie beachten sollten, wenn Sie es in einer Multithread-Umgebung verwenden.Zusätzlich zu einigen anderen guten Antworten kann das Senden von Daten an einen Port mit seriellen Baudraten in Bezug auf Ihre Schleifenzeit geradezu langsam sein und sich auf die weitere Funktionsweise Ihres Programms auswirken (ebenso wie JEDES Debugging Prozess).
Wie andere Leute Ihnen gesagt haben, ist die Verwendung dieser Technik nichts "Schlechtes", aber sie hat, wie viele andere Debug-Techniken, ihre Grenzen. Solange Sie diese Einschränkungen kennen und bewältigen können, ist es äußerst praktisch, Ihnen dabei zu helfen, Ihren Code richtig zu machen.
Eingebettete Systeme haben eine gewisse Undurchsichtigkeit, die das Debuggen im Allgemeinen zu einem Problem macht.
quelle
Bei der Verwendung
printf
auf einem Mikrocontroller treten hauptsächlich zwei Probleme auf.Erstens kann es schwierig sein, den Ausgang zum richtigen Port zu leiten. Nicht immer. Einige Plattformen sind jedoch schwieriger als andere. Einige der Konfigurationsdateien sind möglicherweise schlecht dokumentiert, und es sind möglicherweise umfangreiche Experimente erforderlich.
Der zweite ist die Erinnerung. Eine vollständige
printf
Bibliothek kann BIG sein. Manchmal benötigen Sie jedoch nicht alle Formatspezifizierer, und es können spezielle Versionen verfügbar sein. Zum Beispiel enthältstdio.h
die von AVR bereitgestellte drei verschiedeneprintf
von unterschiedlicher Größe und Funktionalität.Ich hatte eine Instanz, in der keine Bibliothek verfügbar war, und ich hatte nur minimalen Speicher. Ich hatte also keine andere Wahl, als ein benutzerdefiniertes Makro zu verwenden. Die Verwendung von
printf
oder nicht ist jedoch eine der Möglichkeiten, die Ihren Anforderungen entsprechen.quelle
Um hinzuzufügen, was Spehro Pefhany über "Timing-sensitive Sachen" sagte: Nehmen wir ein Beispiel. Angenommen, Sie haben ein Gyroskop, mit dem Ihr eingebettetes System 1.000 Messungen pro Sekunde durchführt. Sie möchten diese Messungen debuggen und müssen sie daher ausdrucken. Problem: Beim Ausdrucken ist das System zu beschäftigt, um 1.000 Messungen pro Sekunde zu lesen. Dadurch läuft der Puffer des Gyroskops über, und beschädigte Daten werden gelesen (und gedruckt). Wenn Sie also die Daten drucken, haben Sie sie beschädigt und glauben, dass beim Lesen der Daten ein Fehler aufgetreten ist, obwohl dies möglicherweise tatsächlich nicht der Fall ist. Ein sogenannter Heisenbug.
quelle
Der Hauptgrund für das Nicht-Debuggen mit printf () ist, dass es normalerweise ineffizient, unangemessen und unnötig ist.
Ineffizient: printf () und kin verbrauchen viel Flash und RAM im Vergleich zu dem, was auf einem kleinen Mikrocontroller verfügbar ist, aber die größere Ineffizienz liegt beim eigentlichen Debuggen. Das Ändern des Protokolls erfordert das Neukompilieren und Neuprogrammieren des Ziels, wodurch der Prozess verlangsamt wird. Es wird auch ein UART verbraucht, mit dem Sie sonst nützliche Arbeit leisten könnten.
Unangemessen: Es gibt nur so viele Details, die Sie über eine serielle Verbindung ausgeben können. Wenn das Programm hängt, wissen Sie nicht genau, wo, nur die letzte Ausgabe, die abgeschlossen wurde.
Unnötig: Viele Mikrocontroller können remote getestet werden. JTAG- oder proprietäre Protokolle können verwendet werden, um den Prozessor anzuhalten, Register und RAM zu überprüfen und sogar den Status des aktiven Prozessors zu ändern, ohne ihn neu kompilieren zu müssen. Aus diesem Grund sind Debugger im Allgemeinen eine bessere Methode zum Debuggen als Ausdrucke, selbst auf einem PC mit viel Speicherplatz und Leistung.
Es ist bedauerlich, dass die häufigste Mikrocontroller-Plattform für Neulinge, Arduino, keinen Debugger hat. Der AVR unterstützt Remote-Debugging, aber das DebugWIRE-Protokoll von Atmel ist proprietär und nicht dokumentiert. Sie können ein offizielles Entwickler-Board verwenden, um mit GDB zu debuggen, aber wenn Sie das haben, sind Sie wahrscheinlich nicht mehr zu besorgt über Arduino.
quelle
printf () funktioniert nicht alleine. Es ruft viele andere Funktionen auf, und wenn Sie nur über wenig Stapelspeicher verfügen, können Sie diese möglicherweise überhaupt nicht zum Debuggen von Problemen verwenden, die nahe an Ihrem Stapelspeicherlimit liegen. Je nach Compiler und Mikrocontroller wird die Formatzeichenfolge möglicherweise auch im Speicher abgelegt, anstatt von Flash aus darauf zu verweisen. Dies kann sich erheblich summieren, wenn Sie Ihren Code mit printf-Anweisungen aufpeppen. Dies ist ein großes Problem in der Arduino-Umgebung - Anfänger, die Dutzende oder Hunderte von printf-Anweisungen verwenden, stoßen plötzlich auf scheinbar zufällige Probleme, weil sie ihren Haufen mit ihrem Stapel überschreiben.
quelle
Selbst wenn man Daten auf eine Art Protokollierungskonsole ausspucken möchte, ist die
printf
Funktion im Allgemeinen keine sehr gute Methode, da sie den übergebenen Format-String untersuchen und zur Laufzeit analysieren muss. Selbst wenn der Code niemals einen anderen Formatbezeichner als verwendet%04X
, muss der Controller im Allgemeinen den gesamten Code enthalten, der zum Parsen beliebiger Formatzeichenfolgen erforderlich wäre. Abhängig von dem genauen Controller, den Sie verwenden, kann es wesentlich effizienter sein, Code wie den folgenden zu verwenden:Bei einigen PIC-Mikrocontrollern werden
log_hexi32(l)
wahrscheinlich 9 Befehle benötigt und 17 (wennl
sich in der zweiten Bank befindet), währendlog_hexi32p(&l)
2 benötigt werden. Dielog_hexi32p
Funktion selbst kann so geschrieben werden, dass sie ungefähr 14 Befehle lang ist, sodass sie sich bei zweimaligem Aufruf bezahlt macht .quelle
Ein Punkt, den keine der anderen Antworten erwähnt hat: In einem einfachen Mikro (IE gibt es nur die main () - Schleife und möglicherweise ein paar ISRs, die zu einem beliebigen Zeitpunkt ausgeführt werden, kein Multi-Thread-Betriebssystem), wenn es abstürzt / stoppt / abruft In einer Schleife stecken, wird Ihre Druckfunktion einfach nicht passieren .
Außerdem haben die Leute gesagt, dass "nicht printf verwenden" oder "stdio.h viel Platz beansprucht", aber nicht viele Alternativen angegeben - embedded.kyle nennt vereinfachte Alternativen, und genau das sollten Sie wahrscheinlich auch sein Selbstverständlich auf einem einfachen eingebetteten System. Eine grundlegende Routine zum Herausspritzen einiger Zeichen aus dem UART könnte ein paar Byte Code sein.
quelle