Tipps Tricks und kleine Helferlein
Worum geht's?
[Bearbeiten]Solange alles wie gewünscht funktioniert, verläuft die Entwicklung von Programmen für den Mikrocontroller nicht sehr viel anders, als die Entwicklung von Programmen für den PC. Sobald die Dinge nicht mehr ganz so wie gewollt ablaufen, zeigen sich deutliche Unterschiede.
Ohne den Einsatz spezialisierter Zusatzhardware steht die „Standardlösung“ Debugger nicht zur Verfügung. Selbst mit entsprechender Ausrüstung sind die Möglichkeiten begrenzt. Ohne Kontrolle der CPU ablaufende Vorgänge, wie das Voranschreiten von Timern lassen sich selbst mit entsprechender Debug-Hardware weder überwachen noch kontrollieren.
In diesem Kapitel wird es darum gehen, eine Reihe von Tipps und Tricks vorzustellen, die falls die Dinge Mal nicht ganz so sollten, wie gedacht, dabei helfen können das Problem zu finden.
Die folgenden Dinge kannst Du in diesem Kapitel lernen:
- Log Daten mit dem Mikrocontroller über die serielle Schnittstelle versenden
- über die serielle Schnittstelle versendete Daten mit dem PC entgegen nehmen
- den Inhalt generierter Programme auflisten
Logging
[Bearbeiten]Wie im vorangegangenen Kapitel angesprochen, verfügt die AVR Libc zwar über die nötige Infrastruktur, um Ausgaben mit der printf() Familie von Funktionen durchzuführen. Standardmäßig stehen allerdings keine Dateihandles bereit, an die Ausgaben auch tatsächlich geschickt werden können.
Um den Fortschritt eines Programms, das auf dem Mikrocontroller läuft zu protokollieren, kann es nützlich sein zumindest eine Ausgabemöglichkeit für Zeichenketten zur Verfügung zu haben. Eine Möglichkeit, die sich auch ohne externe Beschaltung weiterer Bauteile, wie LCD Display zu realisieren, bietet die serielle Schnittstelle. Über die serielle Schnittstelle versandt, können die zu protokollierenden Daten dann mit einem geeigneten Terminalprogramm[1] am PC empfangen und ausgegeben werden.
Experimentier-Boards mit integriertem RS-232 zu USB Konverter stellen bereits die passende Anschlussmöglichkeit zur Verfügung. Ein RS-232 zu USB Konverterkabel kann andernfalls für Abhilfe sorgen.
serielle Schnittstelle
[Bearbeiten]Eine ausführliche Untersuchung aller Möglichkeiten, die für die Bedienung der seriellen Schnittstelle verantwortlich Funktionseinheit des Mikrocontrollers zur Verfügung stellt, ist einem späteren Kapitel vorbehalten. In diesem Abschnitt wird es aus diesem Grund nur um die Aspekte gehen, deren Verständnis nötig ist, um die serielle Schnittstelle zum Protokollieren von Ausgaben zu verwenden.
Damit die Kommunikation über die serielle Schnittstelle funktioniert, ist es erforderlich dafür zu sorgen, dass zwei für den Betrieb wichtige Parameter auf dem Mikrocontroller und im Terminalprogramm auf dem PC übereinstimmen.
Eine Quelldatei, die sich um die Initialisierung der seriellen Schnittstelle auf dem Mikrocontroller kümmert, findest Du hier. Um sie in einem Programm zu verwenden, musst sie sowohl übersetzt, als auch mit den restlichen Komponenten des Programms gelinkt werden. Wenn Du das Makefile aus dem Kapitel Arbeiten mit make verwendest, musst Du der Variable SOURCES den Namen der Quelldatei log.c hinzufügen.
log.c
[Bearbeiten]#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "log.h"
#define BAUDRATE 57600L
#define SERIAL_FORMAT_8N1 0b00000110
#define sbi(port, bit) (port) |= (uint8_t) (1 << (bit))
#define cbi(port, bit) (port) &= (uint8_t) ~(1 << (bit))
static int serial_put(char c, FILE *stream)
{
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = (uint8_t) c;
return c;
}
static FILE the_log = FDEV_SETUP_STREAM(serial_put, NULL, _FDEV_SETUP_WRITE);
FILE* log_init()
{
// baud rate
UBRR0H = 0;
UBRR0L = (uint8_t) (F_CPU / 4 / BAUDRATE - 1) / 2;
sbi(UCSR0A, U2X0); // double speed
UCSR0B |= _BV(TXEN0); // enable transmit
UCSR0C = SERIAL_FORMAT_8N1; // set frame format
return &the_log;
}
Die zugehörige Header Datei findest Du hier.
log.h
[Bearbeiten]#ifndef LOG_H
#define LOG_H
#include <stdio.h>
FILE* log_init(void);
#endif // LOG_H
Sie stellt nur eine Funktion log_init() zur Verfügung, die ein Dateihandle zurückliefert. Um dafür zu sorgen, dass printf() über die Standardausgabe ausgegebene Zeichenketten über die serielle Schnittstelle versendet werden, kann das von log_init() zurückgegebene Dateihandle an stdin zugewiesen werden.
Davon, dass alles wie gewünscht funktioniert, können wir uns mit einem kleinen Testprogramm überzeugen.
Quellcode
[Bearbeiten]#include <avr/io.h>
#include <util/delay.h>
# include "log.h"
// Forward Declarations
void setup(void);
void loop(void);
void setup()
{
stdout = log_init();
}
void loop()
{
printf("hello world\r\n");
_delay_ms(1000);
}
#ifndef ARDUINO
int main(void)
{
setup();
while(1)
loop();
}
#endif
Objekt- und Programmdateien inspizieren
[Bearbeiten]Hin und wieder kann es nützlich sein einen Blick in die vom Compiler generierten Dateien zu werfen. Sowohl das fertige Programm, als auch die Objektdateien, aus den es zusammen gelinkt wird, legt die avr-gcc Compiler Suite im ELF (executable and link format) Format ab.
Mit dem in der Compiler Suite enthaltenen Werkzeug avr-objdump kann der Inhalt von Dateien, die im ELF Format vorliegen inspiziert werden.
Kommandozeile
[Bearbeiten]Eine vollständige Liste aller verfügbaren Optionen erhälst Du, wenn Du avr-objdump mit der Option --help auf der Kommandozeile aufrufst. Wenn das Programm avr-objdump nicht im Suchpfad liegt, musst es mit dem vollen Pfadnamen aufgerufen werden. Wenn Du dem Vorschlag aus dem Kapitel Quickstart Linux gefolgt bist, und die Dateien der Arduino IDE vollständig in das Verzeichnis /opt kopiert hast, kannst Du den folgenden Befehl verwenden.
/opt/arduino-1.8.0/hardware/tools/avr/bin/avr-objdump --help
Makefile
[Bearbeiten]Das Makefile aus dem Kaptiel Arbeiten mit make enthält zwei Regeln, die es erlauben eine Reihe von Informationen aus dem Inhalt von Objektdateien und daraus erstellten Programmdateien aufzulisten. Mit der Hilfe der Dokumentation aus dem vorangegangenen Abschnitt kannst Du die verwendeten Schalter an Deine Bedürfnisse anpassen, wenn Dir die getroffene Vorauswahl nicht gefällt.
%.lst: %.elf
$(OBJDUMP) -h -S -t -C $< > $@
%.lst: %.o
$(OBJDUMP) -h -S -t -C $< > $@
Um den Inhalt der aus der Datei quelle.c generierten Objektdatei aufzulisten kann das Makefile mit dem folgenden Aufruf gestartet werden.
make quelle.lst
Eine Auflistung des zugehörigen Inhalts findet sich dann in der Datei quelle.lst. Analog kann der Inhalt der für das Projekt project generierten Programmdatei durch folgenden Aufruf von make in der Datei project.lst ausgegeben werden.
make project.lst
Rückschau und Ausblick
[Bearbeiten]TODO
Fußnoten
[Bearbeiten]- ↑ das Programm, das ich für diesen Zweck auf meinem PC verwende trägt den Namen gtkterm