16 - Segment - Display
Dieses Display
entstand, während ich die meine IR-Box2 (die momentan immer noch in Arbeit ist) programmierte. Da ich auch
Texte (vernünftig) darstellen wollte und mir ein LCD auf die Ferne zum ablesen zu klein war machte ich mich
auf die Suche nach einem LED (Text) Display. Leider fand nichts passendes, sodass ich mich selbst an die
Arbeit machte. Da das 16 Segment Display später Senkrecht im Gehäuse montiert werden soll, habe ich fast
alles in SMD-Technik aufgebaut, um so die Bauhöhe des Gehäuse so niedrig wie möglich zu halten. Da das
Display Universell auch für andere AVR-Projekte benutzt werden kann, habe ich für die Bauanleitung eine
eigene Seite angelegt. Auch wird die Bauanleitung für die IR-Box2 (wenn sie dann mal irgendwann fertig
ist
) nicht mehr so umfangreich.
Im Gegensatz zu meinen anderen Bauanleitungen ist dieses Display nicht "Plug and Play", d.h. es werden Programmierkentnisse in ASM oder C benötigt um das Display in eigenen Projekten zu betreiben.
Vielleicht werde ich irgendwann eine Software schreiben, die die komplette Steuerung des Displays übernimmt. Denkbar währe eine Ansteuerung über RS232, SPI oder I2C.
Technische Daten:
- Vierstellige 16-Segmentanzeige (rot)
- Ansteuerung im Multiplexbetrieb
- TSOP1736 Infrarotempfänger on Board (wird nur bei Bedarf bestückt)
- Zusatz - LED rechts vom Display (wird bei mir als Alarmled benutzt)
- Ansteuerung seriell mit 3 Schieberegister (74HC595)
- Es werden nur 3 Portleitungen für das Display benötigt
Da ein einzelnes, Digit 16 LEDs enthält (mit dem DP sogar 17) sind also insgesamt (4x17) 68 LEDs anzusteuern.
Ohne Multiplexbetrieb
Beim multiplexen wird immer nur ein Digit für eine gewisse Zeit eingeschaltet. Ist die
Zeit um, wird zum nächsten Digit weitergeschaltet usw. Geschieht das schnell genug entsteht der Eindruck, das
alle Anzeigen gleichzeitig leuchten. währen so immer noch 9 Schieberegister nötig.
Der Schaltplan
Die 74HC595 sind kaskadiert Die
Schieberegister sind Hintereinandergeschaltet, d.h. jeder Überlauf wird in das nächste Schieberegister
getaktet., sodass die drei 8-Bit Schieberegister eigentlich als ein großes 24-Bit Schieberegister
(seriell IN, parallel OUT) ansehen werden kann. An den Ausgängen der HC595 sind über 330 Ohm Vorwiderstände
die 16 Segmente und der DP (Dezimalpunkt) angeschlossen. Die einzelnen (gleichen) Segmente sind
durchverbunden, würde man alle 4 Transistoren gleichzeitig durchschalten, währe auf jedem Digit der gleiche
Char zu sehen. Das würden die 74HC595 jedoch nicht allzulange mitmachen. An QA..QD von IC3 sind die PNP
Treibertransistoren für die gemeinsamen Anoden der 16-Segmentanzeigen "PSA 08-11 RT (Reichelt) angeschlossen.
Der Nachteil hierbei ist, das man bei der Programmentwicklung aufpassen muss, das immer nur ein Transistor
durchschaltet, da ansonsten der Ausgangsstrom der 74HC595 überschritten werden kann, zumal ich keine extra
Treiber für die Segmente vorgesehen habe. Um dies auszuschliessen hätte man die Transistoren an einen
separaten Decoder (z.B. 74HC138) anschliessen können was aber (neben mehr Portleitungen) einen höheren Hard-
und Softwareaufwand bedeutet hätte. Das RC-Glied an SCL sorgt für einen definierten Zustand beim einschalten
des Displays und schaltet alle Segmente ein. Würde man dieses weglassen währe die Anzeige nach dem
Einschalten Zufällig. Man könnte SCL auch einen eigenen Portpin spendieren und so den HC595 Resetten. Wer
mehr über Schieberegister erfahren will wird bei www.mikrocontroller.net fündig.
Trotz der 330 Ohm Vorwiderstände leuchten die Segmente noch schön hell, da die "PSA 08-11 RT" eine Super- Bright - Red Anzeige ist. Der Strom durch ein Segment (I=U/R) ist somit (5V-2.5V)/330 ca. 7,5mA. Die 8 Ausgänge des 74HC 595 können insgesamt 70mA liefern, wenn alle 8 Segmente (eines HC595) leuchten fliesst ein Maximalstrom von ca. 60 mA, ist also noch im "grünen Bereich". Der TSOP1736 (IR-Empfänger) ist mit einem RC - Glied beschaltet wie im Datenblatt angegeben. Der Ausgang des TSOP kann mit SV2 Pin5 an ein Portpin des AVRs angeschlossen werden. Auch die einzelne LED(1) liegt an SV2 .
Layout
Die Displayplatine misst ca. 100 x 48mm und ist Doppelseitig. Der Platz für den TSOP1736 ist etwas knapp bemessen. Dieser lässt sich aber gut bestücken indem man zwischen IC-Gehäuse und Platine etwa 6mm Platz lässt und die Anschlussdrähte so ausrichtet, dass der IC unterhalb von Digit4 Platz findet. Ich habe Doppelkontakt IC-Fassungen für die Anzeigen benutzt die ich mir aus vorhandenen Dil24 (breite Version) auf 18 Pins gekürzt habe, da die Pins der PSA 08-11 RT etwas dicker sind und nicht in die einreihigen (gedrehten) Fassungen passen.

Ansteuerung
Die Ansteuerung erfolgt am besten im Timerinterrupt. Jedes Digit sollte
mindestens 100 mal pro Sekunde angezeigt werden (Multiplexfrequenz = >100Hz) damit kein flackern der
Anzeige mehr zu sehen ist, da 4 Digits vorhanden sind sollte der Interrupt mindestens 400 mal pro Sekunde
durchlaufen werden also alle 2,5 mS. Jeder Interrupt schaltet das Digit eine Stelle weiter und legt den
entsprechenden 16-Segment Code an die Display LEDs. Dies geschieht durch die (serielle) Übertragung von 3
Bytes in das (24Bit) Schieberegister. Das erste Byte enthält (im unteren Nibble
Ein Nibble ist
ein halbes Byte (4 Bit) und passt so genau in eine Stelle einer Hex-Zahl) für das Digit das
eingeschaltet werden soll eine 0 (negative Logik) und für die 3 Transistoren die ausgeschaltet werden jeweils
eine 1. Soll in diesem Digit zusätzlich der DP eingeschaltet werden, muss Bit 7 gelöscht werden. Danach
folgen 2 Bytes mit dem 16 Segment Code. Auch hier die Negative Logik beachten (0 LED ein, 1 LED aus). Zum
übertragen eines Byte in das Schieberegister werden die 3 Signale SER, SCK und RCK an je einen Portpin des MC
angeschlossen und als Ausgang programmiert. SER ist der Dateneingang. Die Daten (0 oder 1) werden mit einer
positiven Flanke
Das ist der Moment, wenn die Spannung von 0 Volt auf +5 Volt
ansteigt an SCK in das Schieberegister getaktet und im internen Flipflop an Position 1 (A)
gespeichert (aber noch nicht an QA ausgegeben) . Vorher wandert der alte Wert von A nach B, B nach C usw. es
wird wie der Name (Schieberegister) schon sagt geschoben
. Der letzte Wert (H) geht dabei nicht verloren weil dieser mit dem SER-Eingang des
nächsten 74HC595 verbunden ist. Die Daten werden jedoch erst an den Ausgangslaches erscheinen wenn RCK kurz
von 0 auf 1 geschaltet wird. Solange also noch geschoben wird ändert sich noch nichts an den Ausgängen des
74HC595. Die Schieberegister ließen sich auch über SPI ansteuern. Ich habe mich für die Softwareversion
entschieden, so kann ich mir die Portpins selbst aussuchen und bin nicht an die vorgegebenen SPI Pins des AVR
gebunden, ausserdem werden beim SPI-Modul die gleichen Pins benutzt die auch für den ISP notwendig sind und
in dieser Richtung wollte ich nicht Experimentieren, zumal meine Routine zum übertragen eines Byte in das
Schieberegister nur 13 Befehle beinhaltet
.
ASM Codebeispiel, ein Byte in den 74HC595 takten:
;Taktet das Byte temp in das Schieberegister, vllt. noch als Makro machen,spart 3* rcall+ret
HC595: sec ;Carry für Schleifenende
rol temp ;erstes Datenbit ->C, C(Schleifenende) -> Temp (Bit0=1)
rjmp shift ;Erstes Datenbit an Port legen
nxbit: lsl temp ;Datenbit raus, Null rein
breq ex1 ;das letzte Carry war meins und geht nichtmehr raus
shift: brcc bit0 ;ist Datenbit =0?
sbi S_Port,SerD ;nein, es ist 1
rjmp bit1 ;an Clock Läuten
bit0: cbi S_Port,SerD ;Datenbit =0
bit1: cbi S_Port,Clock ;Steigende Flanke an Clock..
sbi S_Port,Clock ;.. schiebt das Bit in den HC595
rjmp nxbit ;Das ganze 8 mal
ex1: ret
;--------------------------------------------------------------------
Im Beispiel oben enspricht SerD dem
AVR-Portpin der an SER angeschlossen ist. Clock ist der Portpin der an SCK geht. S_Port entspricht dem dem AVRPort (z.B. PortB). Die
Routine ist etwas Tricky und benötigt keinen Schleifenzähler und keine weiteren Register (ausser temp für die
Übergabe). Die Abbruchbedingung für die Schleife ist erfüllt, wenn in temp alle 8 Bits 0 sind. LSL schiebt eine null von links ein und das Datenbit in
das Carry. Sind alle 8 Bits raus, ist das Z-Flag gesetzt und die Abbruchbedingung ist erfüllt. Das am Anfang
eingeschobene Bit ist notwendig um sicherzugehen, das alle 8 Bits übertragen wurden und befindet sich zum
Schluss wieder im Carry (wo es kein Mensch mehr braucht ).
Beim programmieren der IR-Box2 bin ich folgendermassen Vorgegangen.
- Einen Interruptzähler anlegen der bei jeden Interrupt um 1 hochzählt
- Den Zähler bei 4 Reseten (der Zähler zählt also immer nur von 0..3). In ASM einfach Bit 2..7 ausmaskieren
- 4 Bytes im SRam für die ASCii Codes reservieren die vom Hauptprogramm mit den ASCii Codes beschrieben werden
- Anhand des Interruptzählers den passenden Transistor schalten. Achtung, negative Logik
- Anhand des Interruptzählers das passende SRAM Byte auslesen
- Den ASCii Wert mit 2 multiplizieren (in ASM geht auch LSL) und zur Anfangsadresse der Tabelle addieren.
- Die nächsten 2 Bytes in der Tab. in die 74HC595 takten.
Im Hauptprogramm kann der Displayspeicher dann einfach mit Chars beschrieben werden. Längere Texte können auch gescrollt werden indem man im Main einen Zeiger auf den String erstellt und in einer Schleife immer 4 Chars zum Display schickt (in das Display-SRAM schreibt). Nach einer kurzen Pause wird der Stringzeiger um 1 erhöht um von neuem zu beginnen, bist der komplette Text durch ist.
Codebeispiel ASCii Tabelle
Die habe ich mit Papier und Bleistift erstellt und enthält das notwendigste um Ziffern und (Gross-) Buchstaben darzustellen, ein paar
Sonderzeichen sind auch enthalten. Kleinbuchstaben und ein paar Sonderzeichen fehlen noch, können aber bei
Bedarf hinzugefügt werden. Die Grossbuchstaben habe ich einfach (copy & paste) an die ASCii-Position der
Kleinbuchstaben kopiert, somit ist es egal wie man die Texte im Quellcode ablegt, es werden immer
Grossbuchstaben angezeigt.
;16 Segment ASCTabelle, das erste Byte enthält sie Segmente K..U, Byte2 A..F
;Low aktiv! 0=Segment ein 1=Segment aus
;Da man die ASC Codes 0..15 eh nicht Darstellen kann habe ich 0..9 und A..F in die
;ersten 16 Tabellenpos. geschrieben. Das spart etwas Umrechnungszeit bei Dez - Hex Routinen
;------------------------------------------------------------------------------------------
.org $f00 ;An gerade Adresse setzen, das spart der ISR Zeit da ZH nicht geprüft werden muss
ASCTab:
.db 0b11111111,0b00000000 ;0
.db 0b11011111,0b11001111 ;1
.db 0b11101110,0b00010001 ;2
.db 0b11101111,0b00000011 ;3
.db 0b11101110,0b11001110 ;4
.db 0b11101110,0b00100010 ;5
.db 0b11101110,0b00100000 ;6
.db 0b11011011,0b00111111 ;7
.db 0b11101110,0b00000000 ;8
.db 0b11101110,0b00000010 ;9
.db 0b11101110,0b00001100 ;A
.db 0b10101011,0b00000011 ;B
.db 0b11111111,0b00110000 ;C
.db 0b10111011,0b00000011 ;D
.db 0b11101110,0b00110000 ;E
.db 0b11111110,0b00111100 ;F
;meine Sonderzeichen
.db 0b10111011,0b01011000 ;0 Grad
.db 0b11111010,0b01011010 ;5 Grad
.db 0b10101111,0b10011111 ;Grad
.db 0b11111111,0b11110011 ;Cursor
.db 0b11110011,0b11101101 ;IN (für Innentemperatur)
.db 0b11111010,0b11111100 ;OUT (für Aussen)
.db 0b01110111,0b00000000 ;0 mit Schrägstrich
.db 0b01111101,0b11111100 ;$18 Rechts
.db 0b11010111,0b11001111 ;$19 Links
;ASCii
.org ASCTab+32
.db 0b11111111,0b11111111 ;Space
.db 0b11111111,0b11001111 ;!
.db 0b10111111,0b11111110 ;"
.db 0b10101010,0b11000011 ;#
.db 0b10101010,0b00100010 ;$
.db 0b10001000,0b01100110 ;%
.db 0b10011001,0b10100011 ;&
.db 0b11011111,0b11111111 ;'
.db 0b10111011,0b10110111 ;(
.db 0b10111011,0b01111011 ;)
.db 0b00000000,0b11111111 ;*
.db 0b10101010,0b11111111 ;+
.db 0b11111101,0b11111111 ;,
.db 0b11101110,0b11111111 ;-
.db 0b11111010,0b11111001 ;.
.db 0b11011101,0b11111111 ;/
.db 0b11111111,0b00000000 ;0
.db 0b11011111,0b11001111 ;1
.db 0b11101110,0b00010001 ;2
.db 0b11101111,0b00000011 ;3
.db 0b11101110,0b11001110 ;4
.db 0b11101110,0b00100010 ;5
.db 0b11101110,0b00100000 ;6
.db 0b11011011,0b00111111 ;7
.db 0b11101110,0b00000000 ;8
.db 0b11101110,0b00000010 ;9
.org ASCTab+65 ;ATM noch keine Sonderzeichen
.db 0b11101110,0b00001100 ;A
.db 0b10101011,0b00000011 ;B
.db 0b11111111,0b00110000 ;C
.db 0b10111011,0b00000011 ;D
.db 0b11101110,0b00110000 ;E
.db 0b11111110,0b00111100 ;F
.db 0b11101111,0b00100000 ;G
.db 0b11101110,0b11001100 ;H
.db 0b10111011,0b11111111 ;I
.db 0b11111111,0b10000001 ;J
.db 0b11001110,0b11101100 ;K
.db 0b11111111,0b11110000 ;L
.db 0b01011111,0b11001100 ;M
.db 0b01110111,0b11001100 ;N
.db 0b11111111,0b00000000 ;O
.db 0b11101110,0b00011100 ;P
.db 0b11110111,0b00000000 ;Q
.db 0b11100110,0b00011100 ;R
.db 0b11101110,0b00100010 ;S
.db 0b10111011,0b00111111 ;T
.db 0b11111111,0b11000000 ;U
.db 0b11011101,0b11111100 ;V
.db 0b11110101,0b11001100 ;W
.db 0b01010101,0b11111111 ;X
.db 0b01011011,0b11111111 ;Y
.db 0b11011101,0b00110011 ;Z
.org ASCTab+97
;ATM keine Lust auf Kleinbuchstaben, also vorerst alles in Grossschrift
.db 0b11101110,0b00001100 ;A
.db 0b10101011,0b00000011 ;B
.db 0b11111111,0b00110000 ;C
.db 0b10111011,0b00000011 ;D
.db 0b11101110,0b00110000 ;E
.db 0b11111110,0b00111100 ;F
.db 0b11101111,0b00100000 ;G
.db 0b11101110,0b11001100 ;H
.db 0b10111011,0b11111111 ;I
.db 0b11111111,0b10000001 ;J
.db 0b11001110,0b11101100 ;K
.db 0b11111111,0b11110000 ;L
.db 0b01011111,0b11001100 ;M
.db 0b01110111,0b11001100 ;N
.db 0b11111111,0b00000000 ;O
.db 0b11101110,0b00011100 ;P
.db 0b11110111,0b00000000 ;Q
.db 0b11100110,0b00011100 ;R
.db 0b11101110,0b00100010 ;S
.db 0b10111011,0b00111111 ;T
.db 0b11111111,0b11000000 ;U
.db 0b11011101,0b11111100 ;V
.db 0b11110101,0b11001100 ;W
.db 0b01010101,0b11111111 ;X
.db 0b01011011,0b11111111 ;Y
.db 0b11011101,0b00110011 ;Z
;---------------------------------------------------------------------------------------
Viel Spass beim löten und programmieren
PS. Ich weiss das die Stückliste noch fehlt, die werde ich demnächst noch nachreichen
Die Eagle Dateien der Platine Downloaden
Neu
Ich habe ein
Demoprogramm für das LED-Display geschrieben. Dieses kann man sich unten anschauen. Es läuft auf einem
Tiny2313 (Fusebits auf 8 MHz RC Oszilator stellen, oder 8 MHz Quarz verwenden, DIV8 Fuse deaktivieren). Es
wird gezeigt wie Normaler Text und Ziffern ausgegeben werden ausserdem wird ein String durch das Display
gescrollt. Da ich den Quelltext für das Web etwas modifizieren musste rate ich den Code lieber Downzuloaden
anstatt ihn mit Copy & Paste ins Studio einzufügen. Ich habe das 16Seg-Display an PB0..2 angeschlossen.
Dies lässt sich jedoch einfach im Quelltext ändern, falls diese Pins für etwas anderes vorgesehen sind.

;* Am Beispiel des AT-Tiny2313 wird ein 16-Segment Display in Betrieb genommen. *
;* Bauanleitung bei http://www.avr-projekte.de *
;* Autor: Jürgen Woetzel *
;* Version vom 16.08.09 *
;************************************************************************************
.include "tn2313def.inc"
.device attiny2313
;-------------------------------------------------------------------------------------
.def S =r5 ;SRegister
.def temp =r16 ;Trash
.def temp1 =r17 ;
.def temp2 =r18 ;
.def itemp =r19 ;Bit-Zähler für Digits (Multiplex 16Seg)
.def tick =r25 ;Zähler für div. Timings
;-------------------------------------------------------------------------------------
;Schieberegister 74HC595 für 16Seg.-Display
.equ S_Port = PORTB ;Port des 74HC595
.equ S_DRR = DDRB ;Datenrichtung
.equ RClock = 2 ;74HC595 Schieberegister -> Latch (steigende Flanke)
.equ Clock = 1 ;74HC595 Takt (steigende Flanke)
.equ SerD = 0 ;74HC595 Daten
;-------------------------------------------------------------------------------------
.cseg
.org 0
rjmp Reset
;-------------------------------------------------------------------------------------
;ISR
.org OVF0addr
in S,sreg ;Verschiedene Register sichern
push temp
push temp1
push temp2
push ZH
push ZL
inc tick ;Variable für Warteschleifen
inc itemp ;Digitzähler +1, zählt immer nur von 0..3 ...
cbr itemp,0b11111100 ;... und wird als Index auf das aktive Digit benutzt.
;********************************************************************************************
;* Multiplexen der 16Segment Anzeige *
;* alle 2 ms wird eine der 4 Anzeigen (gem. Anode, Treiber low Aktiv) eingeschaltet (welche *
;* steht in itemp). *
;* Der entsprechende ASC-Code steht im SRam Dig1..4. Die ISR holt den zugehörenden ASC-Code *
;* und ermittelt damit den passenden 16Seg.-Code den er in die Schieberegister taktet. *
;* Im Mainprg. wird nur noch der ASC-Code nach dig1..4 geschrieben, den Rest macht die ISR. *
;********************************************************************************************
;Erstes Byte in den 595 shiften. Bit0..3 =Digit(0=Digit ein), Bit7 =0 für DP ein.
mov temp1,itemp
ser temp ;temp = -1
clc ;Null an die richtige Pos. schieben
nxtr: rol temp ;Anhand von itemp das richtige..
dec temp1 ;Digit schalten
brpl nxtr
;>> in temp steht jetzt für das richtige Digit eine Null
;Wenn nötig, DP (Dezimalpunkt) einschalten
mov temp1,temp
com temp1
lds temp2,dpmem ;ein 0Bit im unteren Nibble schaltet den DP
; com temp2 ;ein 1Bit schaltet DP wenn nicht auskommentiert
and temp1,temp2
brne noDP
cbr temp,$80 ;DP ein
noDP: rcall HC595 ;Erstes Byte in den HC595 takten
ldi YH,high(Dig1) ;Zeiger auf Display SRAM
ldi YL,low(Dig1) ;Y zeigt nun auf 1.Digit
add YL,itemp ;aktuelles Digit addieren
ld temp,Y ;in temp steht nun der ASCii Code des aktuellen Digit
lsl temp ;mal 2, pro Char sind 2 Bytes in der ASCTab.
ldi ZH,high(ASCTab<<1) ;Zeiger auf ASCTab
ldi ZL,low(ASCTab<<1)
add ZL,temp ;+ offset
lpm temp,Z+ ;1. Bitmuster -> Temp
rcall hc595 ;Temp raustakten
lpm temp,Z ;2.Bitmuster
rcall hc595 ;und raus
cbi S_Port,RClock ;Palim Palem,Steigende Flanke an RClock..
sbi S_Port,RClock ;..schreibt das Schieberegister in die Latches
TIM0_OVF_exit: ;ISR Ende
pop ZL ;Register Zurücklesen
pop ZH
pop temp2
pop temp1
pop temp
out sreg,S
reti
;----------------------------------------------------------------------
;Taktet das Byte temp in das Schieberegister, vllt. noch als Makro machen,spart 3* rcall+ret
HC595: sec ;Carry für Schleifenende
rol temp ;erstes Datenbit ->C, C(Schleifenende) -> Temp (Bit0=1)
rjmp shift ;Erstes Datenbit an Port legen
nxbit: lsl temp ;Datenbit raus, Null rein
breq ex1 ;das letzte Carry war meins und geht nichtmehr raus
shift: brcc bit0 ;ist Datenbit =0?
sbi S_Port,SerD ;nein, es ist 1
rjmp bit1 ;an Clock Läuten
bit0: cbi S_Port,SerD ;Datenbit =0
bit1: cbi S_Port,Clock ;Steigende Flanke an Clock..
sbi S_Port,Clock ;.. schiebt das Bit in den HC595
rjmp nxbit ;Das ganze nochmal
ex1: ret
;--------------------------------------------------------------------
;--------------------------------------------------------------------
;Init
Reset: ldi temp,RAMEND ;Stack Init
out SPL,temp ;Wie immer ans Ende des SRAM
;Timer Init
ldi temp,1<<CS00|1<<CS01 ;Timer/Counter0, Vorteiler = Systemtakt/64
out TCCR0,temp ;alle 256*64 Taktzyklen (2,048 mS @ 8MHz) ein Timerinterrupt
ldi temp,1<<TOIE0 ;Timer0 Einschalten
out TIMSK,temp
;Ports Init
ldi temp,1<<SerD|1<<Clock|1<<RClock
out S_DRR,temp ;Die 3 Signale zum HC595 als Ausgang, der Rest ist Eingang
sei ;ISR Los ...
ldi temp,0b1111 ;DP aus,
sts DPmem,temp
;--------------------------------------------------------------------
;Schreibt den Text "DEMO" auf das Display und Wartet ca 5 Sekunden
;
main: ldi temp,'d'
sts Dig1,temp
ldi temp,'e'
sts Dig2,temp
ldi temp,'m'
sts Dig3,temp
ldi temp,'o'
sts Dig4,temp
rcall wait5
;--------------------------------------------------------------------
;Schreibt "1234" auf das Display
;
ldi temp,1
sts Dig1,temp
inc temp
sts Dig2,temp
inc temp
sts Dig3,temp
inc temp
sts Dig4,temp
;--------------------------------------------------------------------
;Lässt den DP 10 mal Blinken
;
ldi temp1,10
blink: ldi temp,0b1101 ;DP an die 2.stelle
sts DPmem,temp ;DP Ein
rcal wait05 ;Zeit verplempern
ldi temp,0b1111 ;DP Aus
sts DPmem,temp
rcall wait05 ;kurz warten
dec temp1 ;das ganze 10 mal
brne blink
;---------------------------------------------------------------------
;Text Scrollen
ldi ZH,high(Text<<1);Zeiger auf den String
ldi ZL,low(Text<<1)
txloop: lpm temp,Z+ ;Die ersten 4 Chars aufs Display
sts Dig1,temp
lpm temp,Z+
sts Dig2,temp
lpm temp,Z+
sts Dig3,temp
lpm temp,Z+
tst temp ;Stringende? (lpm setzt das Z-Flag nicht)
breq main ;Wenn ja Sprung
sts Dig4,temp
sbiw Z,3 ;3 vom Stringzeiger abziehen (es wurde ja um 4 erhöht)
rcall waitx ;ne 1/4 Sek. warten
rjmp txloop ;die nächsten 4 Chars
;-------------------------------------------------------------------------------------
;Warteschleifen
wait05: rcall waitx ;0,5 Sekunde vertrödeln
waitx: clr tick ;Der Zähler wird in der ISR alle 2,048 mS erhöht.
waitx1: cpi tick,128 ;Es werden (128*2,048) 0,262 Sekunden vertrödelt
brne waitx1 ;Um die Scrollgeschwindigkeit zu ändern, mit dem Wert 128 spielen
ret
wait5: ldi temp,20 ;5 Sekunden vertrödeln
wait5_2: rcall waitx
dec temp
brne wait5_2
ret
;-------------------------------------------------------------------------------------
;Text (Null-Terminiert) der Gescrollt werden soll
Text: .db " *** www.avr-projekte.de *** ein tiny2313 schiebt diesen text durch das 16-segment-display *** Sonderzeichen §$%&/()=?><"
.db 16,17,18,19,20,21,22,23,24," ",0
;------------------------------------------------------------------------------------------
;16 Segment ASCTabelle, das erste Byte enthält sie Segmente K..U, Byte2 A..F
;Low aktiv! 0=Segment ein 1=Segment aus
;Da man die Codes 0..15 eh nicht Darstellen kann habe ich 0..9 und A..F in die
;ersten 16 Tabellenpos. geschrieben. Das spart etwas Umrechnungszeit bei Dez - Hex Routinen
;------------------------------------------------------------------------------------------
.org $300 ;An gerade Adresse setzen, das spart der ISR Zeit da ZH nicht geprüft werden muss
ASCTab:
.db 0b11111111,0b00000000 ;0
.db 0b11011111,0b11001111 ;1
.db 0b11101110,0b00010001 ;2
.db 0b11101111,0b00000011 ;3
.db 0b11101110,0b11001110 ;4
.db 0b11101110,0b00100010 ;5
.db 0b11101110,0b00100000 ;6
.db 0b11011011,0b00111111 ;7
.db 0b11101110,0b00000000 ;8
.db 0b11101110,0b00000010 ;9
.db 0b11101110,0b00001100 ;A
.db 0b10101011,0b00000011 ;B
.db 0b11111111,0b00110000 ;C
.db 0b10111011,0b00000011 ;D
.db 0b11101110,0b00110000 ;E
.db 0b11111110,0b00111100 ;F
;meine Sonderzeichen
.db 0b10111011,0b01011000 ;0 Grad
.db 0b11111010,0b01011010 ;5 Grad
.db 0b10101111,0b10011111 ;Grad
.db 0b11111111,0b11110011 ;Cursor
.db 0b11110011,0b11101101 ;IN (für Innentemperatur)
.db 0b11111010,0b111111001 ;OUT (für Aussen)
.db 0b01110111,0b00000000 ;0 mit Schrägstrich
.db 0b01111101,0b11111100 ;$18 Rechts
.db 0b11010111,0b11001111 ;$19 Links
;ASCii
.org ASCTab+32
.db 0b11111111,0b11111111 ;Space
.db 0b11111111,0b11001111 ;!
.db 0b10111111,0b11111110 ;"
.db 0b10101010,0b11000011 ;#
.db 0b10101010,0b00100010 ;$
.db 0b10001000,0b01100110 ;%
.db 0b10011001,0b10100011 ;&
.db 0b11011111,0b11111111 ;'
.db 0b10111011,0b10110111 ;(
.db 0b10111011,0b01111011 ;)
.db 0b00000000,0b11111111 ;*
.db 0b10101010,0b11111111 ;+
.db 0b11111101,0b11111111 ;,
.db 0b11101110,0b11111111 ;-
.db 0b11111010,0b11111001 ;.
.db 0b11011101,0b11111111 ;/
.db 0b11111111,0b00000000 ;0
.db 0b11011111,0b11001111 ;1
.db 0b11101110,0b00010001 ;2
.db 0b11101111,0b00000011 ;3
.db 0b11101110,0b11001110 ;4
.db 0b11101110,0b00100010 ;5
.db 0b11101110,0b00100000 ;6
.db 0b11011011,0b00111111 ;7
.db 0b11101110,0b00000000 ;8
.db 0b11101110,0b00000010 ;9
.org ASCTab+65
.db 0b11101110,0b00001100 ;A
.db 0b10101011,0b00000011 ;B
.db 0b11111111,0b00110000 ;C
.db 0b10111011,0b00000011 ;D
.db 0b11101110,0b00110000 ;E
.db 0b11111110,0b00111100 ;F
.db 0b11101111,0b00100000 ;G
.db 0b11101110,0b11001100 ;H
.db 0b10111011,0b11111111 ;I
.db 0b11111111,0b10000001 ;J
.db 0b11001110,0b11101100 ;K
.db 0b11111111,0b11110000 ;L
.db 0b01011111,0b11001100 ;M
.db 0b01110111,0b11001100 ;N
.db 0b11111111,0b00000000 ;O
.db 0b11101110,0b00011100 ;P
.db 0b11110111,0b00000000 ;Q
.db 0b11100110,0b00011100 ;R
.db 0b11101110,0b00100010 ;S
.db 0b10111011,0b00111111 ;T
.db 0b11111111,0b11000000 ;U
.db 0b11011101,0b11111100 ;V
.db 0b11110101,0b11001100 ;W
.db 0b01010101,0b11111111 ;X
.db 0b01011011,0b11111111 ;Y
.db 0b11011101,0b00110011 ;Z
.org ASCTab+97 ;vorerst alles in Grossschrift
.db 0b11101110,0b00001100 ;A
.db 0b10101011,0b00000011 ;B
.db 0b11111111,0b00110000 ;C
.db 0b10111011,0b00000011 ;D
.db 0b11101110,0b00110000 ;E
.db 0b11111110,0b00111100 ;F
.db 0b11101111,0b00100000 ;G
.db 0b11101110,0b11001100 ;H
.db 0b10111011,0b11111111 ;I
.db 0b11111111,0b10000001 ;J
.db 0b11001110,0b11101100 ;K
.db 0b11111111,0b11110000 ;L
.db 0b01011111,0b11001100 ;M
.db 0b01110111,0b11001100 ;N
.db 0b11111111,0b00000000 ;O
.db 0b11101110,0b00011100 ;P
.db 0b11110111,0b00000000 ;Q
.db 0b11100110,0b00011100 ;R
.db 0b11101110,0b00100010 ;S
.db 0b10111011,0b00111111 ;T
.db 0b11111111,0b11000000 ;U
.db 0b11011101,0b11111100 ;V
.db 0b11110101,0b11001100 ;W
.db 0b01010101,0b11111111 ;X
.db 0b01011011,0b11111111 ;Y
.db 0b11011101,0b00110011 ;Z
;---------------------------------------------------------------------------------------
.dseg
.org SRAM_START
Dig1: .byte 1
Dig2: .byte 1
Dig3: .byte 1
Dig4: .byte 1
DPmem: .byte 1
Alternativ zur Scrollroutine im Quelltext oben, hier noch ein Stückchen Code der einen bestehenden Text aus dem Display scrollt und den String anhängt. Aus diesem Grund sollte der String mit mindestens einem Leerzeichen anfangen. Man spart sich den Befehl "sbiw Z,3"
;Text Scrollen
ldi ZH,high(Text<<1) ;Zeiger auf den String
ldi ZL,low(Text<<1)
txloop: lds temp,dig2 ;Digit2 -> Digit1
sts dig1,temp
lds temp,dig3 ;Digit3 -> Digit2
sts dig2,temp
lds temp,dig4 ;Digit4 -> Digit3
sts dig3,temp
lpm temp,Z+ ;Neuen Char holen
tst temp ;Srtingende ?
breq main ;Wenn ja Sprung
sts Dig4,temp ;Der neue Char kommt in Digit4
rcall waitx ;1/4 Sekunde vertrödeln
rjmp txloop ;Nächste Runde, bis Stringende
;-------------------------------------------------------------------------------------
Den Quellcode Downloaden (rechte Maustaste / speichern unter) Viel
Spass damit