Die Betriebsspannung ist 5,0 V. Signale unter 0,3 V gelten als Low, Signale über 0,7 V als High. Damit ist das Modul gut geeignet, um die Ein- und Ausgabemöglichkeiten unserer Attiny-Platine zu erweitern.
Zur Ansteuerung der Siebensegmentanzeigen und LEDs benutzt der TM1638 einen Displayspeicher mit 16 Registern vom Typ Byte: Jedes dieser Register ist einer LED bzw. einer Siebensegmentanzeige zugeordnet (s. Abb. 1). Der Inhalt des Registers legt bei einer LED fest, ob sie leuchtet oder nicht, bei einer Siebensegmentanzeige, welche Segmente aktiviert werden. Das Register mit der Adresse 4 ist z. B. der Siebensegmentanzeige Nr. 3 (von links) zugeordnet.
Soll in dieser Siebensegmentanzeige z. B. die Zahl 1 erscheinen, müssen dort die Segmente b und c aktiviert werden (vgl. Abb. 2). Dazu muss man das entsprechende Bitmuster &B00000110 in das Register mit der Adresse 4 speichern. Weiter unten werden wir genau beschreiben, welche Befehle und Daten der Mikrocontroller dazu an den TM1638-Baustein senden muss.
Da der TM1638-Baustein viele unterschiedliche Funktionen besitzt, reicht es nicht aus, ihm die Bitmuster für die Siebensegmentanzeigen zu übertragen. Neben diesen Daten muss man ihm vielmehr auch Steuerbefehle (commands) übermitteln. Sowohl Daten als auch Steuerbefehle werden mit dem SPI-Protokoll übertragen (s. https://www.forum.g-heinrichs.de). Die Taktsignale erhält der TM1638 (Slave) über den Eingang CLK vom Mikrocontroller (Master); die maximale Taktfrequenz ist 1 MHz. Damit der Baustein die einzelnen Bits empfangen kann, muss der STB-Eingang des Bausteins auf Low (Chip Selected) sein. Man beachte, dass der TM1638-Baustein bei der seriellen Übertragung der einzelnen Bits erwartet, dass das LSB (Least Significant Bit) zuerst gesendet wird. Will man die USI-Einheit des Attiny2313 ausnutzen (s. u.), dann muss man PortB.7 (USCK) und PortB.6 (DO) des Attiny mit den Anschlüssen CLK bzw. DIO bei dem MT1638-Modul verbinden.
Es gibt drei verschiedene Steuerbefehle. Allen ist gemeinsam, dass sie durch eine negative Flanke am STB-Eingang eingeleitet werden müssen; das unterscheidet sie gerade von den Datenbytes.
Setting of Data Command (B7 = 0; B6 = 1; Restliche Bits: Parameter)
Setting of Address Command (B7 = 1; B6 = 1; Restliche Bits: Parameter)
Display Control Command (B7 = 1; B6 = 0; Restliche Bits: Parameter)
Man erkennt unschwer, dass die Steuerbefehle jeweils durch die beiden Bits B6 und B7 gekennzeichnet sind.
Wir begnügen uns an dieser Stelle damit, für drei Beispiele die nötigen Befehlssequenzen anzugeben. Wer mehr über die Funktionsweise des TM1638-Moduls erfahren möchte, den verweise ich auf das ausführliche Skript im Anhang.
1. Ziffer “1” in der Siebensegmentanzeige Nr. 3 zur Anzeige bringen (w = write)
STB = 1
STB = 0 //erzeugt negative Flanke
w &B01000100 //Schreibmodus; feste Adresse
STB = 1
STB = 0 //erzeugt negative Flanke
w &B11000110 //Adresszeiger auf &B0110 (6)
w &B00000110 //Datenbyte (Bitmuster entspricht der Ziffer 1)
STB = 1
STB = 0 //erzeugt negative Flanke
w &B10001111 //Display einschalten
2. Display ausschalten
STB = 1
STB = 0 //erzeugt negative Flanke
w &B10000000 //Display ausschalten
3. Alle Displayregister löschen (nach power-up empfohlen)
STB = 1
STB = 0 //erzeugt negative Flanke
w &B01000100 //Schreibmodus; autom. Inkrement
STB = 1
STB = 0 //erzeugt negative Flanke
w &B11000000 //Adresszeiger auf &B0000 (Startadresse 0)
Wiederhole 16 mal:
w &B00000000 //Datenbyte 0 (kein Segment aktivieren)
Am Ende sollte der TM1638-Baustein jeweils durch STB = 1 deaktiviert werden.
Für unserer Attiny-Platine kann zur Übertragung der Befehls- und Datenbytes die folgende Funktion benutzt werden
Code: Alles auswählen
Function Spi(s As Byte) As Byte
DDRB = &B11011111
For K = 0 To 7 'Umkehrung
K1 = 7 - K
S1.k = S.k1
Next K
Usidr = S1
Usisr = &B01000000 'USIOIF und Zähler löschen
Usicr = &B00011010 'USIWM0, USICS1,USICLK auf 1
Waitus 1
Do
Usicr.usitc = 1 'Takten durch Setzen von usitc
Waitus 1 'später weg!
Loop Until Usisr.usioif = 1 '16 mal toggeln
S1 = Usidr
For K = 0 To 7 'Umkehrung
K1 = 7 - K
S1.k = Usidr.k1
Next K
Spi = S1
End Function
Hier haben wir nur kurz dargelegt, wie man die Siebensegmentanzeigen ansteuert. Wer mehr über die Funktionsweise des TM1638-Moduls erfahren möchte, insbesondere auch, wie man den Status der Tasten abfragt, der sei auf das Skript im Anhang verwiesen.
Hier gibt es noch ein BASCOM-Programm für unsere Attiny-Platine, welches die Nummer der betätigten Taste in der rechten Siebensegmentanzeige anzeigt.
Code: Alles auswählen
' Datei für Attiny-Platine von E. Eube, G. Heinrichs und U. Ihlefeldt
' SPI-Master
' Achtung: MOSI (DO) über 1K-Widerstand auf PB6, MISO (DI) auf PB5; beim Lesevorgang muss auch ddrb.6 = 0 sein
' CLK auf PB7
' STB auf PB4
' Pinkonfiguration im Manual nicht ganz korrekt!
' In Wirklichkeit hat der Attiny kein echtes MISO/MOSI, sondern nur DI/DO!
'
' Test für TM1638-Modul
' Bei TM1638 muss das LSB zuerst übertragen werden!
' Für Tasterscan muss DIO von TM1638-Modul auch an PB5 angeschlossen sein;
' beim Lesevorgang muss dann PortB.6 durch DDRB.6 hochohmig gemacht werden.
'
' Programm zeigt die Nummer des zuletzt gedrückten Tasters auf der rechten Sieben-Segment-Anzeige an.
'
'----------------------------------------------------------------------------
$regfile = "attiny2313.dat" 'Attiny2313
$crystal = 4000000 '4 MHz
$baud = 9600
'**********************************************************
'******************* Deklarationen ************************
Declare Function Spi(s As Byte) As Byte
Declare Sub Loeschen
Declare Sub Display_einschalten
Declare Sub Ziffer_zeigen
Declare Sub Init_muster
Declare Sub Keyscan
Dim Bef1 As Byte
Dim Bef2 As Byte
Dim Bef3 As Byte
Dim Dummy As Byte
Dim Pause As Byte
Dim Wert As Byte
Dim I As Byte
Dim K As Byte
Dim K1 As Byte
Dim S As Byte
Dim S1 As Byte
Dim Pos As Byte
Dim Scan(4) As Byte
Dim Muster(10) As Byte
'****************** Initialisierung ***********************
Ddrb = &B11011111 'Port B als Ausgangsport; B.5 als Input
Ddrd = &B01110000 'D4, D5, D6 als Ausgang; Rest als Eingang
Portd = &B10001111 'Eingänge auf high legen
Portb.4 = 1 'STB auf 1
Waitms 10
'**********************************************************
'******************** Hauptprogramm ***********************
Pause = 2
Call Init_muster
Call Loeschen
Call Display_einschalten
Wert = Muster(1)
Pos = 14
Call Ziffer_zeigen
Do
Waitms 10
Call Keyscan
For I = 1 To 4
S = Scan(i)
If S.0 = 1 Then
K = I + 1
Wert = Muster(k)
End If
If S.4 = 1 Then
K = I + 5
Wert = Muster(k)
End If
Call Ziffer_zeigen
Next I
Loop
End
'**********************************************************
'******************* Unterprogramme ***********************
Function Spi(s As Byte) As Byte
For K = 0 To 7 'Spiegeln
K1 = 7 - K
S1.k = S.k1
Next K
Usidr = S1
Usisr = &B01000000 'USIOIF und Zähler löschen
Usicr = &B00011010 'USIWM0, USICS1,USICLK auf 1
Waitus 1
Do
Usicr.usitc = 1 'Takten durch Setzen von usitc
Waitus 1 'später weg!
Loop Until Usisr.usioif = 1 '16 mal toggeln
S1 = Usidr
For K = 0 To 7 'Spiegeln
K1 = 7 - K
S1.k = Usidr.k1
Next K
Spi = S1
End Function
Sub Loeschen
Portb.4 = 0
Waitus Pause
Bef1 = $40
Dummy = Spi(bef1) 'Displayreg, Autoinkr.
Portb.4 = 1
Waitus Pause
Portb.4 = 0
Waitus Pause
Bef2 = $c0
Dummy = Spi(bef2) 'Startadresse
Waitus Pause
Wert = 0
For I = 0 To 15
Dummy = Spi(wert)
Waitus Pause
Next I
Portb.4 = 1
Waitus Pause
End Sub
Sub Display_einschalten
Portb.4 = 0
Waitus Pause
Bef3 = $8f '$8F = 16/16 an; &B10001011 = 10/16 an (PWM)
Dummy = Spi(bef3) 'Display
Portb.4 = 1
End Sub
Sub Init_muster
Muster(1) = &B00111111 '0
Muster(2) = &B00000110 '1
Muster(3) = &B01011011 '2
Muster(4) = &B01001111 '3
Muster(5) = &B01100110 '4
Muster(6) = &B01101101 '5
Muster(7) = &B01111101 '6
Muster(8) = &B00000111 '7
Muster(9) = &B01111111 '8
Muster(10) = &B01101111 '9
' ggf. weiter Muster...
End Sub
Sub Ziffer_zeigen
Portb.4 = 0
Waitus Pause
Bef1 = $44
Dummy = Spi(bef1) 'Displayreg, Autoinkr.
Portb.4 = 1
Waitus Pause
Portb.4 = 0
Waitus Pause
Bef2 = $c0 + Pos
Dummy = Spi(bef2)
Waitus Pause
Dummy = Spi(wert)
Portb.4 = 1
Waitus Pause
End Sub
Sub Keyscan
Portb.4 = 0
Waitus Pause
Bef1 = $42 'read command
Dummy = Spi(bef1)
Waitus Pause
Ddrb.6 = 0 'wichtig, weil sonst DI beim Lesen durch DO beeinflusst wird
Waitus Pause
For I = 1 To 4
Scan(i) = Spi(dummy)
Waitus Pause
Next I
Ddrb.6 = 1
Portb.4 = 1
Waitus Pause
End Sub