Hallo zusammen,
ich versuche ein 4x20 China-LCD (TC2004 + PCF8574) zu betreiben. Hab
auch schon Beispielcode und Libraries dazu gefunden.
Ich hab zur Kontrolle jeweils eine LED an SDA und SCL mit drangehängt,
um zu sehen ob da überhaupt was passiert. Das Display zieht SDA und SCL
auf High, ob mit oder ohne Atmega. Der Atmega ohne Display aber nicht,
obwohl die internen Pullups an sind.
Mein Problem:
Das Programm bleibt immer beim ersten START-Signal bzw eigentlich beim
Warten auf TWINT stehen.
Ich setze "TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)" und frage dann mit
"while (!(TWCR & (1<<TWINT)))" den TWINT ab. Genau da ist Ende mit
Ablauf im Programm. Er setzt den TWINT nicht zurück, sendet also START
nicht.
Und ich weiss nicht wieso.
Der MC läuft mit intern 4Mhz, TWBR=12, TWPS=0. I2C sollte also (laut
Rechner) mit 100KHz laufen. Interrupts (SEI) an oder aus macht auch
keinen unterschied.
Ich hab TWI bzw I2C so verstanden:
1. Sende START, warte auf TWINT und Checke Rückgabewert in TWSR
2. SlaveAdresse+Write in TWDR, Sende mit "TWCR = (1<<TWINT) |
(1<<TWEN)", warte auf TWINT und Checke Rückgabewert in TWSR und Antwort
von Slave.
3. Daten in TWDR, Sende mit "TWCR = (1<<TWINT) | (1<<TWEN)", warte auf
TWINT und Checke Rückgabewert in TWSR und Antwort von Slave.
4. Sende STOP (TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN), warte auf TWINT
und Checke Rückgabewert in TWSR.
Bin gerade noch auf der Arbeit und kann dadurch keinen Code posten.
Hab ich da was falsch verstanden???
Gruss Ironlayer
@Karl M.
Indem ich die Fusebits entsprechend setze!
@Frickelfritze
Es hat ja ursprünglich auch nicht funktioniert. Die Leds hab ich im
Nachhinein erst angeklemmt, als Kontrolle!
Ich wollte es nicht schlimmer machen, sondern nur eine "optische
Anzeige" haben. Ich mach sie dann wieder weg. Wär ja ein Ding, wenns
dann geht...
Ist denn mein Verständnis der Abfolge so richtig?
Oder muss ich doch noch irgendwas Starten oder Um/Einstellen?
Armin R. schrieb:> Ist denn mein Verständnis der Abfolge so richtig?
Software in Prosa darzustellen hilft hier im Forum nichts.
Entweder du zeigst deinen Schaltplan, Aufbau und den Code,
oder du musst dir selbst weiterhelfen.
Armin R. schrieb:> Der MC läuft mit intern 4MhzKarl M. schrieb:> "MC läuft mit intern 4Mhz" wie hast Du das bei einem Atmega8 angestellt> ?Armin R. schrieb:> @Karl M.> Indem ich die Fusebits entsprechend setze!Datenblatthinweiser schrieb:> Armin R. schrieb:>> Der MC läuft mit intern 4Mhz> Welcher? Muss man dir alle Details wie Popel einzeln> aus der Nase ziehen?Armin R. schrieb:> @Datenblatthinweiser> Mein Atmega8 als TWI-Master, der das Display ansteuern soll, hängt läuft> mit 4Mhz.
:D :D :D
Ohh, dass hat Potential hier!
So, hab gestern noch die FT232-Platine bekommen und direkt mal den UART
angeworfen. Die LEDs am I2C hab ich rausgeschmissen.
Verdrahtet hab ich den Atmega8 so:
Atmgea Pin2 (PD0/RXD) --> FT232 TXD --> PC USB (Hyperterminal)
Atmgea Pin3 (PD1/TXD) --> FT232 RXD --> PC USB (Hyperterminal)
Atmgea Pin14(PB0) --> LED
Atmgea Pin27(PC4/SDA) --> PCF8574 SDA --> TC2004-LCD
Atmgea Pin28(PC5/SCL) --> PCF8574 SCL --> TC2004-LCD
Die internen Pullups für PC4 und PC5 sind an.
Den Programmer über ISP. Dazu noch Grundbeschaltung mit Kondensatoren
und 5V-Spannungsregler.
Hab nach jedem Senden eines I2C-Pakets eine Ausgabe auf den UART gemacht
(START gesendet... Slaveadresse+RW gesendet... etc).
Eine 4x7Segment-Anzeige Marke Eigenbau mit Schieberegister läuft ja
schon lange an dem Atmega, das funktioniert tadellos.
I2C ist für mich halt ziemliches Neuland. Irgendwie scheine ich das noch
nicht so ganz zu verstehen.
Ich hab einmal den vorgefertigten Code für die Display-Ansteuerung
genommen, da bleibt er schon beim ersten START-Paket bzw "while (!(TWCR
& (1<<TWINT)))" stehen.
Hab dann den PCF8574 einfach mal mit selbstgeschriebenen Befehlen
gefüttert und er bleibt zumindest NICHT bei "while (!(TWCR &
(1<<TWINT)))" stehen, der UART sendet fröhlich
"START-Adresse+RW-Daten-STOP".
Obwohl der Befehl in beiden Fällen "TWCR =
(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)" ist?!
So weit, so gut... Code folgt noch, bin wieder auf der Arbeit!
@Armin:
Frickelfritze schrieb:> Armin R. schrieb:>> Ist denn mein Verständnis der Abfolge so richtig?>> Software in Prosa darzustellen hilft hier im Forum nichts.>> Entweder du zeigst deinen Schaltplan, Aufbau und den Code,> oder du musst dir selbst weiterhelfen.
Armin R. schrieb:> Der Atmega ohne Display aber nicht,> obwohl die internen Pullups an sind.
Die internen Pullups sind nur aktiv, wenn die Pins als Eingänge
geschaltet sind. Das sind sie aber nicht, denn du willst ja TWI Master
sein. Also sollten die Pins erstmal auch als Ausgänge gesetzt werden.
Beim SCL bleibt das auch später so, während SDA auch mal Eingang werden
kann. Open Drain ist der normale Zustand beim TWI Betrieb. Externe
Pullups sind also zwingend.
Datenblatthinweiser schrieb:>> Der MC läuft mit intern 4Mhz>> Welcher? Muss man dir alle Details wie Popel einzeln> aus der Nase ziehen?
Threadtitel lesen ist nicht so dein Ding, oder?
Karl M. schrieb:> Hallo,>> "MC läuft mit intern 4Mhz" wie hast Du das bei einem Atmega8 angestellt
Dazu muss man nur das Datenblatt des Mega8 lesen. Dann sieht man
schnell, das der interne Oszillator auf 1, 2, 4 oder 8 MHz gefused kann.
Armin R. schrieb:> Die internen Pullups für PC4 und PC5 sind an.
Wie oben angemerkt, reicht das für den I²C Betrieb nicht. Mache die
bitte extern ran. 2,2k bis 4,7k sollten hier ok sein. Fig. 68 im
Datenblatt und der Text dazu beschreiben das auch.
Jetzt sieh dir das Flussdiagramm Fig. 77 an. Es wird empfohlen, TWSR zu
lesen, damit du weisst, wo es hakt. Wenn es schon beim Start klemmt,
liegt es nahe, das es die fehlenden Pullups sind.
>Also sollten die Pins erstmal auch als Ausgänge gesetzt werden.>Beim SCL bleibt das auch später so,
Das ist natürlich falsch. Der arme I2C Slave der dann
Clockstretching macht würde sich über einen auf 1 liegenden
Ausgang sicher freuen.
@Matthias Sch.
Vielen Dank für den Hinweis!!!
Das mit den internen Pullups nur bei Eingang hatte ich gar nicht
bedacht.
Wenn ich aber TWI Master bin, darf ich SDA doch trotzdem nicht auf
Ausgang stellen. Der Slave muss doch sein ACK senden können, das würde
der Master dann ja gar nicht bemerken!
Mein ursprünglicher Code war (da wurde fleissig an den UART gesendet):
Allerdings hatte ich bis gestern ja noch die LEDs an den I2C-Leitungen
und eventuell hings auch mit dem fehlenden "TWDR = 0x00;" (hatte ich
erst gestern dazugeschrieben) bei START zusammen, dass die Abfrage des
TWINT schon stehen blieb. Das macht er mit dem obigen Code ja nicht
mehr, er läuft munter im Kreis.
Das lesen des TWSR (soweit hatte ich auch schon gedacht) hat gestern
auch immer ergeben, dass nichts gesendet wird:
1
#define F_CPU 4000000UL
2
#include<avr/io.h>
3
#include<stdint.h>
4
#include<util/delay.h>
5
#include<util/twi.h>
6
#include<uart.h>
7
8
#define BAUDRATE 9600UL
9
#define CR "\r\n"
10
11
//Funktionen Prototypen
12
voidUart_init();
13
voidPort_init();
14
voidI2C_init();
15
voiduart_send_string(constchar*s);
16
17
voidmain()
18
{
19
Uart_init();
20
Port_init();
21
I2C_init();
22
23
uart_send_string("Programmstart...");
24
uart_send_string(CR);
25
26
while(1)
27
{
28
//START senden
29
TWDR=0x00;
30
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
31
while(!(TWCR&(1<<TWINT)));
32
if((TWSR&0xF8)!=START)
33
{
34
uart_send_string("Start NICHT gesendet");
35
}
36
else
37
{
38
uart_send_string("Start gesendet");
39
}
40
uart_send_string(CR);
41
_delay_ms(100);
42
43
//Adresse incl RW senden
44
TWDR=0b01110000;
45
TWCR=(1<<TWINT)|(1<<TWEN);
46
while(!(TWCR&(1<<TWINT)));
47
if((TWSR&0xF8)!=MT_SLA_ACK)
48
{
49
uart_send_string("Slaveadresse+RW NICHT gesendet");
Ich werde erst morgen Abend wieder dazu kommen, etwas zu tüfteln.
Spendiere dem I2C dann mal ein paar externe Pullups und schau was
passiert.
Der obige Code soll übrigens nur zum Testen des I2C-Busses bzw des
PCF8574 dienen, nicht dem Display selber!
Bin wie gesagt auf der Arbeit und morgen, wegen Ausfall, noch länger :(
Gruss Ironlayer
dummy schrieb:> Das ist natürlich falsch. Der arme I2C Slave der dann> Clockstretching macht würde sich über einen auf 1 liegenden> Ausgang sicher freuen.
Datenblatt lesen. Das Management der TWI Pins wird nach dem Init des TWI
Blocks von diesem übernommen und auf OpenDrain geschaltet. Da ist dem
I²C Slave ein Clockstretching völlig unbenommen. Eine 1 lässt einfach
nur SDA los (Wired OR).
Ein Slave wie der PCF8574 probiert auch gar nicht erst, irgendwas auf
low zu ziehen, wenn er nicht angesprochen wurde.
Nur eben die internen Pullups des Mega laufen auch nicht, man muss
extern hochziehen.
Matthias S. schrieb:> Ein Slave wie der PCF8574 probiert auch gar nicht erst, irgendwas auf> low zu ziehen, wenn er nicht angesprochen wurde.
Ohne den PCF8574 (also nur der Atmega verbunden) waren die LEDs am I2C
bei mir auch aus. Mit dem PCF8574 sind die LEDs sofort angegangen und
haben sich nicht mehr gerührt, also kein flackern oder so.
Heisst aber doch eigentlich, dass er das Pullup des Busses übernimmt.
Dann hätte es ja trotzdem funktionieren sollen, oder?!
Naja, mal abgesehen von den LEDs am Bus ;)
Armin R. schrieb:> Heisst aber doch eigentlich, dass er das Pullup des Busses übernimmt.> Dann hätte es ja trotzdem funktionieren sollen, oder?!
Nö. Der PCF8574 ist ein Chip des Erfinders von I²C und hält sich an die
Specs. Evtl. hattest du die Masse des Chips in der Luft? Pullups sind an
jedem TWI/I²C Bus ein Muss. Du kannst aber notfalls auch deine LEDs mal
gegen Plus statt Masse legen, dann übernehmen sie teilweise die Pullup
Funktion.
Nee, Masse hängt nicht in der Luft. GND und 5V beide mit dem Atmega
verbunden.
Die LEDs am Buss lass ich mal lieber weg, hab ja genügend Widerstände
rumfliegen.
Sind die Pullups nur bei Mastern oder auch bei Slaves pflicht? Wenn auch
bei Slave PCF8574, dann macht er den Job ja schon...
Oder doppelt gemoppelt hält besser :)
Ich häng auf jedenfall heut Abend mal die Pullups drann und schau was
passiert!
Armin R. schrieb:> Sind die Pullups nur bei Mastern oder auch bei Slaves pflicht?
Die sind auf dem Bus Pflicht, also auf jeder Leitung einer. Es geht hier
nicht um Terminierung (I²C ist ein geräteinterner Bus für kurze
Entfernung), sondern um Pegel.
Mal eine ganz einfahe Frage. Lese was vom I2C Bus. Ist dazu eine Baud
einstellung notwendig? Wozu wird dabei uart verwendet? Kenne es immer
mit den datein von Peter, so wie TWImaster und so.
Vielleicht habe ich was verpasst in der Schule
Lehrling schrieb:> Wozu wird dabei uart verwendet?
Ein UART geht nicht, es muss der USART sein, wie er z.B. in einigen AVR
verbaut ist - TWI/I²C ist nämlich ein synchroner Bus mit Takt und Daten.
Eine Baudeinstellung in dem Sinne gibt es nicht, aber einen
ursprünglichen Standard von max. 100kHz Takt. Mittlerweile gibt es auch
schnellere Bausteine, die 400kHz Takt unterstützen. Da I²C aber synchron
ist, ist ähnlich wie bei SPI, der Takt in weiten Grenzen variabel. Man
kann also auch mit 2kHz I²C betreiben.
Das da in irgendeiner Form ein Pullup an jede Leitung muss ist mir schon
klar.
Ich meine ja nur, da der PCF8574 ja den Bus schon "hochzieht" (also da
vermutlich schon "externe" Pullups drauf sind) sind meine externen ja im
Prinzip überflüssig. Oder nicht?
Armin R. schrieb:> Ich meine ja nur, da der PCF8574 ja den Bus schon "hochzieht" (also da> vermutlich schon "externe" Pullups drauf sind)
Der Chip selber hat mit Sicherheit keine Pullups. Ob dein Adapterboard
welche drauf hat, kann ich von hier aber nicht sehen :-P
So. Endlich bin ich ne Ecke weiter...
Die Pullups haben offensichtlich was gebracht.
Hab noch lange probiert das Display anzusprechen, da die Slaveadresse
immer falsch war. Im Datenblatt des PCF steht ja 0111 als Basis und A2
A1 A0 als Useradresse. Bei mir sind A2-0 nicht geschlossen, also bin ich
von LOW ausgegangen. Ich doof hab immer 0b01110000 geschickt. Die
Adresse ist aber 0b01111110, da offene Brücken HIGH bedeuten!
Jetzt hab ich das Display schon mit der Hintergrundbeleuchtung blinken
lassen, als Test.
Mein nächstes Problem ist aber die Kommunikation mit dem TC2004 selbst.
Im Datenblatt werden ja Einstell- bzw Kontrollbits mit 8-Bit aufgeführt.
Mein Display ist aber nur mit D0-D3 mit dem PCF verbunden, also D4-D7
sind nicht verlötet.
Die Initilisierung des Displays (laut Datenblatt) bewirkt ein kurzes
Ein- und Ausschalten der Beleuchtung.
Muss ich mir nochmal die LCD Libraries genauer anschauen!
Aktuell funktionierender I2C-Code folgt noch...
Chris F. schrieb:> Wie der ATMega8(??) ohne externen Oszillator mit 4MHz intern läuft,> durch fuses, habe ich immernoch nicht begriffen.
Wie wäre es mit den Fuses?
Hilfestellung gibt es hier: http://www.engbedded.com/fusecalc/
Chris F. schrieb:> Wie der ATMega8(??) ohne externen Oszillator mit 4MHz intern läuft,> durch fuses, habe ich immernoch nicht begriffen.
Datenblatt S. 30
Chris F. schrieb:> Wie der ATMega8(??) ohne externen Oszillator mit 4MHz intern läuft,> durch fuses, habe ich immernoch nicht begriffen.
Schau mal ins Datenblatt Seite 30 (Calibrated internal RC Oscilator).
Da steht alles, was man wissen muss ;)
Oder wenn du es bequemer haben willst gibts auch ne Website, die dir die
Einstellung fertig darlegt:
www.engbedded.com/fusecalc/
Die nutze ich auch gerne. Wenn du, so wie ich, mit PonyProg flashst,
kannst du die Häkchen genau so setzen, wie da zu sehen. Ansonsten das
Hellgrau gedruckte lesen, die Bits sind invertiert...
Edit: UPS... da war jemand schneller :p
Okay, also geht das mit avrdude, oder Pony und den Fuses aus dem
Kalkulator. In Atmelstudio bekomme ich beim 8, 8A, 8L, 644 und 644V
nämlich nur "Int RC osc" und "int RC osc mit 128kHz".
Ich habe mal davon einen Screenshot gemacht.
Danke für den Hinweis und: Gute Nacht zusammen.
Hallo nochmal.
Ich häng schon wieder fest...
Ich muss ja das TC2004 mit 4Bit ansprechen, da der PCF ja nur mit 4
Datenleitungen mit dem LCD verbunden ist.
Die Initialisierung wie im Datenblatt scheint zu funktionieren, es
schaltet auf 4 Zeilen (kann man leicht die Pixel erkennen). Wo es noch
nicht funktionierte, hats nur 2 Zeilen gehabt.
Im Datenblatt finde ich aber keinen Hinweis, wie ich Daten in 4Bit da
reinschiebe (manuel, ohne Library).
Hab auch schon ein paar Libs durchgeschaut, steige aber irgendwie nicht
dahinter.
Das Bit7 zum Beispiel ist ja zum setzen der DDR Ram Adresse, da komme
ich ja mit 4Bit garnicht so drann.
Hat da jemand Erfahrung mit?
Armin R. schrieb:> Ich häng schon wieder fest...> Ich muss ja das TC2004 mit 4Bit ansprechen, da der PCF ja nur mit 4> Datenleitungen mit dem LCD verbunden ist.
Du redest die ganze Zeit von PCF8574, adressierst aber PCF8574A !
Für PCF8574 ist die richtige Adresse:
0b0100xxx0 oder 0x4x
Für PCF8574A ist die richtige Adresse:
0b0111xxx0 oder 0x7x
Welche von beiden hast du nun ?
Marc V. schrieb:> Welche von beiden hast du nun ?
Ich hab den PCF8574A auf dem Display. Die Ansteurung desjenigen
funktioniert ja! Slaveadresse ohne geschlossene A0-A2 ist auch
0111111+0(rw)
Das Display reagiert ja auf meine Daten, also Beleuchtung an/aus und
Anzahl der Zeilen etc...
Ich bekomme halt nichts angezeigt, nicht einmal nen Cursor oder
wenigstens nen Pixel. Nichts.
Das liegt vermutlich an meinem Unverständnis der Datenverarbeitung des
Displays (nicht des PCF8574A) im 4Bit-Mode!
Armin R. schrieb:> Mein nächstes Problem ist aber die Kommunikation mit dem TC2004 selbst.> Im Datenblatt werden ja Einstell- bzw Kontrollbits mit 8-Bit aufgeführt.> Mein Display ist aber nur mit D0-D3 mit dem PCF verbunden, also D4-D7> sind nicht verlötet.
Probiere es mal mit D4...D7 als Datenbus und lasse D0...D3 frei, dann
sollte es eigentlich funktionieren:
http://www.pollin.de/shop/downloads/D120687D.PDF (Seite 7,(2) MPU
INTERFACE 4-bit/8-Bit) ;-)
Armin R. schrieb:> Ich hab den PCF8574A auf dem Display. Die Ansteurung desjenigen> funktioniert ja! Slaveadresse ohne geschlossene A0-A2 ist auch> 0111111+0(rw)>> Das Display reagiert ja auf meine Daten, also Beleuchtung an/aus und> Anzahl der Zeilen etc...
Wie, Beleuchtung an/aus ?
Seit wann wird das mit Befehlen gesteuert ?
Schreib doch mal wie RS, E, R/W und D7-D4 angeschlossen sind.
Op schrieb:> Der kontrast ist schon richtig eingestellt, oder? :D
Ja, ist er. Man kann ja die Pixel leicht "leuchten" sehen. Hab auch
schon am Poti gedreht :)
Thomas S. schrieb:> Probiere es mal mit D4...D7 als Datenbus und lasse D0...D3 frei, dann> sollte es eigentlich funktionieren
Sorry, mein Fehler. Habe ja auch D4-D7 verbunden. Ist ja ein fertiges
Modul, LCD mit aufgelöteter PCF-Platine.
Marc V. schrieb:> Schreib doch mal wie RS, E, R/W und D7-D4 angeschlossen sind.
Also, Pinbelegung (nachgemessen):
LCD RS -» PCF P0
LCD RW -» PCF P1
LCD E -» PCF P2
LCD D4 -» PCF P4
LCD D5 -» PCF P5
LCD D6 -» PCF P6
LCD D7 -» PCF P7
PCF P3 liegt frei!
Marc V. schrieb:> Wie, Beleuchtung an/aus ?> Seit wann wird das mit Befehlen gesteuert ?
Wenn ich z.B. 0b00001000, 0b00001100, 0b00001110 oder 0b00001111 sende,
geht die Hintergrundbeleuchtung an. Lasse ich aber das D4-Bit weg (z.B.
0b11110111) geht die Beleuchtung aus.
Thomas S. schrieb:> (Seite 7,(2) MPU> INTERFACE 4-bit/8-Bit) ;-)
Das hatte ich auch schon gelesen, aber irgendwie bekomme ich das so
nicht hin!
Meine Initialisierung habe ich im Moment wie folgt(vereinfacht
geschrieben):
_delay_ms(15)
//Versuch 1: 4Bit-Modus
0b00101100
_delay_ms(5)
0b00001100
//Versuch 2: 4Bit-Modus
0b00101100
_delay_ms(1)
0b00001100
//Versuch 3: 4Bit-Modus
0b00101100
_delay_ms(1)
0b00001100
//Set 4-Line/5x8 Pixel
0b00101000
_delay_ms(1)
0b00001000
//Set Increment Address/Cursor Shift
0b00100110
_delay_ms(1)
0b00000110
Armin R. schrieb:> PCF P3 liegt frei!
Glaub ich nicht. Die Module die ich kenne haben dort
einen Transistor angeschlossen der die LED-Background
Beleuchtung schaltet.
Armin R. schrieb:> Hab ich das mit dem Enable(E)-Pin irgendwie falsch verstanden?
Deinem "Code" nach zu urteilen schon.
Das Enable Bit muss für jedes Nibble das du an das LCD
schickst einmal ein und wieder ausgeschaltet werden.
1
PCF_val&=0x0F;/* Steuerbit belassen wie sie sind */
2
/* und Nibble rücksetzen */
3
PCF_val|=nible_to_write;/* nibble in bit 7..4 */
4
byte_an_PCF_schreiben(PCF_val);
5
/* LERR */
6
/* nWS */
7
PCF_val|=0b00000100;/* set Enable high */
8
byte_an_PCF_schreiben(PCF_val);
9
_delay_us(2)
10
PCF_val&=~0b00000100;/* set Enable low */
11
byte_an_PCF_schreiben(PCF_val);
Delays braucht man eigentlich nicht zu benutzen da über
den PCF alles so langsam ist dass sich die Delays von
selbst ergeben.
Bei der ganzen Steuerei muss auch das R/W Bit und das
Register Select Bit natürlich immer richtg stehen .....
Das ist jetzt im meinem Bespiel Code nicht enthalten.
Frickelfritze schrieb:> Glaub ich nicht. Die Module die ich kenne haben dort> einen Transistor angeschlossen der die LED-Background> Beleuchtung schaltet.
Stimmt. Habs nachgemessen, geht zum Transistor am Jumper für die
Beleuchtung.
Hatte nur die Verbindingen zu den Lötpins gemessen und da geht er ja
nicht hin ;)
Frickelfritze schrieb:> Das ist das D3 Bit. Die Zählweise hier ist immer 0...7
Weiss ich, sorry. Die blöden Flüchtigkeitsfehler...
Frickelfritze schrieb:> Das Enable Bit muss für jedes Nibble das du an das LCD> schickst einmal ein und wieder ausgeschaltet werden.
Also muss ich erst die Daten schicken, dann Enable1 und Enable0?
Alles nacheinander, also 3x senden?
Ich dachte, das Enable muss MIT den Daten aktiviert sein! Und
deaktivieren zum übernehmen!
Armin R. schrieb:> Also muss ich erst die Daten schicken, dann Enable1 und Enable0?> Alles nacheinander, also 3x senden?> Ich dachte, das Enable muss MIT den Daten aktiviert sein! Und> deaktivieren zum übernehmen!
Nein.
Da du mit 4-bit arbeitest, müssen die Nibbles getauscht werden.
Also:
// LowNibble senden
High- und Low-Nibble tauschen
Byte zum PCF
Enable HIGH
1us warten
Enable LOW
1us warten
// HighNibble senden
High- und Low-Nibble tauschen
Byte zum PCF
Enable HIGH
1us warten
Enable LOW
1us warten
Am besten du schreibst dir eine Routine die das macht und nennst
diese LcdEnable(), etwa so:
1
{
2
PCF->xxxx-x1xx
3
delay1us
4
PCF->xxxx-x0xx
5
delay1us
6
}
Und eine, die deine Bytes rausschickt:
1
{
2
NibbleSwap();
3
LcdEnable();
4
NibbleSwap();
5
LcdEnable();
6
}
Dann brauchst du noch eine Routine, die RS auf LOW oder HIGH setzt,
je nachdem ob du DATA oder CMND schreiben willst und das war es dann
schon.
DATA braucht kein delay, CMND (z.B. CLEAR DISPLAY, HOME usw.) schon,
bis zu 2-3 ms.
Armin R. schrieb:> Ich dachte, das Enable muss MIT den Daten aktiviert sein! Und> deaktivieren zum übernehmen!
Muss nicht, aber kann. Die Fluss-Steuerung ist flanken-getriggert,
nicht zustands-getriggert. Die fallende Flanke von Enable übergibt
Daten an das LCD.
Warum liest du nicht das Datenblat eines HD44780, dem Urvater aller
(kompatiblen) Controller, dort steht alles geschrieben.
Marc V. schrieb:> // LowNibble senden> ............> // HighNibble senden
Käse.
Auszug aus dem Datenblatt der HD44780:
"As for the order of data transfer, the four high order bits
(for 8-bit operation, DB4 to DB7) are transferred before the
four low order bits (for 8-bit operation, DB0 to DB3)."
Frickelfritze schrieb:> Ja ..... das ist schön gruselig .....
Naja. Eigenbau halt, mit Streifen-Lochraster ;)
Ist ja alles nur zum tüfteln. Solange es funktioniert!
Wenn dann alles so läuft, wie ichs mir vorstelle, dann gibts ne neue
Platine...
@Marc Vesely und Frickelfritze
Danke für die Tipps!!
Ich habs, glaube ich, jetzt verstanden.
Werde mich heut Abend mal daran machen...
Sag mal, habe ich Augenkrebs oder hast Du da genau 3 Pins des
PCF8574-Moduls mit dem Display verbunden / angelötet?
DSC_1009.JPG.jpg
Poste doch bitte mal den Schaltplan vom Display-Anschluss.
Dieter F. schrieb:> habe ich Augenkrebs
Ja, hast du. Und keine Ahnung von diesen Modulen.
Das Display ist 1:1 mit dem I2C Modul (wo der PC8574 drauf
ist) verbunden. Das sind 16 Steckverbindungen auf einer Steckerleiste.
Vom I2C Modul gehen 4 Leitungen zum Prozessor:
GND, Vcc, I2C_Clock und I2C_Data.
Frickelfritze schrieb:> Ja, hast du. Und keine Ahnung von diesen Modulen.
O.K. das hast Du ja jetzt festgestellt. Wo sind denn die Anschlüsse des
LC-Displays auf dem Bild?
Ich meine genau da, wo das Modul drauf sitzt. Falls nicht, berichtige
mich bitte. Dann kannst Du mir blindem Huhn auch erzählen, wie viele
Lötstellen Du da siehst.
Dieter F. schrieb:> O.K. das hast Du ja jetzt festgestellt. Wo sind denn die Anschlüsse des> LC-Displays auf dem Bild?>> Ich meine genau da, wo das Modul drauf sitzt. Falls nicht, berichtige> mich bitte. Dann kannst Du mir blindem Huhn auch erzählen, wie viele> Lötstellen Du da siehst.
Es ist ein fertiges Modul welches 1:1 auf LCD geht und von AVR per I2C
angesteuert wird. Deswegen kann er auch Hintergrundbeleuchtung mit
einem Pin aus- oder einschalten.
Sein AVR sitzt auf der Lochrasterplatine.
Frickelfritze schrieb:> Ja, hast du. Und keine Ahnung von diesen Modulen.
Dass du zufällig mehr über diese Module weisst als er, gibt dir nicht
das Recht, sich so überheblich auszudrucken.
Frickelfritze schrieb:> Käse.
Kein Käse, wenn ich mit 4-bit arbeite, verbinde ich Port0-Port3 mit
LCD4-Lcd7. Deswegen mache ich zuerst Nibbleswap.
Bei diesem Modul ist PCF7 mit LCD7 verbunden es geht bei erstem
Nibble auch ohne.
Marc V. schrieb:> Kein Käse, wenn ich mit 4-bit arbeite,
Voll der Käse.
.... um so schlimmer dass du nicht einmal verstehst was da
geschrieben steht. Mit LowNibble/Highnibble senden erzeugst
du absolut nur Käse auf dem Display. Aber du wirst es wohl
nie verstehen.
Frickelfritze schrieb:> Marc V. schrieb:>> Kein Käse, wenn ich mit 4-bit arbeite,>> Voll der Käse.>> .... um so schlimmer dass du nicht einmal verstehst was da> geschrieben steht. Mit LowNibble/Highnibble senden erzeugst> du absolut nur Käse auf dem Display.
LowNibble/HighNibble steht nur als Kommentar, es wird zuerst
HighNibble und dann LowNibble ausgegeben.
Frickelfritze schrieb:> Aber du wirst es wohl nie verstehen.
Ich habe es schon verstanden und damit gearbeitet als du zum
ersten Mal in der Grundschule sitzengeblieben bist.
Marc V. schrieb:> LowNibble/HighNibble steht nur als Kommentar
Ach so, du schreibst also einen Kommentar zu einem Codeblock
wo der Kommentar nicht hingehört. Respekt! Da kann ich nur sagen:
Der arme TO der sich deinen Käse antun muss.
Marc V. schrieb:> Also:> // LowNibble senden> High- und Low-Nibble tauschen> Byte zum PCF> Enable HIGH> 1us warten> Enable LOW> 1us warten> // HighNibble senden> High- und Low-Nibble tauschen> Byte zum PCF> Enable HIGH> 1us warten> Enable LOW> 1us warten
Dieter F. schrieb:> Sag mal, habe ich Augenkrebs oder hast Du da genau 3 Pins des> PCF8574-Moduls mit dem Display verbunden / angelötet?
Ich weiss, was gemeint ist :)
Der PCF ist original so bei mir aus der Verpackung gekommen. Er ist
total schief eingelötet. Heisst, die linken Pins sind etwas weiter
durchgesteckt als die Rechten.
Die drei gemeinten Lötstellen auf dem Bild sind die, wo beim Löten von
der Oberseite das Lot zur Unterseite durchgelaufen ist. Es sind aber
alle 16 Pins verlötet, nur nicht bei allen auf die Rückseite
durchgelaufen!
Die Chinesen habens anscheinend nicht so mit Genauigkeit. Ausserdem hat
das LCD blos 5€ inkl Versand gekostet, da erwarte ich nicht absolut
gleichmässige Lötstellen.
Jetzt streitet euch doch nicht! Ich bin gerade dabei hier meinen Code
umzuschreiben. Dann kann ich ja später berichten, was bei meinem LCD
funktioniert ;)
Armin R. schrieb:> Jetzt streitet euch doch nicht!
Ich streite nicht - möchte nur wissen, was korrekt ist.
Marc V. schrieb:> Es ist ein fertiges Modul welches 1:1 auf LCD geht und von AVR per I2C> angesteuert wird. Deswegen kann er auch Hintergrundbeleuchtung mit> einem Pin aus- oder einschalten.
O.K. - das (das es ein fertiges Modul ist) war so für mich nicht zu
erkennen - aber es steht ja auch im Eintgangpost ... :-(
Armin R. schrieb:> ich versuche ein 4x20 China-LCD (TC2004 + PCF8574)
insofern mea culpa
Armin R. schrieb:> Die drei gemeinten Lötstellen auf dem Bild sind die, wo beim Löten von> der Oberseite das Lot zur Unterseite durchgelaufen ist. Es sind aber> alle 16 Pins verlötet, nur nicht bei allen auf die Rückseite> durchgelaufen!
Prima, dann brauche ich ja keine Brille mehr :-)
Morgen, wenn ich die Zeit finde (ich gehe davon aus) spiel ich das mal
nach ...
Frickelfritze schrieb:> Ach so, du schreibst also einen Kommentar zu einem Codeblock> wo der Kommentar nicht hingehört. Respekt! Da kann ich nur sagen:> Der arme TO der sich deinen Käse antun muss.
Hab gerade meinen alten CAN Sniffer rausgeholt, und Codeblock
ausprobiert. Es scheint zu funktionieren, obwohl Kommentare falsch
sind. Sogar mit 128x64. Unglaublich.
Nur der Text auf dem Display nervt mich ein bisschen...
Kannst du mir mit deinen LCD-Kenntnissen helfen ?
So. Da bin ich wieder :-)
Mein LCD mag die Daten wohl Low-, dann High-Nibble.
Ich bekomme es trotzdem nicht richtig konfiguriert!
Ich sende die Initialisierung laut Datenblatt:
20ms pause
0b00110000 //init1
5ms pause
0b00110000 //init2
1ms pause
0b00110000 //init3
1ms pause
0b00100000 //set to 4bit-mode
Danach steht das LCD auf 2Line.
Dann sende ich
0b00100000 //4bit-2line-5x8
und es stellt auf 4line5x8 mit blinkendem Cursor an Zeile1 Position2
Sende ich dann direkt
0b00000010 //cursor home
stellt es auf 2line5x8 mit dem blinkenden Cursor an Zeile1 Position2
Sende ich aber cursor home erst 3Sekunden später, stellt es nur auf
2line5x8, ohne cursor...
Mein Sende-Code ist übrigens folgender (verwende ich nach
Initialisierung):
Armin R. schrieb:> Was mache ich falsch????
Du hast grundsätzlich nicht verstanden dass das
gesamte Byte das am LCD ansteht nur durch Ver-odern
und Ver-undung geändert werden soll.
Armin R. schrieb:
1
I2C_Send_Data(Data,2);
2
I2C_Send_Data(0b00001000,2);//Led=1,E=0
Erzeugt eine fallende Flanke von Enable bei der die
Daten am LCD auf Null wechseln. Was willst du damit
erreichen? Hast du mein Code-Beispiel nicht verstanden?
"Interessant" wäre auch noch was der 2 Parameter beim
Aufruf von <I2C_Send_Data> soll.
Armin R. schrieb:> Mein LCD mag die Daten wohl Low-, dann High-Nibble.
Du hast mich voll überzeugt. Die ganze (LCD-)Welt verlangt
es umgekehrt, nur deines nicht.
Frickelfritze schrieb:> Du hast grundsätzlich nicht verstanden dass das> gesamte Byte das am LCD ansteht nur durch Ver-odern> und Ver-undung geändert werden soll.
Ok. Also so:
1
voidI2C_Write_4Bit_Set(intcmd)
2
{
3
intData;
4
//Low-Nibble
5
Data=((cmd&0b00001111)<<4);
6
Data|=(1<<2)|(1<<3);//Led=1,E=1
7
I2C_Send_Data(Data,2);
8
Data&=~(1<<2);//E=0
9
I2C_Send_Data(Data,2);
10
//High-Nibble
11
Data=(cmd&0b11110000);
12
Data|=(1<<2)|(1<<3);//Led=1,E=0
13
I2C_Send_Data(Data,2);
14
Data&=~(1<<2);//E=0
15
I2C_Send_Data(Data,2);
16
}
Frickelfritze schrieb:> "Interessant" wäre auch noch was der 2 Parameter beim> Aufruf von <I2C_Send_Data> soll.
Das ist einfach nur ein Delay_ms!
Frickelfritze schrieb:> Du hast mich voll überzeugt. Die ganze (LCD-)Welt verlangt> es umgekehrt, nur deines nicht.
Ich habs halt in beiden Varianten versucht und bei Low/High kam
wenigstens ein Cursor ;-)
Mit der "neuen" Send-Funktion geht das LCD nach Init und Set4Bit4Line5x8
zwar in 4Line, nimmt aber danach keine Daten mehr an. Egal ob H/L oder
L/H...
Armin R. schrieb:> Ich habs halt in beiden Varianten versucht und bei Low/High kam> wenigstens ein Cursor ;-)> Mit der "neuen" Send-Funktion geht das LCD nach Init und Set4Bit4Line5x8> zwar in 4Line, nimmt aber danach keine Daten mehr an. Egal ob H/L oder> L/H...
Wenn du es schon selber machen willst, ich habs mal auf die schnelle
von ASM umgeschrieben, sollte funktionieren:
1
#define RS 0
2
#define RW 1
3
#define EN 2
4
#define LED 3
5
6
voidI2C_CtrlByt(uint8_tcmd)
7
{
8
uint8_tData;
9
Data=cmd&0xF0;
10
Data|=((1<<EN)|(1<<LED));
11
I2C_Send_Data(Data,5);// 5 steht fur ms delay
12
Data&=~(1<<EN);
13
I2C_Send_Data(Data,5);
14
15
Data=cmd<<4;
16
Data|=((1<<EN)|(1<<LED));//Led=1,E=1
17
I2C_Send_Data(Data,5);
18
Data&=~(1<<EN);// E=0
19
I2C_Send_Data(Data,5);
20
}
21
22
23
intmain(void)
24
{
25
// ******************
26
// 200ms Pause
27
// ******************
28
29
I2C_CtrlByt(3);
30
I2C_CtrlByt(3);
31
I2C_CtrlByt(3);
32
// ******************
33
// 20ms Pause
34
// ******************
35
36
I2C_CtrlByt(0x28);
37
I2C_CtrlByt(0x06);
38
I2C_CtrlByt(0x0C);
39
I2C_CtrlByt(0x01);
40
// ******************
41
// 20ms Pause
42
// ******************
43
}
Wenn es klappt, brauchst du noch eine Routine fur Data, mit RS = 1.
Oder du änderst die Ausgaberoutine (+ Parameter fur CTRL/DATA).
Aber warum probierst du nicht die Library von Falk ?
Armin R. schrieb:> Ich habs halt in beiden Varianten versucht und bei Low/High kam> wenigstens ein Cursor ;-)
Vorsicht!
Marc Vesely besteht in seinem Code-Vorschlag plötzlich darauf
das High Nibble zuerst und dann das Low Nibble zu senden. Wie
sich die Zeiten doch ändern ....
Du willst aber unbedingt die andere Version!
Frickelfritze schrieb:> Vorsicht!>> Marc Vesely besteht in seinem Code-Vorschlag plötzlich darauf> das High Nibble zuerst und dann das Low Nibble zu senden. Wie> sich die Zeiten doch ändern ....
LOL.
Du Armer.
Marc V. schrieb:> Wenn du es schon selber machen willst, ich habs mal auf die schnelle> von ASM umgeschrieben, sollte funktionieren:
Habs gerade ausprobiert. Da rührt sich garnichts am Display!
Es Initialisiert sich noch nicht einmal. Denn I2C_CtrlByt(3) bewirkt ja,
dass auch das Enable mit gesetzt bzw gelöscht wird. Bei der
Initialisierung aber wohl nicht vorgesehen. Das hatte ich bei meiner
Initialisierung auch schon probiert!
Im Prinzip is deine Funktion ja ähnlich meiner!
Marc V. schrieb:> Aber warum probierst du nicht die Library von Falk ?
Ich wills ja auch verstehen, was da genau passiert. Nicht nur "schicke
xy an LCD" schreiben.
Frickelfritze schrieb:> Du willst aber unbedingt die andere Version!
Mir gehts nicht um irgendeine Version. Ob H/L oder L/H wäre mir ja
völlig egal. An der Initialisierung im Datenblatt kann man ja auch
erkennen, dass H/L stimmen sollte. Aber MEIN Display zickt dabei rum und
ich weiss nicht wieso.
Ich versuche alle Tipps umzusetzen, aber bisher erfolglos...
@ Armin R. (ironlayer)
>> Aber warum probierst du nicht die Library von Falk ?>Ich wills ja auch verstehen, was da genau passiert. Nicht nur "schicke>xy an LCD" schreiben.
Dann nutze erstmal meine Lib und bring es zum laufen. Wenn das geht,
weißt du daß deine hardware in Ordung ist. Dann kannst du deine Software
debuggen.
Armin R. schrieb:> Denn I2C_CtrlByt(3) bewirkt ja,> dass auch das Enable mit gesetzt bzw gelöscht wird. Bei der> Initialisierung aber wohl nicht vorgesehen.
Falsch. Enable muss bei jedem Nibbble betätigt werden, auch
bei der Initialisierung. Da hatte ich dir schon einmal
erklärt (vielleicht doch mal Datenblatt lesen und verstehen
lernen?):
Frickelfritze schrieb:> Das Enable Bit muss für jedes Nibble das du an das LCD> schickst einmal ein und wieder ausgeschaltet werden.
So, hab jetzt das Projekt von Falk auf MC gespielt und es läuft 1A. Also
LCD ist in Ordnung.
Frickelfritze schrieb:> Enable muss bei jedem Nibbble betätigt werden, auch> bei der Initialisierung.
Hab jetzt mal alles mit E_on und E_off geschickt. Jetzt bekomme ich
manchmal ein 4Line mit Cursor NoBlink hin, beim Neustart des MC (mit dem
selben Hex) bleibt er auf 2Line mit BlinkCursor???????
Steh ich schon so aufn Schlauch?
Armin R. schrieb:> Steh ich schon so aufn Schlauch?
Ich denke du hast noch nicht verstanden dass bei der
Initialisierung (siehe Datenblatt) zuerst Nibbles
geschrieben werden und dann nach Umschaltung in den
richtigen Mode Bytes nibble-weise.
1
/* ------ Init -------- */
2
3
LCD_WriteNibble(0x30,0);/* Init laut Datenblatt */
4
_delay_ms(50);
5
6
LCD_WriteNibble(0x30,0);
7
_delay_ms(50);
8
9
LCD_WriteNibble(0x30,0);
10
_delay_ms(50);
11
12
LCD_WriteNibble(0x20,0);/* Pos 0x10 --> 0 4 Bit Interface */
13
_delay_ms(50);
Wobei der Parameter 0 das RS Bit wiederspiegelt.
Warum? Weil nach dem Einschalten das LCD auf 8 Bit steht und
man ihm damit keine 2 Nibbles für ein Steuerwort hintereinander
schicken kann. Daher ist die Init-Kommandierung per LCD-
Implementierung auf die oberen 4 Bits beschränkt. Die unteren
werden aber ohne bestimmten Wert mitgeschrieben.
Frickelfritze schrieb:> Ich denke du hast noch nicht verstanden dass bei der> Initialisierung (siehe Datenblatt) zuerst Nibbles> geschrieben werden und dann nach Umschaltung in den> richtigen Mode Bytes nibble-weise.
Wenn auch nur ungern, aber ich muss ihm Recht geben.
Deswegen klappt auch die (schlecht) übersetzte Initsequenz von
mir nicht.
Wenn du willst, kann ich dir die 1:1 ASM=>C senden.
Frickelfritze schrieb:> Ich denke du hast noch nicht verstanden dass bei der> Initialisierung (siehe Datenblatt) zuerst Nibbles> geschrieben werden und dann nach Umschaltung in den> richtigen Mode Bytes nibble-weise.
Doch. Das hab ich schon kappiert. Ich hab ja die einzelnen Nibbles+-E
geschickt.
0b00110100
0b00110000
0b00110100
0b00110000
0b00110100
0b00110000
0b00100100
0b00100000
Es lag (vermutlich) an was anderem: ich hab zur Kontrolle immer die
Bytes und Text auf den UART ausgegeben, das hat wohl zuviel Verzögerung
gebracht.
Hab alles UART-Anzeigezeugs rausgenommen und ES GEHT.
Ich hab den NoBlinkCursor nach rechts verschoben und XY anpeilen geht
auch. :-p
Ich frag mich jetzt nur, warum eine FOR-Schleife nicht geht?!
for(i=0;i<10;i++) CursorMoveRight
In Kurzform geschrieben!
Vielen Dank schonmal an alle, für die Geduld und prima Hilfe
Armin R. schrieb:> das hat wohl zuviel Verzögerung gebracht.
Nö. Die LCDs arbeiten quasi statisch. D.h. solange Spannung
anliegt kann von der einen Flanke bis zur nächsten Jahre
vergehen ohne dass sich was (fehlerhaft) ändert.
Hallo nochmal...
Hab mal wieder ein Problem mit dem Display.
Ich schicke einen Text an das Display und nach jedem String zeigt es ein
weiteres Zeichen (4 horizontale Striche übereinander). Ich hab null
Ahnung woher das kommt. Ich finds auch nicht in der Zeichentabelle des
Datenblatt.
Sende ich nur ein Zeichen in Hex oder Bin, zeigt es das auch korrekt,
wie in der Tabelle, an.
Beispiel:
LCD_Print_Char(0x30); //Ergebnis auf Display: 0
Das funktioniert also!
Aber
LCD_Print_String("Hallo"); //Ergebnis auf Display: Hallo#
Die Raute wird nicht gezeigt, sondern dieses komische Zeichen. Ist nur
zur Verdeutlichung.
Wie kommt das? Was ist da falsch?
@ Armin R. (ironlayer)
Die Stringausgabe ist eine Geschichte voller Missverständnisse ;-)
(Wofür wurden eigentlich all die Grundlagenbücher für C geschrieben? Für
die Katz?)
Falk B. schrieb:> LCD_Print_String(const char *s) {> while(*s) {> LCD_Print_Char(*s++);> }> }
Hab ich ja zuerst so probiert ;-)
Gibt aber den selben Effekt...LCD zeigt nichts an!
Habs jetzt so gelöst:
1
LCD_Print_String(constchar*s)
2
{
3
do
4
{
5
if(*s)LCD_Print_Char(*s);
6
}
7
while(*s++);
8
}
Ist zwar nicht sehr elegant, aaaber...es funktioniert einwandfrei!
Armin R. schrieb:> Gibt aber den selben Effekt...LCD zeigt nichts an!
Das kann ganz einfach nicht wahr sein !
1
#define F_CPU 8000000
2
#include<stdlib.h>
3
#include<stdint.h>
4
5
uint8_tprb[10];
6
uint8_tptr=0;
7
8
voidI2C_Write_4Bit_Ram(chardata)
9
{
10
prb[ptr++]=data;
11
}
12
13
voidLCD_Print_Char(chardata)
14
{
15
I2C_Write_4Bit_Ram(data);
16
}
17
18
voidLCD_Print_String(constchar*s)
19
{
20
while(*s)LCD_Print_Char(*s++);
21
}
22
23
intmain(void)
24
{
25
LCD_Print_String("1234");
26
}
muss funktionieren, es sei denn, du hast wieder mal irgendetwas
in deinen Routinen geändert und der Compiler (der sich mit C viel
besser auskennt als du, hat beschlossen, dass das völlig unnötig ist
und hat es einfach wegoptimiert...
Nimm den obigen Code, compile das Ganze und probiere es noch
einmal. Wenn es funktioniert, hat der Compiler deine Routinen
wegoptimiert.
EDIT:
Hab deine I2C_Write_4Bit_Ram(data) Routine geändert, probiere es
mal so, zum testen.