XML Schema Teil 2: Datentypen

 

Zweckbestimmung In der [XML (Second Edition)] Spezifikation werden eingeschränkte Möglichkeiten definiert, Datentypen für den Inhalt eines Dokuments anzugeben. In diesen Dokumenten werden Datentypen für Elemente oder Attribute entweder im Dokument enthalten oder referenziert angegeben.

In C-Programmen sollten grundsätzlich diese Bit-Register verwendet werden! Die folgenden vordefinierten Datentypen sind abgeleitet von token:.

Inhaltsverzeichnis

Väldigt intressant att läsa! Sysslar själv med periodisk fasta och älskar morgonträningen och har valt att använda mig utav BCAA före, under och .

Responsive website design is technique of developing websites which are hugely functional and the development that interact to user's behavior depending on screen sizes platform and orientation. It uses fluid grids, flexible images and a smart usage of CSS me AccessPress Lite features extensive styling option and flexible layout options so every page in your website can be unique.

It's a multi-purpose Responsive Flexible WordPress theme which you can use to create almost any kind of websites. It features are intuit Recreational Program Recently, company performed outdoor recreational program to motivate all its staffs.

Market Update, This study presents an in-depth analysis of the key trends impacting the Business carrier services m Company plan to Launch new product Company today announced to launch its new product by the end of april. Thanks for delivering top quality services to your clients. It just takes a minute to get an answer from you when in difficulties. Thank you very much the support team AccessPress lite for service, are really wonderful in their care and in the resolution of the problem.

Hello, I would say I am much satisfied! Wir unterscheiden zwischen 8-Bit und Bit Registern. Vorerst behandeln wir die 8-Bit Register. Dazu muss man den Namen der controllerspezifischen Headerdatei nicht kennen.

Intern wird diese "Automatik" wie folgt realisiert: Der Controllertyp wird dem Compiler als Parameter übergeben vgl. Der Compiler definiert intern eine dem mmcu-Parameter zugeordnete "Variable" genauer: Zur Veranschaulichung einige Ausschnitte aus einem Makefile:. Zum Schreiben kann man Register einfach wie eine Variable setzen. Die ausführliche Schreibweise sollte bevorzugt verwendet werden, da dadurch die Zuweisungen selbsterklärend sind und somit der Code leichter nachvollzogen werden kann.

Atmel verwendet sie auch bei Beispielen in Datenblätten und in den allermeisten Quellcodes zu Application-Notes. Der gcc C-Compiler unterstützt ab Version 4. Man sollte sie daher nicht verwenden, wenn Code mit anderen ausgetauscht oder mit anderen Compilern bzw.

Es wird jeweils nur der Zustand des angegebenen Bits geändert, der vorherige Zustand der anderen Bits bleibt erhalten. Mit dieser Methode lassen sich auch mehrere Bits eines Registers gleichzeitig setzen und löschen. Bei bestimmten AVR Registern mit Bits, die durch Beschreiben mit einer logischen 1 gelöscht werden, muss eine absolute Zuweisung benutzt werden.

Beide Funktionen sind nicht mehr erforderlich. Zum Lesen kann man auf Register einfach wie auf eine Variable zugreifen. Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und inp ist nicht mehr erforderlich. Einige Beispiele zum Prüfen ob Bits gesetzt oder gelöscht sind:. Es gibt in der Bibliothek avr-libc Funktionen, die warten, bis ein bestimmter Zustand eines Bits erreicht ist.

Es ist allerdings normalerweise eine eher unschöne Programmiertechnik, da in diesen Funktionen "blockierend" gewartet wird. Der Programmablauf bleibt also an dieser Stelle stehen, bis das maskierte Ereignis erfolgt ist. Setzt man den Watchdog ein, muss man darauf achten, dass dieser auch noch getriggert wird Zurücksetzen des Watchdogtimers. Wenn das Bit beim Aufruf der Funktion bereits gesetzt ist, wird die Funktion sofort wieder verlassen.

Das niederwertigste Bit hat die Bitnummer 0. Wenn das Bit beim Aufruf der Funktion bereits gelöscht ist, wird die Funktion sofort wieder verlassen. Universeller und auch auf andere Plattformen besser übertragbar ist die Verwendung von C-Standardoperationen.

Die avr-libc definiert zusätzlich die meisten dieser Variablen die Bezeichnung ohne "L" oder "H". Auf diese Register kann dann direkt zugegriffen werden. Auch die Compare-Register müssen synchron geschrieben werden, da es ansonsten zu unerwünschten Compare-Ereignissen kommen kann.

Um diese Datenmüllproduktion zu verhindern, gibt es in beiden Fällen eine Synchronisation, die jeweils durch den Zugriff auf das Low-Byte ausgelöst wird:. Des weiteren ist zu beachten, dass es für all diese Bit-Register nur ein einziges temporäres Register gibt, so dass das Auftreten eines Interrupts, in dessen Handler ein solches Register manipuliert wird, bei einem durch ihn unterbrochenen Zugriff i.

Wenn mit Interrupts gearbeitet wird, kann es erforderlich sein, vor einem solchen Zugriff auf ein Bit-Register die Interrupt-Bearbeitung zu deaktivieren. In C-Programmen sollten grundsätzlich diese Bit-Register verwendet werden! Sollte trotzdem ein Zugriff auf ein Teilregister erforderlich sein, sind obige Angaben zu berücksichtigen.

Es ist darauf zu achten, dass auch ein Zugriff auf die Bit-Register vom Compiler in zwei 8-Bit-Zugriffe aufgeteilt wird und dementsprechend genauso nicht-atomar ist wie die Einzelzugriffe. Auch hier gilt, dass u. In diesem Fall muss bzw.

Ein Aufruf der Funktion mit call by value würde Folgendes bewirken: Beim Funktionseintritt wird nur eine Kopie des momentanen Portzustandes angefertigt, die sich unabhängig vom tatsächlichen Zustand das Ports nicht mehr ändert, womit die Funktion wirkungslos wäre.

Die Übergabe eines Zeigers wäre die Lösung, wenn der Compiler nicht optimieren würde. Denn dadurch wird im Programm nicht von der Hardware gelesen, sondern wieder nur von einem Abbild im Speicher. Das Ergebnis wäre das gleiche wie oben. Mit dem Schlüsselwort volatile sagt man nun dem Compiler, dass die entsprechende Variable entweder durch andere Softwareroutinen Interrupts oder durch die Hardware verändert werden kann.

Diese Register dienen dazu:. Bit im Register gesetzt 1 für Ausgang, Bit gelöscht 0 für Eingang. Bit 1 wenn Pin "high", Bit 0 wenn Portpin low. Dieses Register wird verwendet, um die Ausgänge eines Ports anzusteuern. Zuerst muss die Datenrichtung der verwendeten Pins bestimmt werden.

Um dies zu erreichen, wird das Datenrichtungsregister des entsprechenden Ports beschrieben. Für jeden Pin, der als Ausgang verwendet werden soll, muss dabei das entsprechende Bit auf dem Port gesetzt werden. Soll der Pin als Eingang verwendet werden, muss das entsprechende Bit gelöscht sein. Angenommen am Port B sollen die Pins 0 bis 4 als Ausgänge definiert werden, die noch verbleibenden Pins 5 bis 7 sollen als Eingänge fungieren.

Will man also nur den dritten Pin Bit Nr. Beide Funktionen sind in aktuellen Versionen der avr-libc nicht mehr enthalten und auch nicht mehr erforderlich. Daraus ergibt sich die Abfolge für einen Pin, der bisher als Eingang mit abgeschaltetem Pull-Up konfiguriert war:. Vergleiche dazu auch das Datenblatt Abschnitt Configuring the Pin. Am einfachsten ist es, wenn die Signale direkt aus einer anderen digitalen Schaltung übernommen werden können.

Optokoppler, Spannungsteiler , "Levelshifter" aka Pegelwandler anpassen. Die Masse der beiden Schaltungen muss selbstverständlich miteinander verbunden werden. Der Software selber ist es natürlich letztendlich egal, wie das Signal eingespeist wird.

Detaillierte Informationen darüber, ab welcher Spannung ein Eingang als 0 "low" bzw. Will man also die aktuellen Signalzustände von Port D abfragen und in eine Variable namens bPortD abspeichern, schreibt man folgende Befehlszeilen:.

Diese können in vielen Fällen statt externer Widerstände genutzt werden. Bei einem Wert von 0 ist der Pull-Up Widerstand nicht aktiv. Man sollte jeweils entweder den internen oder einen externen Pull-Up Widerstand verwenden, aber nicht beide zusammen. Der Anschluss mechanischer Kontakte an den Mikrocontroller, ist zwischen zwei unterschiedliche Methoden zu unterscheiden: Active Low und Active High.

Damit bei offenem Schalter der Controller kein undefiniertes Signal bekommt, wird zwischen die Versorgungsspannung und den Eingangspin ein sogenannter Pull-Up Widerstand geschaltet.

Dieser dient dazu, den Pegel bei geöffnetem Schalter auf logisch 1 zu ziehen. Hier wird der Kontakt zwischen die Versorgungsspannung und den Eingangspin geschaltet. Damit bei offener Schalterstellung kein undefiniertes Signal am Controller ansteht, wird zwischen den Eingangspin und die Masse ein Pull-Down Widerstand geschaltet.

Dieser dient dazu, den Pegel bei geöffneter Schalterstellung auf logisch 0 zu halten. Wird er allerdings zu hoch gewählt, ist die Wirkung eventuell nicht gegeben. Als üblicher Wert haben sich 10 kOhm eingebürgert. Drehgebern statt externer Bauteile verwendet werden können. Interne Pull-Down-Widerstand sind nicht verfügbar und müssen daher in Form zusätzlicher Bauteile in die Schaltung eingefügt werden. Die Bibliotheksfunktionen sind einfachen Zählschleifen Warteschleifen vorzuziehen, da leere Zählschleifen ohne besondere Vorkehrungen sonst bei eingeschalteter Optimierung vom avr-gcc-Compiler wegoptimiert werden.

Die Wartefunktion blockiert den Programmablauf. Möchte man einerseits warten, um z. Die Bibliotheksfunktionen funktionieren allerdings nur dann korrekt, wenn sie mit zur Übersetzungszeit beim Compilieren bekannten konstanten Werten aufgerufen werden.

Der Quellcode muss mit eingeschalteter Optimierung übersetzt werden, sonst wird sehr viel Maschinencode erzeugt, und die Wartezeiten stimmen nicht mehr mit dem Parameter überein. Genau genommen warten diese nämlich nicht eine bestimmte Zeit, sondern verbrauchen eine bestimmte Anzahl von Prozessortakten. Abhängig von der Version der Bibliothek verhalten sich die Bibliotheksfunktionen etwas unterschiedlich.

Längere Wartezeiten müssen dann über einen mehrfachen Aufruf in einer Schleife gelöst werden. Es ist nicht möglich, eine Variable als Argument zu übergeben.

Ein Verlust, der sich im Allgemeinen verschmerzen lässt. Dem Programmierer wird keine Rückmeldung gegeben, dass die Funktion ggf. Abhilfe ist eine korrigierte Includedatei: Nachdem wir nun alles Wissenswerte für die serielle Programmerstellung gelernt haben nehmen wir jetzt ein völlig anderes Thema in Angriff, nämlich die Programmierung unter Zuhilfenahme der Interrupts des AVR. Tritt ein Interrupt auf, unterbricht engl. Das Hauptprogramm wird also beim Eintreffen eines Interrupts unterbrochen, die Interruptroutine ausgeführt und danach erst wieder das Hauptprogramm an der Unterbrechungsstelle fortgesetzt vgl.

Alle Punkte sind zu beachten. Um unliebsamen Überraschungen vorzubeugen, sollten einige Grundregeln bei der Implementierung der Interruptroutinen beachtet werden. Interruptroutinen sollten möglichst kurz und schnell abarbeitbar sein, daraus folgt:. Interruptroutinen ISRs sollten also möglichst kurz sein und keine Schleifen mit vielen Durchläufen enthalten. Bei Übereinstimmung ein globales Flag setzen volatile bei Flag-Deklaration nicht vergessen, s. Dann im Hauptprogramm prüfen, ob das Flag gesetzt ist.

Es gibt allerdings die seltene Situation, dass man gerade eingelesene ADC-Werte sofort verarbeiten muss. Besonders dann, wenn man mehrere Werte sehr schnell hintereinander bekommt. Dann bleibt einem nichts anderes übrig, als die Werte noch in der ISR zu verarbeiten. Kommt aber sehr selten vor und sollte durch geeignete Wahl des Systemtaktes bzw. Auswahl des Controllers vermieden werden!

Die Anzahl der möglichen Interruptquellen variiert zwischen den verschiedenen Microcontroller-Typen. Dieses wird automatisch wieder gesetzt, wenn die Interruptroutine beendet wird. Wenn in der Zwischenzeit weitere Interrupts eintreffen, werden die zugehörigen Interrupt-Bits gesetzt und die Interrupts bei Beendigung der laufenden Interrupt-Routine in der Reihenfolge ihrer Priorität ausgeführt. Dies kann eigentlich nur dann zu Problemen führen, wenn ein hoch priorisierter Interrupt ständig und in kurzer Folge auftritt.

Dieser sperrt dann möglicherweise alle anderen Interrupts mit niedrigerer Priorität. Dies ist einer der Gründe, weshalb die Interrupt-Routinen sehr kurz gehalten werden sollen.

Es ist möglich das GIE-Bit in der ISR zu setzen und so schon wieder weitere Interrupts zuzulassen - allerdings sollte man damit vorsichtig sein und genau wissen was man damit macht.

Kritisch wird es vor allem wenn der gleiche Interrupt noch einmal kommt, bevor die ISR abgearbeitet ist. Funktionen zur Interrupt-Verarbeitung werden in den Includedateien interrupt. Das Makro sei schaltet die Interrupts ein. Oft steht man vor der Aufgabe, dass eine Codesequenz nicht unterbrochen werden darf. Es liegt dann nahe, zu Beginn dieser Sequenz ein cli und am Ende ein sei einzufügen. Dies ist jedoch ungünstig, wenn die Interrupts vor Aufruf der Sequenz deaktiviert waren und danach auch weiterhin deaktiviert bleiben sollen.

Ein sei würde ungeachtet des vorherigen Zustands die Interrupts aktivieren, was zu unerwünschten Seiteneffekten führen kann. Die aus dem folgenden Beispiel ersichtliche Vorgehensweise ist in solchen Fällen vorzuziehen:.

Zu den aktivierten Interrupts ist eine Funktion zu programmieren, deren Code aufgerufen wird, wenn der betreffende Interrupt auftritt Interrupt-Handler, Interrupt-Service-Routine.

Als Argument muss dabei die Benennung des entsprechenden Interruptvektors angegeben werden. Diese sind in den jeweiligen Includedateien IOxxxx. Auf die korrekte Schreibweise der Vektorbezeichnung ist zu achten. Der gcc-Compiler prüft erst ab Version 4. Aus dem gcc-Quellcode Version 3. Während der Ausführung der Funktion sind alle weiteren Interrupts automatisch gesperrt.

Beim Verlassen der Funktion werden die Interrupts wieder zugelassen. Sollte während der Abarbeitung der Interruptroutine ein weiterer Interrupt gleiche oder andere Interruptquelle auftreten, so wird das entsprechende Bit im zugeordneten Interrupt Flag Register gesetzt und die entsprechende Interruptroutine automatisch nach dem Beenden der aktuellen Funktion aufgerufen.

Ein Problem ergibt sich eigentlich nur dann, wenn während der Abarbeitung der aktuellen Interruptroutine mehrere gleichartige Interrupts auftreten. Die entsprechende Interruptroutine wird im Nachhinein zwar aufgerufen jedoch wissen wir nicht, ob nun der entsprechende Interrupt einmal, zweimal oder gar noch öfter aufgetreten ist.

Deshalb soll hier noch einmal betont werden, dass Interruptroutinen so schnell wie nur irgend möglich wieder verlassen werden sollten. Die nachfolgend beschriebene Methode nur dann verwenden, wenn man sich über die unterschiedliche Funktionsweise im Klaren ist.

Bei unsachgemässer Handhabung kann dies zu erheblichen Problemen durch Rekursion wie einem Stack-Overflow oder anderen unerwarteten Effekten führen und sollte wirklich nur dann eingesetzt werden, wenn man sich sicher ist, das Ganze auch im Griff zu haben. Damit wird dem Compiler mitgeteilt, dass der Inhalt der Variablen vor jedem Lesezugriff aus dem Speicher gelesen und nach jedem Schreibzugriff in den Speicher geschrieben wird.

Ansonsten könnte der Compiler den Code so optimieren, dass der Wert der Variablen nur in Prozessorregistern zwischengespeichert wird, die nichts von der Änderung woanders mitbekommen. Zur Veranschaulichung ein Codefragment für eine Tastenentprellung mit Erkennung einer "lange gedrückten" Taste. Wird innerhalb einer ISR mehrfach auf eine mit volatile deklarierte Variable zugegriffen, wirkt sich dies ungünstig auf die Verarbeitungsgeschwindigkeit aus, da bei jedem Zugriff mit dem Speicherinhalt abgeglichen wird.

Lokale Variable werden bei eingeschalteter Optimierung mit hoher Wahrscheinlichkeit in Prozessorregistern verwaltet und der Zugriff darauf ist daher nur mit wenigen internen Operationen verbunden. Die ISR aus dem vorherigen Beispiel lässt sich so optimieren:. Im Beispiel ist der Vorteil gering, bei komplexeren Routinen kann die Zwischenspeicherung in lokalen Variablen jedoch zu deutlicheren Verbesserungen führen.

Bei volatile in Verbindung mit Pointern ist zu beachten, ob der Pointer selbst oder die Variable, auf die der Pointer zeigt, volatile ist. Falls der Pointer volatile ist zweiter Fall im Beispiel , ist zu beachten, dass der Wert des Pointers, also eine Speicheradresse, intern in mehr als einem Byte verwaltet wird.

AVRs sind 8-bit Controller. Zur Veranschaulichung ein Codefragment:. Die avr-libc bietet ab Version 1. Falls Register sowohl im Hauptprogramm als auch in Interrupt-Routinen verändert werden, ist darauf zu achten, dass diese Zugriffe sich nicht überlappen. Nur wenige Anweisungen lassen sich in sogenannte "atomare" Zugriffe übersetzen, die nicht von Interrupt-Routinen unterbrochen werden können.

Das Setzen des einzelnen Bits wird bei eingeschalteter Optimierung für Register im unteren Speicherbereich in eine einzige Assembler-Anweisung sbi übersetzt und ist nicht anfällig für Unterbrechungen durch Interrupts. Die Anweisung zum Setzen von drei Bits wird jedoch in drei abhängige Assembler-Anweisungen übersetzt und bietet damit zwei "Angriffspunkte" für Unterbrechungen. Damit würde der Zwischenspeicher nicht mehr mit dem tatsächlichen Zustand übereinstimmen aber dennoch nach der Bitoperation hier ori in das Register zurückgeschrieben.

PORTA sei anfangs 0b Nun wird im ersten Teil der zweiten Anweisung der Portzustand in ein Register eingelesen b. In den beiden noch folgenden Anweisungen des Hauptprogramms wird nun der zwischengespeicherte "alte" Zustand 0b mit 0b logisch- ODER -verknüft c und das Ergebnis 0b in PortA geschrieben d.

Obwohl zwischenzeitlich Bit 0 gelöscht wurde, ist es nach d wieder gesetzt. Es wird zum Löschen eine 1 in das betreffende Bit geschrieben. Da sonst weitere Flags, als nur das gewünschte, ebenfalls gelöscht werden könnten. Im einfachsten Ausnahme- Fall gar nichts mehr. Es ist also durchaus denkbar, ein Programm zu schreiben, welches in der main-Funktion lediglich noch die Interrupts aktiviert und dann in einer Endlosschleife verharrt. Sämtliche Funktionen werden dann in den ISRs abgearbeitet.

Diese Vorgehensweise ist jedoch bei den meisten Anwendungen schlecht: Normalerweise wird man in den Interruptroutinen nur die bei Auftreten des jeweiligen Interruptereignisses unbedingt notwendigen Operationen ausführen lassen. Alle weniger kritischen Aufgaben werden dann im Hauptprogramm abgearbeitet. Diese ermöglichen es, Teile des Controllers abzuschalten. Zum Einen kann damit besonders bei Batteriebetrieb Strom gespart werden, zum Anderen können Komponenten des Controllers deaktiviert werden, die die Genauigkeit des Analog-Digital-Wandlers bzw.

Der Controller wird durch Interrupts aus dem Schlaf geweckt.