Forum: Mikrocontroller und Digitale Elektronik Atmega8 und I2C-Display startet nicht


von Armin R. (ironlayer)


Lesenswert?

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

von Karl M. (Gast)


Lesenswert?

Hallo,

"MC läuft mit intern 4Mhz" wie hast Du das bei einem Atmega8 angestellt 
?

von Frickelfritze (Gast)


Lesenswert?

Armin R. schrieb:
> Hab ich da was falsch verstanden???

Ja. Du kannst keine LEDs an den I2C Bus dranhängen und erwarten
dass er dann noch funktioniert.

von Armin R. (ironlayer)


Lesenswert?

@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!

von holger (Gast)


Lesenswert?

>Es hat ja ursprünglich auch nicht funktioniert. Die Leds hab ich im
>Nachhinein erst angeklemmt, als Kontrolle!

Um es noch schlimmer zu machen?

von Datenblatthinweiser (Gast)


Lesenswert?

Armin R. schrieb:
> Der MC läuft mit intern 4Mhz

Welcher? Muss man dir alle Details wie Popel einzeln
aus der Nase ziehen?

von Armin R. (ironlayer)


Lesenswert?

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?

von Armin R. (ironlayer)


Lesenswert?

@Datenblatthinweiser
Mein Atmega8 als TWI-Master, der das Display ansteuern soll, hängt läuft 
mit 4Mhz.

von Marc H. (marchorby)


Lesenswert?

Poste doch einfach mal nen SCHALTPLAN und passende FOTOS vom 
AUFBAU!!!einself1111!!!

von Frickelfritze (Gast)


Lesenswert?

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.

von Philipp L. (philipp_l89)


Lesenswert?

Armin R. schrieb:
> Der MC läuft mit intern 4Mhz

Karl 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!

von Armin R. (ironlayer)


Lesenswert?

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!

von Philipp L. (philipp_l89)


Lesenswert?

@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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

: Bearbeitet durch User
von dummy (Gast)


Lesenswert?

>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.

von Armin R. (ironlayer)


Lesenswert?

@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):
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
void Uart_init();
13
void Port_init();
14
void I2C_init();
15
void uart_send_string(const char *s);
16
17
void main()
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
  uart_send_string("Start gesendet");
33
  uart_send_string(CR);
34
  _delay_ms(100);
35
36
  //Adresse incl RW senden
37
  TWDR = 0b01110000;
38
  TWCR = (1 << TWINT) | (1 << TWEN);
39
  while (!(TWCR & (1 << TWINT)));
40
  uart_send_string("Slaveadresse+RW gesendet");
41
  uart_send_string(CR);
42
  _delay_ms(100);
43
 
44
  //Daten senden
45
  TWDR = 0b00011001;
46
  TWCR = (1 << TWINT) | (1 << TWEN);
47
  while (!(TWCR & (1 << TWINT)));
48
  uart_send_string("Daten gesendet");
49
  uart_send_string(CR);
50
  _delay_ms(100);
51
52
  //STOP senden
53
  TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
54
  while (!(TWCR & (1 << TWINT)));
55
  uart_send_string("Stop gesendet");
56
  uart_send_string(CR);
57
58
  uart_send_string(CR);
59
  uart_send_string("--------------------");
60
  uart_send_string(CR);
61
  uart_send_string(CR);
62
  _delay_ms(100);
63
 }
64
}
65
66
//Funktionen
67
void Uart_init()
68
{
69
 uint16_t ubrr=(uint16_t)((uint32_t)F_CPU/(16*BAUDRATE)-1);
70
 UBRRH=(uint8_t)(ubrr>>8);
71
 UBRRL=(uint8_t)(ubrr);
72
 UCSRB=(1<<RXEN)|(1<<TXEN);
73
 UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
74
}
75
76
void Port_init()
77
{
78
 DDRB |=(1<<PB0);// PB0 Ausgang (LED)
79
 PORTC |=(1<<PC4);//PC4 Pullup (SDA)
80
 PORTC |=(1<<PC5);//PC5 Pullup (SCL)
81
}
82
83
void I2C_init() // (100KHz)
84
{
85
 TWSR = 0;
86
 TWBR = 12;
87
}
88
89
void uart_send_string(const char *s)
90
{
91
 while(!(UCSRA&(1<<UDRE)));
92
 do
93
 {
94
  UDR= *s;
95
  _delay_ms(5);
96
 }
97
 while(*s++);
98
}

Ergebnis im Hyperterminal:
1
Programmstart...
2
Start gesendet
3
Slaveadresse+RW gesendet
4
Daten gesendet
5
Stop gesendet
6
--------------------
7
8
Start gesendet
9
Slaveadresse+RW gesendet
10
Daten gesendet
11
Stop gesendet
12
--------------------
13
usw...

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
void Uart_init();
13
void Port_init();
14
void I2C_init();
15
void uart_send_string(const char *s);
16
17
void main()
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");
50
  }
51
  else
52
  {
53
   uart_send_string("Slaveadresse+RW gesendet");
54
  }
55
  uart_send_string(CR);
56
  _delay_ms(100);
57
 
58
  //Daten senden
59
  TWDR = 0b00011001;
60
  TWCR = (1 << TWINT) | (1 << TWEN);
61
  while (!(TWCR & (1 << TWINT)));
62
  if((TWSR & 0xF8) != MT_DATA_ACK)
63
  {
64
   uart_send_string("Daten NICHT gesendet");
65
  }  
66
  else
67
  {
68
   uart_send_string("Daten gesendet");
69
  }
70
  uart_send_string(CR);
71
  _delay_ms(100);
72
73
  //STOP senden
74
  TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
75
  while (!(TWCR & (1 << TWINT)));
76
  uart_send_string("Stop gesendet");
77
  uart_send_string(CR);
78
79
  uart_send_string(CR);
80
  uart_send_string("--------------------");
81
  uart_send_string(CR);
82
  uart_send_string(CR);
83
  _delay_ms(100);
84
 }
85
}
86
87
//Funktionen
88
void Uart_init()
89
{
90
 uint16_t ubrr=(uint16_t)((uint32_t)F_CPU/(16*BAUDRATE)-1);
91
 UBRRH=(uint8_t)(ubrr>>8);
92
 UBRRL=(uint8_t)(ubrr);
93
 UCSRB=(1<<RXEN)|(1<<TXEN);
94
 UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
95
}
96
97
void Port_init()
98
{
99
 DDRB |=(1<<PB0);// PB0 Ausgang (LED)
100
 PORTC |=(1<<PC4);//PC4 Pullup (SDA)
101
 PORTC |=(1<<PC5);//PC5 Pullup (SCL)
102
}
103
104
void I2C_init() // (100KHz)
105
{
106
 TWSR = 0;
107
 TWBR = 12;
108
}
109
110
void uart_send_string(const char *s)
111
{
112
 while(!(UCSRA&(1<<UDRE)));
113
 do
114
 {
115
  UDR= *s;
116
  _delay_ms(5);
117
 }
118
 while(*s++);
119
}

Ergebnis im Hyperterminal:
1
Programmstart...
2
Start NICHT gesendet
3
Slaveadresse+RW NICHT gesendet
4
Daten NICHT gesendet
5
Stop gesendet
6
--------------------
7
8
Start NICHT gesendet
9
Slaveadresse+RW NICHT gesendet
10
Daten NICHT gesendet
11
Stop gesendet
12
--------------------
13
usw...

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

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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 ;)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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!

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Lehrling (Gast)


Lesenswert?

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

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

: Bearbeitet durch User
von Armin R. (ironlayer)


Lesenswert?

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?

: Bearbeitet durch User
von Armin R. (ironlayer)


Lesenswert?

@Lehrling
Der UART wird bei mir nur zur Ausgabe der Meldungen auf den PC 
verwendet. Der hat mit dem I2C nix zu tun!

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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

von Armin R. (ironlayer)


Lesenswert?

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...

von Chris F. (chfreund) Benutzerseite


Lesenswert?

Wie der ATMega8(??) ohne externen Oszillator mit 4MHz intern läuft, 
durch fuses, habe ich immernoch nicht begriffen.

von Hubert G. (hubertg)


Lesenswert?

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/

von Dieter F. (Gast)


Lesenswert?

Chris F. schrieb:
> Wie der ATMega8(??) ohne externen Oszillator mit 4MHz intern läuft,
> durch fuses, habe ich immernoch nicht begriffen.

Datenblatt S. 30

von Armin R. (ironlayer)


Lesenswert?

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

: Bearbeitet durch User
von Chris F. (chfreund) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

: Bearbeitet durch User
von Armin R. (ironlayer)


Lesenswert?

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!

: Bearbeitet durch User
von Op (Gast)


Lesenswert?

Der kontrast ist schon richtig eingestellt, oder? :D

von Thomas S. (thommi)


Lesenswert?

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) ;-)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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

von Armin R. (ironlayer)


Angehängte Dateien:

Lesenswert?

Hier nochmal als Eagle-Schaltplan meine Verdrahtung...

von Armin R. (ironlayer)


Lesenswert?

Hab ich das mit dem Enable(E)-Pin irgendwie falsch verstanden?

von Armin R. (ironlayer)


Angehängte Dateien:

Lesenswert?

Hier noch mal Fotos vom Aufbau...

von Frickelfritze (Gast)


Lesenswert?

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.

von Frickelfritze (Gast)


Lesenswert?

Armin R. schrieb:
> Lasse ich aber das D4-Bit weg

Das ist das D3 Bit. Die Zählweise hier ist immer 0...7

von Frickelfritze (Gast)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
 delay 1us
4
 PCF -> xxxx - x0xx
5
 delay 1us
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.

: Bearbeitet durch User
von Frickelfritze (Gast)


Lesenswert?

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.

von Frickelfritze (Gast)


Lesenswert?

Armin R. schrieb:
> Hier noch mal Fotos vom Aufbau...

Ja ..... das ist schön gruselig .....

von Frickelfritze (Gast)


Lesenswert?

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)."

von Armin R. (ironlayer)


Lesenswert?

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...

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

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.

von Frickelfritze (Gast)


Lesenswert?

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.

von Dieter F. (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Frickelfritze (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

: Bearbeitet durch User
von Frickelfritze (Gast)


Lesenswert?

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

von Armin R. (ironlayer)


Lesenswert?

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 ;)

von Dieter F. (Gast)


Lesenswert?

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 ...

von Marc V. (Firma: Vescomp) (logarithmus)


Angehängte Dateien:

Lesenswert?

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 ?

von Armin R. (ironlayer)


Lesenswert?

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):
1
void I2C_Write_4Bit_Set(int cmd)
2
{
3
 int Data;
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
 I2C_Send_Data(0b00001000,2); //Led=1,E=0
9
 //High-Nibble
10
 Data=(cmd&0b11110000);
11
 Data|=(1<<2)|(1<<3); //Led=1,E=0
12
 I2C_Send_Data(Data,2);
13
 I2C_Send_Data(0b00001000,2); //Led=1,E=0
14
}

Was mache ich falsch????

: Bearbeitet durch User
von Frickelfritze (Gast)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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
void I2C_Write_4Bit_Set(int cmd)
2
{
3
 int Data;
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...

von Falk B. (falk)


Lesenswert?

Nimm die Lib und sein glücklich.

Beitrag "Re: I2CLCD Library für HD44780 LCDs"

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
void I2C_CtrlByt(uint8_t cmd)
7
{
8
 uint8_t Data;
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
int main(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 ?

: Bearbeitet durch User
von Frickelfritze (Gast)


Lesenswert?

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!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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...

von Falk B. (falk)


Lesenswert?

@ 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.

von Frickelfritze (Gast)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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?

von Frickelfritze (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

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

von Frickelfritze (Gast)


Lesenswert?

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.

von Armin R. (ironlayer)


Lesenswert?

Ich hab aber sonst nix geändert! Irgendwie hat der UART anscheinend 
gestört. Keine Ahnung wieso.

von Armin R. (ironlayer)


Lesenswert?

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?

1
LCD_Print_String(const char *s)
2
{
3
 do
4
 {
5
  LCD_Print_Char(*s);
6
 }
7
 while(*s++);
8
}
9
10
LCD_Print_Char(char data)
11
{
12
 I2C_Write_4Bit_Ram(data);
13
}

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Armin R. schrieb:
1
 while(*s++);

 Nicht nachher erhöhen, sondern vorher prüfen.
 So wird der Stringterminator (0) mitangezeigt.

von Armin R. (ironlayer)


Lesenswert?

1
LCD_Print_String(const char *s)
2
{
3
 while(*s)
4
 {
5
  LCD_Print_Char(*s);
6
  *s++;
7
 }
8
}

So zeigts gar nichts an...:-(

von Falk B. (falk)


Lesenswert?

@ 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?)
1
LCD_Print_String(const char *s) {
2
  while(*s) {
3
    LCD_Print_Char(*s++);
4
  }
5
}

von Armin R. (ironlayer)


Lesenswert?

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(const char *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!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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_t prb[10];
6
uint8_t ptr = 0;
7
8
void I2C_Write_4Bit_Ram(char data)
9
{
10
   prb[ptr++] = data;
11
}
12
13
void LCD_Print_Char(char data)
14
{
15
 I2C_Write_4Bit_Ram(data);
16
}
17
18
void LCD_Print_String(const char *s)
19
{
20
 while(*s) LCD_Print_Char(*s++);
21
}
22
23
int main(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.

: Bearbeitet durch User
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
Noch kein Account? Hier anmelden.