Besucher seit 10/07/2004
kostenlose counter
   

Im WWW Suchen

Benutzerdefinierte Suche
   

16 - Segment - Display

16Segment DisplayDieses   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:

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.

16 - Segment Eagle Schaltplan

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.

16Segment- Display

Ansteuerung

DigitDie 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. 

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.

Die blauen Streifen im Videoclip bekomme ich leider nicht weg .
;************************************************************************************
;*    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