0.56" 4-Digit 7-Segment Display w/I2C Backpack --- Probleme mit der Ansteuerung

Senpai

Mitglied
14. Mai 2012
143
0
16
Sprachen
  1. Assembler
Hallo
Ich habe mir jetzt oben genanntes Display im Onlineshop besorgt
und will es nun mit Assembler ansteuern.
Nun stehe ich aber Ziemlich auf dem Schlauch was die Ansteuerung angeht.
Aus dem Datenblatt des HT16K33 nicht schlau.
kennt jemand ein Tutorial das mir Weiterhelfen könnte oder einen Tipp?
danke schonmal im vorraus:D
 
Hallo
Ich habe mir jetzt oben genanntes Display im Onlineshop besorgt
und will es nun mit Assembler ansteuern.
Nun stehe ich aber Ziemlich auf dem Schlauch was die Ansteuerung angeht.
Aus dem Datenblatt des HT16K33 nicht schlau.
kennt jemand ein Tutorial das mir Weiterhelfen könnte oder einen Tipp?
danke schonmal im vorraus:D
Hi Senpai,

Cassio hat das Ding dioch schonmal in BASCOM angesteuert. Das sollte doch vom Ansteuerprinzip her portierbar sein.

Gruß
Dino
 
Hallo Senpai,

eine fertige Lösung für Assembler habe ich nicht, aber vielleicht hilft dir folgendes weiter ...


Du gehst am besten so vor:

A. TWI initialisieren
Zuerst initialisierst du TWI (I2C) Master (das wird in Assembler sicherlich noch die schwierigere Aufgabe sein).

Wenn kein Lötjumper gebrückt ist, dann hat der Displaycontroller die Adresse 0x70.

B. HT16K33 konfigurieren
Danach initialisiertst du den HT16K33, indem du folgende Werte sendest:

(1) Oszillator aktivieren (0x70+senden, Command 0x21)
(2) Blinken aus, Display an (0x70+senden, Command 0x81)
(3) Helligkeit auf maximalen Wert (0x70+senden, Command 0xEF)

Das Display ist nun an.

C. Daten senden

ACHTUNG: Nicht richtig:
Nun kannst du Daten zum Display senden. Es sind 8 Datenbyte vorhanden. Das Displaymodul nutzt die ersten 5 Bytes.
Byte 0: 1000er
Byte 1: 100er
Byte 2: Doppelpunkt (0x00 aus, 0xFF an)
Byte 3: 10er
Byte 4: 1er
Byte 5..7: nicht genutzt


Dies ist richtig:
Es sind 16 Datenbyte vorhanden. Zordnung erfolgt so:

Byte 0: nicht genutzt
Byte 1: 1000er
Byte 2: nicht genutzt
Byte 3: 100er
Byte 4: nicht genutzt
Byte 5: Doppelpunkt (0x00 aus, 0xFF an)
Byte 6: nicht genutzt
Byte 7: 10er
Byte 8: nicht genutzt
Byte 9: 1er
Byte 10..15: nicht genutzt

Daten sendest du folgendermaßen:
(1) I2C Start mit Adresse 0x70+senden
(2) Startadresse 0x00 senden
(3) 8 Datenbytes senden

Die Dekodierung für die Sieben-Segmentanzeige erfolgt nach folgender Tabelle (hier in C, aber ich denke es ist verständlich):
Code:
/*************************************************************************
 Decoding table for the seven segment display located in flash memory
*************************************************************************/
static const uint8_t numbertable[] PROGMEM = { 
    0x3F, /* 0 */
    0x06, /* 1 */
    0x5B, /* 2 */
    0x4F, /* 3 */
    0x66, /* 4 */
    0x6D, /* 5 */
    0x7D, /* 6 */
    0x07, /* 7 */
    0x7F, /* 8 */
    0x6F, /* 9 */
    0x77, /* a */
    0x7C, /* b */
    0x39, /* C */
    0x5E, /* d */
    0x79, /* E */
    0x71, /* F */
    0x00, /* clear */
};




Vielleicht hilft dir das ja schon etwas weiter.

Wenn du C kannst, dann schau dir mal das Tutorial von Adafruit (Code auf Github) an (ist für Arduino geschrieben).
Demnächst stelle ich hier eine C-Lösung (Atmel Studio 6) für das Display in das Forum.

Falls du nicht zurecht kommst, dann stelle vielleicht auch einmal deinen Assember-Code in das Forum.


Dirk :ciao:

(PS: Dankeschön, dass du im mikrocontroller-praxis.de Onlineshop bestellst. Damit unterstützt du nämlich unser Forum! :))
 
Danke ich denke jetzt seh ich klarer:rolleyes:

nix zu Danken da sind ja tolle sachen bei
habe mir letzten Monat das Developementboard Nano
besorgt und bin sehr begeistert davon;)
 
Hallo Senpai!

Zum Einen ist der BASCOM-Thread dazu HIER zu finden.
Vielleicht hilft es dir ja ein bisschen weiter, oder es bringt dich auf die Ideen.


Zum Anderen muss ich zu Dirk`s Beschreibung noch mal etwas hinzufügen. :wink:

Das INIT realisiere ich mit:
21 hex
A0 hex
EF hex
81 hex

Das A0h dient zum Einstellen des letzten Pins (Interrupt, oder normaler Output).
Da dieser Pin bei den LED`s aber nicht verwendet wird, ist die Einstellung eigentlich egal..... und kann daher auch weggelassen werden (siehe Dirk`s INIT).

Wichtig ist nur, dass du jedes Kommando einzeln zum 16K33 sendest!
Also immer: I2C-Start -> 16K33-Adresse -> Kommando -> I2C-Stop


Entgegen Dirk`s Erklärung bin ich der Meinung, dass die Doppelpunkte nicht mit FFh eingeschaltet werden, sondern mit 02h! :wink:


Grüße,
Cassio


EDIT:
Hatte ganz vergessen zu erwähnen, dass die Standardadresse für "meine" blaue LED-Anzeige aber E0h ist..... und nicht 70h, wie von Dirk geschrieben. :cool:
 
Hallo Cassio!
Entgegen Dirk`s Erklärung bin ich der Meinung, dass die Doppelpunkte nicht mit FFh eingeschaltet werden, sondern mit 02h! :wink:

0xFF setzt ebenfalls die selben Bits wie 0x02, hat somit die selbe Wirkung: Doppelpunkt geht an. :cool:

Das Routing habe ich mir nicht angeschaut, ist auch nicht notwendig, es ist dann egal, wo DP angeschlossen ist.

Ich denke mal im Code von Adafruit wird 0xFF für an und 0x00 für aus verwendet.

Es ist aber auch eigentlich egal, wenn es auch mit 0x02 geht ...


Ich hoffe mal, meine Initialisierung ist richtig. Ich habe in meinen C Projekt nachgeschaut und musste die Commandobytes errechnen, da ich mein Code etwas flexibler gestaltet habe. Also sicherheitshalber bei Cassio schauen.

Dirk :ciao:

EDIT:
Hatte ganz vergessen zu erwähnen, dass die Standardadresse für "meine" blaue LED-Anzeige aber E0h ist..... und nicht 70h, wie von Dirk geschrieben.
cool.png

Die Adresse ist nur 7bit groß.

Das erste Byte nach I2C Start setzt sich aus Deviceadresse (Bits 7..1) und Schreib-/Lesebit (Bit 0) zusammen.
Wenn man schreiben möchte, sendet man 0xE0, das entspricht 0x70(1 nach links geshiftet)+0x00.

Wie man es handhabt, kommt auf die verwendeten I2C Routinen an.
 
Es sind 8 Datenbyte vorhanden. Das Displaymodul nutzt die ersten 5 Bytes.
Byte 0: 1000er
Byte 1: 100er
Byte 2: Doppelpunkt (0x00 aus, 0xFF an)
Byte 3: 10er
Byte 4: 1er
Byte 5..7: nicht genutzt


Hallo!

Nach dem EDIT im vorherigen Beitrag, nun noch ein Nachtrag von mir..... :wink:


Ich finde die Aussage von Dirk etwas "irreführend", daher schreibe ich noch mal ein paar Zeilen dazu.

Es stimmt zwar, dass die LED-Anzeige immer nur ein Byte benötigt......
Allerdings musst du immer zwei Bytes für ein Digit senden, wenn du die Daten später am Stück zum 16K33 schicken solltest.

Das HT16K33 verwendet zwar das Autoincrement, wenn du die Daten für alle vier Digits und Doppelpunkte versendest, allerdings erwartet der Chip dann auch insgesamt 10 Bytes........ und erwartet nur in den "ungeraden" Bytes eine Info zu den LED`s. :wink:


Grüße,
Cassio
 
Hi Cassio,

ja du hast recht. Ich habe in meinem Code (uint16_t) also WORD verwendet. Ich denke in der Zuordnung sind es immer 2Byte je Digit?! (Ich habe meinen Code jetzt nicht vorliegen und im Moment auch nicht so die Zeit).

Dirk :ciao:
 
Die Adresse ist nur 7bit groß.

Das erste Byte nach I2C Start setzt sich aus Deviceadresse (Bits 7..1) und Schreib-/Lesebit (Bit 0) zusammen.
Wenn man schreiben möchte, sendet man 0xE0, das entspricht 0x70(1 nach links geshiftet)+0x00.

Wie man es handhabt, kommt auf die verwendeten I2C Routinen an.


Hallo Dirk!

Stimmt schon, mit den 7bit für die I2C-Adresse.
Ich finde die Info ohne das R/W-bit aber immer so verwirrend, daher habe ich die E0h erwähnt.

Kann aber natürlich gut sein, dass man in ASM und C die Routinen grundsätzlich so schreibt, dass erst später das letzte Bit "hinzugeshiftet" wird.
Da kenne ich mich natürlich nicht aus. :wink:


Die Ansteuerung der Doppelpunkte habe ich nur nach dem Routing genutzt.
Darum komme ich in meinem Beispielprogramm auch auf die 02h.
Wenn du aber natürlich bei dem Digit alles "einschaltest" (FFh), dann geht es natürlich auch. :cool:

Grüße,
Cassio
 
Hier noch die korrigierte Zuordnung:


Byte 0: nicht genutzt
Byte 1: 1000er
Byte 2: nicht genutzt
Byte 3: 100er
Byte 4: nicht genutzt
Byte 5: Doppelpunkt (0x00 aus, 0xFF an)
Byte 6: nicht genutzt
Byte 7: 10er
Byte 8: nicht genutzt
Byte 9: 1er
Byte 10..15: nicht genutzt
 
Muss ich denn die Adresse jedesmal als byte neu senden oder
reicht es aus wenn ich diese einmal in das Register TWAR
schreibe?

Die nicht genutzten Bytes muss ich die als 0x00 senden?
 
Muss ich denn die Adresse jedesmal als byte neu senden oder
reicht es aus wenn ich diese einmal in das Register TWAR
schreibe?

Im TWI Master Modus verwendest du das Datenregister TWDR. Das Adressregister TWAR benötigst du im Slave Modus oder wenn du einen Master hast, der durch einen anderen Master adressiert werden kann.

Die Adresse kopierst du jedesmal nach TWDR, da der Inhalt ja überschrieben wird. Bit7..1 ist die Adresse, Bit 0 ist schreiben (0) oder lesen (1).

EDIT: Ein Beispiel in Assembler habe ich leider nicht zur Hand.


Die nicht genutzten Bytes muss ich die als 0x00 senden?

Für die nicht genutzten bytes kannst du irgendwas senden, am besten einfach 0x00. Nach dem 10. Byte kannst du einfach mit I2C-STOP abbrechen, du musst nicht alle 16 Bytes senden.

Dirk :ciao:
 
Muss ich denn die Adresse jedesmal als byte neu senden oder
reicht es aus wenn ich diese einmal in das Register TWAR
schreibe?

Die nicht genutzten Bytes muss ich die als 0x00 senden?
Hi,

der UART sendet dir ja auch nicht automatich ein CRLF (Carriage Linefeed) am Zeilenende.
Die TWI-Schnittstelle hat nur ein Datenregister. Du kannst nichts zwischenspeichern. Das Register TWAR ist für den Empfang von Daten wenn der Atmel selber der Slave ist und von einem Master angesteuert wird.

The TWAR should be loaded with the 7-bit slave address (in the seven most significant bits of TWAR) to which the TWI will respond when programmed as a slave transmitter or receiver. In multimaster systems, TWAR must be set in masters which can be addressed as slaves by other masters.

Gruß
Dino
 
Ok dann hatte ich das mit dem TWAR falsch verstanden
mit dem UART hab ich noch gar nicht gearbeitet
Vielen Dank für die Hilfe:adore:
 
Habe es gerad versucht aber es will nicht so recht der ATmega8 spuckt was aus aber das Display bleibt dunkel
muss ich denn bei jedem Byte ein Start und Stop Signal senden oder nur ein Start am Anfang und ein Stop am ende?
 
Habe es gerad versucht aber es will nicht so recht der ATmega8 spuckt was aus aber das Display bleibt dunkel
muss ich denn bei jedem Byte ein Start und Stop Signal senden oder nur ein Start am Anfang und ein Stop am ende?

Die Konfigurationskommandos immer einzeln senden:

(1) I2CStart mit Adresse und R/W Bit
(2) Kommandobyte senden
(3) I2CStop

... nächstes Konfigurationsbyte (Kommando), usw.


Bei den Anzeigedaten:

(1) I2CStart mit Adresse und R/W Bit
(2) Startadresse (i.d.R 0x00)
(3) n Datenbytes
(4) I2CStop

n kann kleiner als 16 sein. n>=10 wenn alle Segmentbits geändert werden sollen.

Dirk :ciao:
 
Hallo Senpai,

beim I2C-Bus geht das folgendermaßen ...

Mit der Start-Sequenz sagst du allen Geräten auf dem Bus das nun was passieren soll.

Danach mußt du eine Adresse senden damit sich auch ein Gerät angesprochen fühlt. Bei dieser Adresse handelt es sich (normalerweise) um eine 7Bit-Adresse. Du sendest aber 8 Bit. Bit 1-7 sind die 7Bit-Adresse. Bit 0 sagt dem Gerät ob etwas vom Gerät gelesen werden soll (dann ist es ein Slave-Transmitter) oder ob etwas zum Gerät geschrieben werden soll (dann ist das Gerät Slave-Receiver). Auf jeden Fall ist das Gerät ein Slave weil der Master die Kommunikation angeschubst hat.

Nun weiß das Gerät das es angesprochen ist und was passieren soll (lesen oder schreiben). Manche Geräte haben nur ein internes 8Bit-Register (zB PCF8574 IO-Baustein). Da mußt du jetzt nur einfach das Byte senden was in das Register soll.

Wenn ein Gerät mehrere interne Register/Speicherstellen hat dann sendet man (siehe Datenblatt des ICs!!) normalerweise nun die Adresse des internen Register bei dem man anfangen will zu schreiben. Damit weiß das Gerät wo man beginnen will. ZB bei einer RTC bei den Minutenregistern. Danach schreibt man nun die Datenbytes. Das Gerät erhöht automatisch intern bei jedem Schreibvorgang die Adresse der internen Register (Autoincrement). Jedes geschriebene Byte wandert also in die nächste Registeradresse (erst Minuten-Zehner, dann die Einer, dann Stunden, ...).

Wenn man meint das nun Ende ist, dann sendet man eine Stop-Sequenz. Nun wissen alle Bausteine auf dem Bus das wieder Ruhe ist.

Wenn du zwischendurch eine Stop-Sequenz sendest dann fängst du danach wieder bei Null an (also Start, IC-Adresse, Registeradresse, 1.Datenbyte, 2.Datenbyte, ...)

Soweit erstmal. Genau wird das alles in den I2C-Referenzen von Philips beschrieben. Die PDF kann ich wirklich nur empfehlen. Und natürlich das Datenblatt des jeweiligen ICs.

Gruß
Dino
 
Habe es nun nochmal nach eurer Anweisung versucht doch leider Erfolglos:stupido3::banghead:
Zuvor hatte ichvergessen die Startadresse zu Senden.

Hier mal mei Code vielleicht seht ihr ja auf Anhieb woes klemmt

Code:
 .include"m8def.inc"

 rjmp init

 init:

 ldi r16,high(ramend)
 out sph,r16
 ldi r16,low(ramend)
 out spl,r16

 ldi r17,0xE0       ;Slave Adresse
 clr r18            ;für leerbyte

 sei                ;interrupts aktivieren


;initialisiere TWI
ldi r16,0b00000000 ;SCL Prescaler /1
out TWSR,r16
ldi r16,10         ;Bit rate generator Prescaler
out TWBR,r16


;initialisiere Slave
initslave:
rcall start
ldi r16,0x21      ;Oszillator einschalten
out TWDR,r16 
rcall waitbyte
rcall stop

rcall start
ldi r16,0x81    ;Blinken aus,Display ein
out TWDR,r16
rcall waitbyte
rcall stop

rcall start
ldi r16,0xEF   ;Display MAX Helligkeit
out TWDR,r16
rcall waitbyte
rcall stop

;Hauptprogramm
main:
rcall start

ldi r16,0x00   ;Startadresse senden
out TWDR,r16
rcall send

rcall leerbyte ;Byte0

ldi r16,0x7f   ;Byte1,1000er,8
out TWDR,r16
rcall send

rcall leerbyte ;Byte2

ldi r16,0x7f   ;Byte3,100er,8
out TWDR,r16
rcall send

rcall leerbyte ;Byte4

ldi r16,0x00   ;Byte5,Doppelpunkt,aus
out TWDR,r16
rcall send

rcall leerbyte ;Byte6

ldi r16,0x7f   ;Byte7,10er,8
out TWDR,r16
rcall send

rcall leerbyte ;Byte8

ldi r16,0x7f   ;Byte9,1er,8
out TWDR,r16
rcall send

rcall stop

rjmp main

;Unterprogramme



start:
out TWDR,r17        ;Sende Slave Adresse
ldi r16,0b10100100  ;Setze TWINT,TWSTA,TWEN 
out TWCR,r16        ;Sende Start Byte
rcall waitbyte
ret

    

send:
ldi r16,0b10000100 ;setze TWINT,TWEN
out TWCR,r16       ;Byte Senden
rcall waitbyte
ret

waitbyte:
in r16,TWCR
sbrs r16,TWINT    ;Senden erfolgt?
rjmp waitbyte
ret

stop:
ldi r16,0b10010100   ;setze TWINT,TWSTO,TWEN
out TWCR,r16         ;Sende Stop Byte
ret

leerbyte:
out TWDR,r18
rcall send
rcall waitbyte
ret
 
Ich habe dir etwas Assembler Code geschrieben (ist nicht ausgetestet), dieser macht folgendes ...

(1) I2C START Condition senden
(2) Adresse + R/W Bit senden
(3) Datenbyte/Commandobyte senden
(4) I2C Stop Condition senden

Eine Überprüfung des Statusregisters habe ich weggelassen.

Überträgst du mehrere Datenbytes, wiederholt sich Punkt (3) entsprechend. Nach einem Commando kommt direkt I2C STOP Condition.

Die Adresse mit R/W Bit musst du nach START Condition senden, so als wäre es ein Datenbyte (siehe auch deine Routine "start", dort machst du es anders).

Dirk :ciao:

EDIT: Code korrigiert

Code:
  ldi r17, 0xE0  ; Adresse + W Bit

; *** START Condition senden ***
  ldi r16, (1<<TWINT) | (1<<TWSTA) | (1<<TWEN)
  out TWCR, r16
  rcall wait_i2c

; hier kann man noch TWSR überprüfen

; *** Adresse + R/W Bit senden ***
  out TWDR, r17  ; Adresse + R/W bit
  ldi r16, (1<<TWINT) | (1<<TWEN)
  out TWCR, r16 
  rcall wait_i2c

; hier kann man noch TWSR überprüfen

; *** Datenbyte senden ***
  out TWDR, r18  ; in R18 wäre nun ein Datenbyte (nehme ich einfachheitshalber mal an)
  ldi r16, (1<<TWINT) | (1<<TWEN)
  out TWCR, r16 
  rcall wait_i2c

; hier kann man noch TWSR überprüfen

; bei einem Commando nun STOP senden, bei Daten entsprechend weitere Bytes senden, danach STOP

; *** STOP senden ***
  ldi r16, (1<<TWINT) | (1<<TWSTO) | (1<<TWEN)
  out TWCR, r16
wait_stop:
  sbis TWCR, TWSTO
  rjmp wait_stop

; ...
ret

wait_i2c:
  sbis TWCR, TWINT
  rjmp wait_i2c
ret
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)