Diese Experimentierplatine habe ich Ende 2007 entwickelt um mich ein bisschen mit Portexpandern und PWM auseinanderzusetzen. Ein Bekannter kam zu diesem Zeitpunkt
zu mir mit 2 großen Laufschrift-Displays (110x12 LEDs) und fragte mich, ob ich ihm eine Ansteuerung hierfür bauen kann. Dummerweise sind die Programmiertastaturen
für diese Laufschriften nämlich verloren gegangen.
Da ich mich zu diesem Zeitpunkt noch nie mit Schieberegistern oder PWM auseinandergesetzt hatte, wollte ich natürlich nicht gleich auf die Ansteuerung los,
sondern habe mir eben erst einmal diese Experimentierplatine mit 2 Spalten á 14 LEDs entwickelt. Jetzt weiß ich, dass das eine gute Idee war...
Über den Attiny2313 schiebe ich jeweils 16 Bit in die Schieberegister, wobei die ersten beiden Ausgänge des IC1 die Spalten über die beiden Transistoren Q1 und Q2
schalten, die Ausgänge 3 bis 8 steuern die LEDs 1 bis 6 an - und die Ausgänge 1 bis 8 des zweiten 74HC595 steuern die LEDs 7 bis 14. Also werden genau 16 Bit
benötigt.
Zunächst hatte ich die Ansteuerung komplett in Bascom geschrieben - was nicht unbedingt voll zufriedenstellend war. Also habe ich mich mal einen Tag hingesetzt und
schnell mal ein bisschen Assembler gelernt - und am gleichen Tag die Ansteuerungsroutinen dorthin umgebaut. Das Ganze ist jetzt schön schnell - für Aufbereitung und
Ausgabe beider Spalten werden 1086 clocks bei einer Zeit von ca. 0,054ms benötigt. Für 127 Helligkeitswerte bedeutet das: ein Durchlauf benötigt ca. 7ms - also liegt
die Anzeigefrequenz bei ca. 140Hz.
Ich bin mir sicher, dass man noch ein bisschen was am Code drehen kann - aber dafür, dass ich am Tag zuvor noch kein Assembler konnte ist die Funktion richtig zufriedenstellend.
So, generell funktioniert also alles schon einmal wie es soll - die Helligkeit aller 28 LEDs können einzeln ohne flackern gedimmt werden. Aber ein Problem besteht noch:
Warum um Himmels Willen leuchtet eine ausgeschaltene LED trotzdem noch ein bisschen, wenn die LED in der anderen Spalte an ist?
Auf der Platine oben kann man es nur schwer erkennen: Die ersten 5 LEDs der linken Spalte leuchten mit einer Helligkeit von 0/127 bis 4/127. Die oberste LED der rechten
Spalte ist - wie die oberste der linken Spalte - wie es sich gehört komplett aus. Aber LEDs 2 bis 5 der rechten Spalte glimmen proportional zur Helligkeit der LEDs der linken
Spalte.
Links eine Detailaufnahme einer ähnlichen Ansteuerung. Die LEDs in der linken Spalte leuchten jeweils mit einer Helligkeit von 0 bis 20 in 5er-Schritten (also 0 - 5 - 10 - 15 - 20).
Normalerweise sind die LEDs schon ein Stück dunkler - aber die Kamera lässt das Ganze gerne mal ein bisschen heller aussehen... Die 5 LEDs der linken Spalte sind eigentlich alle
aus - aber wie man hier schön sieht, leuchten sie trotzdem proportional zu der Helligkeit der gegenüberliegenden LED.
Auf dem rechten Bild ebenfalls eine andere Ansteuerung. Die rechten LEDs leuchten mit der größten Helligkeit 127 - die LEDs in der linken Spalte sollten eigentlich aus sein.
WARUM? Das versuche ich jetzt verzweifelt herauszufinden. Ein Königreich für ein Oszilloskop, das mir leider immer noch in meiner Werkstatt fehlt - ist erst mal einfach zu teuer...
Im Moment bin ich so weit zu denken, dass die Schieberegister den "hohen" Takt nicht ganz mitmachen und die Ausgänge daher doch noch ein kleines bisschen von der Spalte vorher offen sind - kann
ich mir aber irgendwie nicht ganz vorstellen... Oder die Transistoren schließen bei der Frequenz noch nicht komplett? Glaub ich aber auch nicht - die sollten noch mehr aushalten... Aber irgendwo
muss ja ein kleiner Strom fließen, die die LEDs (übrigens Low-Current-LEDs) zum Leuchten bringen.
Aber es spricht auch etwas für die Theorie, dass Schieberegister oder Transistor nicht richtig schließen: Wenn ich eine Pause zwischen der Ausgabe der beiden Spalte setze, also Ausgabe Spalte 1 -
Pause - Spalte 2 - Pause - usw., dann leuchten die LEDs, die aus sein sollen, nicht! Auch kann man hier gut erkennen, dass sich da kein Fehler ins Programm geschmuggelt hat, der die LED
eventuell kurz aufleuchten lässt - aber dafür flackert die Ausgabe dann auch saumäßig!
Nun ja, jetzt werde ich erst einmal in Foren nachfragen, ob jemand hier eine Lösung weiß - vielleicht ist es ja nur eine Kleinigkeit...?
Bisher versuchte Änderungen an der Hardware:
Änderung |
Ergebnis |
Transistor BC558 statt TIP125 eingesetzt |
keine Änderung |
Widerstände R21 und R22 zwischen Basis und Emitter auf 2,2k gesetzt |
keine Änderung |
Bisher versuchte Änderungen an der Software:
Änderung |
Ergebnis |
Zeilen kommentiert |
Besser verständlich ;) |
Zwischen der Ausgabe der einzelnen Spalten werden die Spalte erst einmal wieder gelöscht |
LED-aus-Problem erst einmal beseitigt, dafür sind die anderen LEDs aber auch dunkler |
Vorschläge zu Änderungen an der Hardware (noch nicht durchgeführt):
Hier zur Vervollständigung noch der zu Grunde liegende Schaltplan von der ganzen Sache (klicken für Großansicht):
Und zu guter Letzt noch der komplette Quelltext (Inline-Assembler in BASCOM):
$regfile = "attiny2313.DAT"
$crystal = 20000000
$baud = 9600 ' use baud rate
$hwstack = 28 ' default use 32 for the hardware stack
$swstack = 16 ' default use 10 for the SW stack
$framesize = 40
$prog &HFF , &H64 , &HDF , &H00 ' generated. Take care that the chip supports all
' fuse bytes.
Dim Outbyte As Integer
Dim Led_pwm(32) As Byte
Dim X As Byte , Y As Byte
Dim S As Byte
For X = 3 To 32 'PWM-Werte mit versch. Helligkeit vorbelegen
Led_pwm(x) = X - 3
Led_pwm(x) = Led_pwm(x) * 4
Led_pwm(x) = Led_pwm(x) + 11
Next
Led_pwm(3) = 0
Led_pwm(4) = 0
Led_pwm(5) = 0
Led_pwm(6) = 0
Led_pwm(7) = 0
Led_pwm(19) = 0
Led_pwm(20) = 5
Led_pwm(21) = 10
Led_pwm(22) = 15
Led_pwm(23) = 20
'Led_pwm(10) = 127
Led_pwm(19) = 127
'Led_pwm(26) = 0
'Led_pwm(32) = 127
Led_pwm(1) = 0 'Spalte 2 aus
Led_pwm(2) = 255 'Spalte 1 an
Led_pwm(17) = 255 'Spalte 2 an
Led_pwm(18) = 0 'Spalte 1 aus
$asm
.def Temp = R16
.def Pwmcnt = R17
.def Cnt = R18
.def Pwmwert = R19
.equ Schiebe_ddr = Ddrb
.equ Schiebe_port = Portb
.equ Rck = Pb4
.equ Sck = Pb7
.equ Seri = Pb5
.equ Poe = Pb3
'PCK, SCK, SERI, POE als Ausgänge schalten
LDI temp,184 'PB3 OR PB4 OR PB5 OR PB7
Out Schiebe_ddr , Temp
CBI SCHIEBE_PORT,poe 'Schieberegister "aktivieren"
RCALL Leeren 'Schieberegister komplett leeren
CLR pwmcnt 'Zähler für PWM auf 0 setzen
'---------------------------------------------------------------------------
'Hauptprogramm
Beginn:
INC PwmCnt 'PWM-Zähler um 1 erhöhen
CPI Pwmcnt,128 'PWM-Zähler mit 128 vergleichen
BRNE WorkPWM 'Wenn PWM-Zähler nicht 128 ist, dann zu "Workpwm"
CLR pwmcnt 'ansonsten PWM-Zähler auf 0 zurücksetzen
Workpwm:
Loadadr Led_pwm(32) , Z 'Zeiger auf PWM-Werte-Array setzen (letzes
' Element, da Ausgabe "von hinten nach vorne")
LDI cnt,2 '2 Spalten sollen ausgegeben werden
S_loop:
RCALL Leeren 'Schieberegister leeren
RCALL Spalte_out 'Spalte (16 Bit) in Schieberegister laden
RCALL Schiebe_out 'Schieberegister-Daten in Ausgang übernehmen
DEC cnt 'Spalten-Zähler um 1 verringern
BRNE S_Loop 'Wenn Spalten-Zähler nicht 0, dann zu "S_Loop"
rjmp Beginn 'zu "Beginn" springen => nächste PWM-Stufe
Leeren:
'16 Bit in das Schieberegister, dass alles aus ist
Push temp 'Register sichern
ldi temp,16 '16 Bits sollen übermittelt werden
Leeren_1:
SBI SCHIEBE_PORT,SERI '1 ins Schieberegister schreiben (LED aus)
RCALL Schiebe_CLOCK 'Schiebepuls geben => Schieberegister shiften
dec temp 'Bit-Zähler um 1 verringern
brne Leeren_1 'Wenn Bit-Zähler nicht 0 ist, dann zu "Leeren_1"
RCALL Schiebe_out 'Schieberegister-Daten in Ausgang übernehmen
POP temp 'Register wiederherstellen
RET
Schiebe_out:
'Daten im Schieberegister in Ausgang übernehmen
sbi SCHIEBE_PORT,RCK 'RCK am Schieberegister high => Daten an Ausgang
Cbi SCHIEBE_PORT,RCK 'RCK wieder auf low setzen
ret
Schiebe_clock:
'Daten im Scheiberegister shiften
SBI SCHIEBE_PORT,SCK 'SCK am Schieberegister auf high => Daten shiften
CBI SCHIEBE_PORT,SCK 'SCK wieder auf low setzen
RET
Spalte_out:
'Spalte ausgeben
PUSH cnt 'Register sichern
LDI cnt,16 '16 Bits sollen übermittelt werden
Spalte_out_1:
LD PwmWert,Z 'aktuellen PWM-Wert aus Array holen
LDI temp,1 ' und Zeiger
Sub Zl , Temp ' um 1 verringern
LDI temp,0 ' Zeiger wird somit auf das
SBC ZH,temp ' vorherige Element gesetzt
CPI Pwmwert,0 'PWM-Wert für die LED mit 0 vergleichen
BREQ Ledaus 'Wenn gleich (PWM-Wert=0), dann zu "Ledaus"
CP pwmwert,Pwmcnt 'PWM-Wert mit PWM-Zähler vergleichen
BRLO LedAus 'wenn PWMWert<PWM-Zähler, dann zu "Ledaus"
Ledan:
CBI SCHIEBE_PORT,SERI '0 ins Schieberegister schreiben (LED an)
rjmp Schieben 'zu "Schieben" springen
Ledaus:
SBI SCHIEBE_PORT,SERI '1 ins Schieberegister schreiben (LED aus)
Schieben:
RCALL Schiebe_CLOCK 'Schiebepuls geben => Schieberegister shiften
DEC cnt 'Bit-Zähler um 1 verringern
BRNE Spalte_Out_1 'Wenn Bit-Zähler != 0, dann zu "Spalte_Out_1"
POP cnt 'Register wiederherstellen
ret
$end Asm