Hallo zusammen, ich habe mir neulich auf ebay ein 8-fach 7-Segment-Modul mit einem TM1638 LED-Treiber gekauft. Da ich gerade Assembler lerne, dachte ich mir, dass das es ein schönes Übungsprojekt wäre, dafür einen Treiber zu schreiben. Gedacht... getan :-) Der Treiber unterstützt z.Zt. nur die "Common Cathode" Version des Moduls. "Common Anode" habe ich noch in Arbeit, dort ist die Ansteuerung schwieriger zu realisieren... Die CC-Version funzt aber inzwischen sehr gut und man kann alle LED gezielt ansteuern, Zahlen als Hex, Dez und Bin ausgeben, sowie Texte als Laufschrift erscheinen lassen. Das Demo im Anhang zeigt die Möglichkeiten: https://drive.google.com/open?id=0Bztkubpzy4YtUTc5OFdManBwM0U Da es sich um mein erstes AVR-ASM Projekt handelt würde ich mich über konstruktive Kritik sehr freuen. Es ist sicherlich nicht alles optimal z.B. hätte ich in der Sendeschleife das Carry-Flag verwenden können statt umständliche Logik zu programmieren. Daran sieht man, dass der Treiber Teil meines Lernprozesses ist... Die Routinen zur Zahlenausgabe habe ich aus dem Tutorial genommen und an meinen Code angepasst. Man muss das Rad ja nicht jedesmal komplett neu erfinden. Der gesamte übrige Code (also der Treiber an sich...) ist auf meinen Mist gewachsen... Ich freue mich auf Feedback! Viele Grüße Ralf
:
Bearbeitet durch User
Ich habe wohl einen falschen Link zum Demo kopiert :( Der hier sollte funktionieren: https://drive.google.com/file/d/0Bztkubpzy4YtUTc5OFdManBwM0U/view?usp=sharing Und noch kurz ein paar Infos zum TM1638: - Treiber für max. 10(!) 7-Segment-Anzeigen mit gemeinsamer Anode oder Kathode - Kann außerdem max. 16 Taster abfragen (noch nicht im Code integriert) - keine weiteren Bauteile erforderlich (Widerstände o. Transistoren) - Ansteuerungen über 3 Leitungen (SPI-ähnlich). Strobe, Clock und Data - Helligkeit per Display-Control-Command einstellbar - Chips sind kaskadierbar mit je einer Strobe-Leitung per Chip - günstig (<1€ vom Chinamann)
:
Bearbeitet durch User
Eine Frage: Ich stieß beim Programmieren auf einen Assembler-Fehler, den ich mir nicht erklären kann. Der Übersichtlichkeit halber verwende ich folgende Deklarationen:
1 | .EQU STB_PIN = PA0 ; TM1638 strobe input |
2 | .EQU CLK_PIN = PA1 ; TM1638 clock input |
3 | .EQU DATA_PIN = PA2 ; TM1638 data input/output |
4 | |
5 | ldi AKKU, (1<<STB_PIN)|(1<<CLK_PIN)|(1<<DATA_PIN) |
Das funktioniert!
1 | .EQU DATA_CMD = 0x40; |
2 | .EQU FIXED_ADDR = 0x04; |
3 | |
4 | ldi TM1638_DATA_BYTE, (1<<DATA_CMD)|(1<<FIXED_ADDR) |
Dies funktioniert ebenfalls!
1 | .EQU DISP_CTRL_CMD = 0x80 |
2 | .EQU DISP_PWM_MASK = 0x03 ; first 3 bits are brightness (PWM) |
3 | .EQU DISP_ON = 0x08 |
4 | |
5 | ldi TM1638_DATA_BYTE, (1<<DISP_CTRL_CMD)|(1<<DISP_ON)|(1<<DISP_PWM_MASK) |
Das letzte Konstrukt führt jedoch zu einer Assembler-Warnung (Constant out of Range o.ä.) und führt auch nicht zum gewünschten Ergebnis. Wie kann das sein? Eine Oder-Verknüpfung von 0x80|0x03|0x08 ergibt doch: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 ------------------------ 1 0 0 0 0 1 0 1 1 ...also keinswegs "out of Range". Ich sehe auch keinen Unterschied zum 2. Beispiel, welches ja funktioniert!? Stehe gerade auf dem Schlauch :( Nachtrag: Ich verwende avra unter Linux!
:
Bearbeitet durch User
Hi Also bei mir hat ein Byte 8 Bit (Bit7 ... Bit0) >Das funktioniert! >.EQU DATA_CMD = 0x40; >.EQU FIXED_ADDR = 0x04; >ldi TM1638_DATA_BYTE, (1<<DATA_CMD)|(1<<FIXED_ADDR) Bezweifle ich: 1<<DATA_CMD schiebt eine 1 nach Bit64 >...also keinswegs "out of Range". Ich sehe auch keinen Unterschied zum >2. Beispiel, welches ja funktioniert!? Hier das gleiche >.EQU DISP_CTRL_CMD = 0x80 >.EQU DISP_PWM_MASK = 0x03 ; first 3 bits are brightness (PWM) >.EQU DISP_ON = 0x08 1<<DISP_CTRL_CMD -> Schiebt eine 1 zum Bit 128 1<<DISP_PWM_MASK)-> Schiebt eine 1 zum Bit 8 MfG Spess
spess53 schrieb: > Also bei mir hat ein Byte 8 Bit (Bit7 ... Bit0) Bei mir selbstverständlich auch. Ich hatte mich da ganz offensichtlich vertippt. spess53 schrieb: > 1<<DISP_CTRL_CMD -> Schiebt eine 1 zum Bit 128 > 1<<DISP_PWM_MASK)-> Schiebt eine 1 zum Bit 8 Ok, das erklärt es. Danke!
Dafür, dass du offensichtlich AVR-Assembler-Anfänger bist, schaut das Ergebnis schon recht gut aus. Ein paar Dinge sind mir bei tm1638_cc.asm aufgefallen (nachdem du ein Feedback möchtest): Gibt es einen Grund, warum du Bit-Banging statt SPI verwendest? Ggf. könnte man beide Varianten per Assembler-Direktiven verwirklichen. Ab TM1638_PRINT_DEC lassen die Kommentare ziemlich nach. ;-) So solltest du u.a. auch kommentieren, wie du das T-Flag verwendest. Im Source-Code wird manchmal per Leerzeichen getrennt, manchmal per TAB, manchmal sogar mit beiden nacheinander. Schöner wird es einheitlich mit TABs bis zum Kommentar (wie es bei dir oft, aber nicht immer der Fall ist). Bei delay.inc scheint ein kleiner Fehler zu sein, denn für Delay1s wird das Unterprogramm Delay10ms 255 mal durchlaufen. Delay1 soll (naheliegenderweise) vermutlich Delay100ms lauten (muss dann natürlich auch bei den Aufrufen geändert werden). Die diversen aus der CPU-Frequenz berechneten .equ für die Zahl der Schleifendurchgänge könnte man noch etwas übersichtlicher an den Anfang von delay.inc stellen anstatt zwischen den Assembler-Befehlen. Den Rest habe ich bislang nicht angeschaut. Gute Fortschritte!
Hallo Eberhard, zunächst mal vielen Dank für dein Feedback! Eberhard H. schrieb: > Gibt es einen Grund, warum du Bit-Banging statt SPI verwendest? > Ggf. könnte man beide Varianten per Assembler-Direktiven verwirklichen. Als ich mir das Datenblatt des Chips anschaute, hatte ich das Protokoll nicht sogleich als SPI erkannt (Anfänger...). Daher kam mir die Verwendung des Hardware-SPI zu diesem Zeitpunkt gar nicht in den Sinn. Die Erleuchtung kam dann erst mit der Analyse meines Bit-Banging Codes mittels Logic-Analyzer. Zu diesem Zeitpunkt war die Senderoutine aber schon fertig, so dass ich keine Lust mehr hatte sie auf Hardware-SPI umzustellen. Ich schaue mir das aber auf jeden Fall noch an. Eberhard H. schrieb: > Ab TM1638_PRINT_DEC lassen die Kommentare ziemlich nach. ;-) > So solltest du u.a. auch kommentieren, wie du das T-Flag verwendest. Ja. TM1638_PRINT_DEC, ...PRINT_HEX und ...PRINT_BIN habe ich ja dem Tutorial hier auf mikrocontroller.net entnommen und lediglich angepasst. Ich hatte den Code natürlich analysiert, dann aber nicht mehr daran gedacht, ihn zu kommentieren. Das hat sich dann leider auch in meinem weiteren Code so fortgesetzt. Da muss ich auf jeden Fall disziplinierter arbeiten! Gleiches gilt für die Code-Formatierung. Ich verwende z.Zt. Geany unter Linux und da habe ich erst vor kurzem die Funktion gefunden, die mir Steuerzeichen anzeigen lassen kann. Sehr hilfreich :-) Die Delay-Routinen habe ich auch nur auf die Schnelle reingefummelt, daher die inkonsistente Benennung. Eberhard H. schrieb: > Gute Fortschritte! Danke! Es macht aber auch einen Riesen-Spaß :-) Eines meiner vorrangigen Ziele war, Chips (z.B. Display-Treiber bzw. Controller) nach Datenblatt programmieren zu können. Ich war es leid, z.B. bei C-Projekten immer nach Librarys für die verwendeten Bausteine suchen zu müssen. Viel spannender erschien es mir, so etwas auch selber zu können und zu machen. Viele Grüße Ralf
Eberhards Vorschlägen folgend habe ich nun folgendes verändert: 1. Hardware SPI-Senderoutine per Assembler-Direktive implementiert.
1 | #define BITBANGING |
Damit wird der Bitbanging-Code assembliert, ansonsten der SPI-CODE. 2. Die Formatierung des Quelltextes ist nun vereinheitlicht (Tabs). 3. Der Quelltext ist weiter kommentiert (Zahlenausgaben: siehe Tutorial hier im Board). Des Weiteren ist es mir nun auch gelungen, die Leuchtdiodenleiste (die 8 Einzeldioden) oberhalb der 7-Segmentanzeigen anzusteuern. Democode: TM1638_LEDS https://drive.google.com/file/d/0Bztkubpzy4YtOUswaTZBVWp4RVU/view
Hi
Da geht einiges in Bezug auf Hauptprogramm und Library durcheinander.
Eine Library sollte per .include in das das Hauptprogramm eingebunden
werden und nicht umgedreht. Das heißt z.B. in der Lib haben '.INCLUDE
"m32def.inc"', Interruptvektortabelle, ... nichts zu suchen. Das gehört
ins Hauptprogramm.
In vielen Fällen ist es notwendig die Library in einen Teil mit
Konstanten und einen Teil mit dem Librarycode aufzuteilen. Die
Konstanten werden vor und der Code nach dem Hauptprogramm includiert.
>2. Die Formatierung des Quelltextes ist nun vereinheitlicht (Tabs).
Wenn es einheitlich werden soll benutzt man Leerzeichen und keine Tabs.
Denn die Tabeinstellungen können durchaus verschieden sein.
MfG Spess
Hallo Spess, danke für die Tipps! Ich werde den Code entsprechend umbauen... Grüße Ralf
Ich habe mir nun ein paar Projekte in der Codesammlung angeschaut und mich in Bezug auf die Library-Strukturierung an den Projekten von "peda" orientiert. tm1638cc.asm - der Beispielcode tm1638cc.h - Definitionen, Konstanten, Register tm1638cc.mac - Makros tm1638cc.inc - Funktionen der Library tm1638cc_font.inc - Fonts der Library tm1638cc_delay.inc - Delay-Routinen der Library Das sollte nun stimmen, oder?
Ralf J. schrieb: > Das sollte nun stimmen, oder? Ja schaut hübsch und übersichtlich aus. Ich möchte jetzt hier keine Diskussionen über Dateiendungen lostreten aber ich bin von diesem System trotzdem schon wieder weg und benenne nach Fertigstellung alles in .txt um. Das lässt sich halt von überall ohne weitere Rückfragen problemlos anzeigen und editieren. Der Dateiname bietet Raum genug für genauere Bezeichnung.
Aufgrund eines aktuellen Feedbacks hier ein Link zur aktuellen Version der Library: https://github.com/Radulfus/TM1638 Die Version hier im Board hat noch ein paar schwere Bugs, daher bitte nicht verwenden. Stattdessen einfach ein checkout bzw. clone von Github machen... Gruß Ralf
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.