Home ==> Mikrobeginner ==> 2. LED An
ATtiny13

Lektion 2: Eine LED anschalten


2.0 Übersicht

  1. Einführung
  2. Hardware
  3. Bauteile und Aufbau
  4. Programmierung

2.1 Einführung

Das erste gigantische Mikroprozessor-Programm schaltet eine Leuchtdiode an. Dabei lernen wir wie ein Programm aussieht, wie es assembliert wird, was dabei herauskommt und wie es in den Mikroprofessor übertragen wird. Wir lernen viel über Leuchtdioden und über I/O-Pins und ihre Manipulation.

2.1.1 Leuchtdioden

Leuchtdioden senden Licht aus, wenn Strom durch sie hindurch fließt. So weit, so gut. In einem gewissen Bereich gilt: je mehr desto mehr. Der Bereich ist aber sehr eng begrenzt. Zuviel Strom macht dann nicht mehr Licht, sondern nur mehr Wärme. Im Bereich niedriger Ströme von wenigen Milliampere (mA) ist die Lichtzunahme am höchsten, bei hohen praktisch nicht mehr merklich. Auch ist unser Auge und Sehvermögen alles andere als linear, so dass wir "viel" und "viel mehr" zunehmend weniger unterscheiden können.

LED-Spannung Elektrisch betrachtet ist eine Leuchtdiode ein etwas krummes Bauelement, weil ihr Widerstand mit steigendem Strom abnimmt und fast auf Null sinkt. Das ist der Grund dafür, dass Leuchtdioden immer irgendwie strombegrenzt betrieben werden müssen, weil sie selbst dem Strom nur wenig Widerstand entgegensetzen. Das kann ein Vorwiderstand sein oder ein Stromregler auf Halbleiterbasis.

Die Größe von Vorwiderständen kann mit dem Ohm'schen Gesetz R = U / I ermittelt werden. Am Vorwiderstand bleibt die Differenz zwischen der Durchlassspannung der Leuchtdiode und der Betriebsspannung hängen, also z.B. 5,0 - 2,1 V = 2,9 V. Für einen Strom von 10 mA ergibt sich ein Vorwiderstand von R = 2,9 / 0,010 = 290 Ohm.

Prozessorpins als Ein- und Ausgänge

Portpins Portinterna Der Prozessor ATtiny13 hat 8 Pins, von denen 5 als Portpins geschaltet werden können. Sie werden mit PB0 bis PB4 bezeichnet. Jeder dieser Portpins wird über ein Bit in zwei verschiedenen Prozessorspeicherstellen manipuliert, die als DDRB (Datenrichtungsregister) und als PORTB (Ausgangsregister) bezeichnet werden. Der logische Zustand des Portpins kann im PINB (Eingangsregister) gelesen werden.

Jeder Portpin kann in vier Modi geschaltet werden (jeweils für PB0):
  1. Ausgangstreiber aus (DDB0 = 0), Pull-Up-Widerstand aus (PORTB0 = 0). In diesem Modus dient der Pin als hochohmiger Eingang, der Zustand am Portpin kann per Software aus dem Register PINB eingelesen (PINB0) und ausgewertet werden.
  2. Treiber aus (DDB0 = 0), Pull-Up-Widerstand an (PORTB0 = 1). Dabei zieht ein interner Widerstand von etwa 50k den Pin auf Plus und kann mittels eines Schalters oder Tasters extern auf Null gezogen werden. Beim Einlesen von PINB0 wird bei offenem Schalter Eins erhalten, bei geschlossenem Taster Null.
  3. Treiber an (DDB0 = 1), Ausgang auf Null (PORTB0 = 0). Der Pin liegt auf sehr niedriger Spannung in der Nähe der negativen Betriebsspannung. Der Pin kann mit etwa 50 mA belastet werden, wobei die Ausgangsspannung etwas ansteigt.
  4. Treiber an (DDB0 = 1), Ausgang auf Eins (PORTB0 = 1). Der Pin liegt auf hoher Spannung in der Nähe der positiven Betriebsspannung. Der Pin kann mit bis zu 30 mA belastet werden, dabei sinkt die Ausgangsspannung ab.


2.1.2 Prozessorpins als Ausgang

Um eine Leuchtdiode mit dem Prozessor einzuschalten resultieren daraus grundsätzlich zwei Möglichkeiten:
  1. Ein Pin des Prozessors wird als Ausgang geschaltet und liefert Strom durch den Vorwiderstand und die Leuchtdiode, die mit dem Minuspol verbunden sind, oder
  2. Ein Pin des Prozessors wird als Ausgang geschaltet und zieht Strom durch den Vorwiderstand und die Leuchtdiode, die mit dem Pluspol verbunden sind.
Beide Fälle unterscheiden sich: um die Leuchtdiode im ersten Fall zum Leuchten zu bringen, muss der Ausgangspin auf Eins liegen (auf der Betriebsspannung). Im zweiten Fall muss der Ausgangspin auf Null (negative Betriebsspannung) liegen, damit die LED leuchtet.
Source und Sink Hier sind beide Möglichkeiten mit den jeweiligen Spannungsverhältnissen dargestellt. Links die Schaltung 2, bei der der Treibertransistor im Prozessor den LED-Strom auf GND zieht ("Sink"), rechts liefert der Treibertransistor den Strom für die LED ("Source").

Die Ausgangstreiber des Prozessors haben in der Sourceschaltung einen etwas grösseren Spannungsverlust im Vergleich zur Sinkschaltung. Bei 10 mA und fast 5 V Betriebsspannung macht das noch nicht so arg viel Unterschied, bei grösserem Strom und bei niedrigeren Betriebsspannungen von z. B. 2,7 V ist der Unterschied gravierend. Als Auslegungsregel sollten Ausgangspins grundsätzlich in Sinkschaltung betrieben werden. Ist das nicht möglich, sollten die Datenblätter bezüglich der realisierbaren Ströme konsultiert werden.

Alle Ausgänge sind übrigens dauerhaft kurzschlusssicher. Liegen allerdings bei mehreren I/O-Pins gleichzeitig Kurzschlüsse vor, kann die maximale Wärmelast des Chips überschritten werden. Sind größere Ströme oberhalb 30 mA zu treiben, sollte ein Transistortreiber zwischengeschaltet werden.

Home Top Einführung Aufbau Programmierung

2.2 Hardware

LED am Port Um die LED einzuschalten ist hier eine LED an den Portpin PB0 angeschlossen, deren Anode (Pluspol) über einen Vorwiderstand von 220 Ohm mit dem Pluspol verbunden ist. Die LED wird also im Sink-Modus betrieben: ist der Portpin Null, leuchtet die LED. Ist der Portpin Eins, ist sie ausgeschaltet.

Links oben ist noch die Formel zur Berechnung des LED-Stroms angegeben. Die 4,8 V sind unsere Akku-Betriebsspannung, die 2,1 V die Durchlassspannung der LED bei ca. 10 mA LED-Strom und die 0,2 V die Treiberspannung bei ca. 10 mA Sinkstrom.

Größere Ströme bringen nichts, der Helligkeitsunterschied ist praktisch nicht zu sehen. Nur bei anderen LED-Typen macht ein höherer Strom Sinn.

Der Rest der Schaltung bleibt der gleiche, den wir schon zum Zugriff auf den Chip verwendet hatten.
Home Top Einführung Hardware Programmierung

2.3 Bauteile und Aufbau

2.3.1 Bauteile

Die LED

LED Das hier ist eine rote Standard-LED mit 5 mm. Der längere Anschlussdraht ist die Anode, der Pluspol. Wird sie falsch herum angeschlossen, fließt kein Strom. Wie alle Halbleiterdioden leiten sie in verkehrter Richtung aber dennoch, allerdings liegt diese sogenannte Zenerspannung bei roten LED bei 16 V.

Der 220 Ohm-Widerstand

Widerstand 220 Ohm Das hier sind zwei Bauformen des Widerstands von 220 Ohm. Oben ein Kohleschicht-Widerstand mit 5% Toleranz, unten Metallfilm mit 1% Toleranz.

2.3.2 Der Aufbau

LED-Aufbau Der LED-Aufbau erfolgt so, dass die Kathode mit PB0 (Pin 5) des ATtiny13 verbunden wird, die Anode kommt an die benachbarte leere Spalte. Von dort wird der 220 Ohm-Widerstand mit der Plus-Schiene verbunden. Das war es.

Auch mit Strom leuchtet da jetzt mal rein gar nix. Das liegt daran, weil ein nativer ATtiny13 bei jedem Programmstart alle seine Portpins abschaltet. Um diese Portpins einzuschalten, muss erst Programmcode ausgeführt werden.
Home Top Einführung Hardware Aufbau

2.4 Programmierung

2.4.1 Programmspeicher

Um dem ATtiny13 Leben einzuhauchen, muss er programmiert werden. In diesem Fall mit den beiden Hexadezimalworten 9AB8 und 98C0 am Beginn seines Programmspeichers. Die entsprechen binär den Werten 1001.1010.1011.1000 und 1001.1000.1100.0000 an den Adressen 0000 und 0001 seines Flash-Speichers. Beim Einkauf (und nach dem Erase mit dem Programmiergerät) stehen im gesamten Programmspeicher nur lauter Einsen herum, der Prozessor tut damit rein gar nichts. Das gleiche würde übrigens passieren, wenn der Flashspeicher mit lauter Nullen gefüllt wäre. Damit lernen wir die beiden ersten Befehle des Prozessors kennen: 0000.0000.0000.0000 und 1111.1111.1111.1111. Sie heißen "Tu nichts" oder englisch "No operation", kurz NOP.

Der Programmspeicher des ATtiny13 hat 1024 Bytes, in die 512 Befehlsworte zu je 16 Bits passen. Das hört sich nicht nach viel an, aber in Assembler ist das eine ganze Menge. Unser kompliziertestes Programm wird einige zehn Befehlsworte haben, und ich bin auch mit komplizierten Abläufen noch nie an diese Grenze herangekommen. Meine Schrittmotorsteuerung hatte 141 Befehlsworte. Wenn also Arduino-Freaks über so wenig Programmspeicher die Nase rümpfen, liegt das nur an ihrem total uneffektiven Speicherfresser-C-Stil.

2.4.2 Quellcode

Da man sich Binärcodes wie oben 9AB8 und 98C0 nur sehr schwer merken kann, hat man dafür menschengerechtere Kürzel erfunden, woraus und mit deren Hilfe dieses binäre Kauderwelsch auf einfache Weise erzeugt werden kann. In diesem Fall schreibt der Programmierer die beiden Zeilen

	sbi DDRB,DDB0
	cbi PORTB,PORTB0

in eine Textdatei (Quellcodedatei hier) . Aus diesen beiden Zeilen macht der Assembler, ein Übersetzungsprogramm, die beiden Befehlsworte 9AB8 und 98C0.

Das Kauderwelsch der beiden Zeilen ist nicht so arg viel verstšndlicher als die Binär- oder Hexadezimalworte. Es erschließt sich erst, wenn man die ausfürliche Version der beiden Zeilen dazu schreibt:
	SBI: Setze Bit im I/O-Register [set bit I/O, sbi] der Datenrichtung
          von Port B [DDRB] des Portbits DDB0 [DDB0] auf Eins
	Lösche Bit im I/O-Register [clear bit I/O, cbi] im Ausgangsport des
          Ports [PORTB] des Portbits PORTB0 [PORTB0] auf Null
Das hört sich schon etwas verständlicher an. Mit diesem Hintergrundwissen kann man sich nun SBI und CBI vielleicht besser merken.

Dem Übersetzungsprogramm, dem Assembler, ist es übrigens egal, ob Instruktionen oder Parameter in Groß- oder Kleinbuchstaben geschrieben sind.

Grundätzlich entspricht jede Zeile im Quellcode (z.B. SBI DDRB,DDB0) genau einer ganz bestimmten Operation des Prozessors, einem einzigen Befehlswort. Nur Operationen, die der Prozessor tatsächlich physisch beherrscht, haben eine Entsprechung in einem Assemblerkürzel. Das ist unter den Programmiersprachen einzigartig, denn alle anderen Sprachen verwenden Kürzel, die eine Vielzahl von Prozessoroperationen nach sich ziehen. In Assembler kann man sich sicher sein, dass jede Codezeile sich in genau eine und nur eine einzige Operation des Prozessors verwandelt. Die Assemblerkürzel sind nur Repräsentationen des Prozessorkönnens. Sie werden als "Mnemonics" (Gedächtnisstützen) bezeichnet.

Das ist auch der Grund dafür, warum sich Assemblerinstruktionen in vielen unterschiedlichen Dialekten nicht groß darin unterscheiden, was der Prozessor tatsächlich macht. Jeder Prozessor kann zwei Zahlen addieren, in unterschiedlichen Dialekten wird das manchmal nur unterschiedlich mit Gedächtnisstützen belegt. Wer also AVR-Assembler beherrscht, muss sich bei PIC-Assembler nur geänderte Mnemonics und andere Fähigkeiten des Prozessors draufschaffen. Das Prinzip, ein Mnemonic steht für einen bestimmten Ablauf im Prozessor, bleibt das Gleiche.

2.4.3 Assemblieren

In der Codezeile "sbi DDRB,DDB0" steht "sbi" für eine Prozessorinstruktion, "DDRB" und "DDB0" sind hingegen Parameter für diese Instruktion. "DDRB", das Datenrichtungsregister von Port B, ist im Portbereich des Prozessors angesiedelt. Das Handbuch zum Prozessor sagt in seiner Portliste dazu:

Port-Register
DDRB liegt also im Portbereich an der Adresse 0x17, das im Quellcode verwendete Wort DDRB übersetzt sich daher in 0x17, DDB0 in 0x00. DDRB und DDB0 sind Symbole für Zahlen, die man sich nicht merken will. Und deren Merken auch sinnlos wäre, denn bei einem anderen AVR-Typ könnte dieser Port an einer anderen Adresse liegen.

Die beiden Ports DDRB und PORTB sind im Handbuch folgendermaßen beschrieben:

DDRB
PORTB
R/W bedeutet, diese Bits im Port lassen sich sowohl Lesen (R) als auch Schreiben (W). Initial Value bedeutet, dieses Bit wird bei einem Reset des Prozessors auf diesen Wert gesetzt.

2.4.4 Quellcode schreiben

Um Assemblerprogramme zu schreiben, braucht man einen einfachen Texteditor, der einfach ASCII-Zeichen in eine Datei schreibt, z.B. Notepad (in Windoof) oder KWrite (in Linux-KDE) und nennt diese "irgendwie.asm".

Wer es etwas komfortabler haben will, schreibt den Quellcode im Editorfenster des Studios. Hier legen wir ein neues Projekt mit Namen "2_Led_An" an und schreiben im Editorfenster:

Quellcode
Im Quellcode sind neben vielen Kommentaren (Kommentare beginnen immer mit Semikolon) noch die drei Zeilen
  
.NOLIST ; Ausgabe im Listing unterdruecken
.INCLUDE "tn13def.inc" ; Port-Definitionen lesen 
.LIST ; Ausgabe im Listing einschalten

eingebaut. Die Datei tn13def.inc enthält alle Definitionen des Prozessortyps, dort stehen die Adressen von DDRB und PORTB und sind die Bits DDB0 und PORTB0 angegeben. Die Datei findet sich im Programmpaket des Studios und das Studio findet sie. Damit das Listing nicht mit diesen ellenlangen Definitionen vollgeschrieben wird, wird seine Ausgabe mit der Assemblerdirektive .NOLIST abgeschaltet, danach mit .LIST wieder eingeschaltet.

Zur Erleichterung der Erkennung der Art von Einträgen färbt der Studio-Editor diese in unterschiedlichen Farben ein.

2.4.5 Assemblieren

Der Weg Das hier ist der weitere Weg des Quellcodes im überblick. Mit dem Assemblieren werden aus dem Quellcode ein Listing und eine Datei mit Hexcode erzeugt. Der Hexcode kann dann an eine Schreibsoftware weitergeleitet und mittels eines Programmiergeräts in den Flashspeicher des AVR übertragen werden.

Assemblieren geht mit einem externen Assembler oder mit dem im Studio eingebauten Assembler. Als externen Assembler empfehle ich meinen eigenen, gavrasm. Studio-Intern wird einfach der Menuepunkt "Build" angestoßen und das Übersetzungswerk geht ab. Es endet mit folgenden Ergebnissen:

Listing Hier legt der Assembler alle seine Ergebnisse, Beobachtungen und Meldungen ab. Hier kann man sich den erzeugten Hex-Code des gesamten Programmes anschauen. Das muss man aber nur dann, wenn der Assembler Fehler beim Assemblieren meldet.

Hex-Code Dies ist der erzeugte Hexcode in menschenlesbarer Form, im Intel-Hex-Format. Dieser enthält nur den nackten Maschinencode, zusammen mit Adressangaben und Prüfbytes. Um diesen Code müssen wir uns nicht näher kümmern.

2.4.6 In den Flashspeicher brennen

Programmierfenster Um das binäre Programm in den Chip zu übertragen, starten wir im Studio wieder die Tools und dort "Autoconnect". Im Tabulator "Main" versichern wir uns, dass der Prozessor ansprechbar ist, indem wir die Typenbytes auslesen. Dann steuern wir den Tabulator "Program" an. Dort wählen wir mit dem kleinen Quadrat hinter "Input Hex File" die vom Assembler erzeugte Datei aus und starten mit dem "Program"-Button die Übertragung in den Chip.

LED ist eingeschaltet Nach einigem Gezappel der LED, die die Programmierimpulse anzeigt, bleibt die LED dauernd an. Unsere zwei Programmzeilen haben ganze Arbeit geleistet und machen, was sie sollen.
Home Top Einführung Hardware Aufbau Programmierung
©2016 by http://www.gsc-elektronic.net