Problem bei I2C Verbindung zu 1602 LCD

#4924258
Lesenswert?

Hallo zusammen,

ich bin noch recht neu im Umgang mit Mikrocontrollern und versuche 
folgendes Setup zum Laufen zu bringen:

Ich habe einen ATmega328P auf einem Breadboard mit einem 8MHz Quarz. An 
PIN 28 (SCL) und PIN 27 (SDA) ist das Display 1602 (HD44780) über einen 
I2C Controller (PCF8574AT) verbunden.
Die Adresse des I2C Controllers ist 0x27 oder 0x3F (keine Lötbrücken). 
Die I2C clock ist dabei 100kHz.
Die Verbindungslänge ist 30 cm.
SDA und SCL sind über 7,87kOhm Widerstände an 5V verbunden.

Ich programmiere in Atmel Studio 7 und verwende zur Ansteuerung den Code 
von Nico/Thomas Eichelmann (http://computerheld.de/i2clcd/) und das I2C 
MasterInferace von Peter Fleury 
(http://homepage.hispeed.ch/peterfleury/avr-software.html).

Ich habe die i2clcd.h in folgender Weise angepasst:
1
//--Display-Configuration-Settings--
2

3
/** \defgroup DISPLAY_CONFIGURATION DISPLAY CONFIGURATION
4
 Change this settings to your configuration.
5
*/
6
/*@{*/
7
#define LCD_I2C_DEVICE 0x27  /**< Change this to the address of your expander */
8
#define LCD_LINES      2  /**< Enter the number of lines of your display here */
9
#define LCD_ROWS       16  /**< Enter the number of rows of your display here */
10

11
#define LCD_LINE1      0x00  /**< This should be 0x00 on all displays */
12
#define LCD_LINE2      0x40  /**< Change this to the address for line 2 on your display */
13
#define LCD_LINE3      0x10  /**< Change this to the address for line 3 on your display */
14
#define LCD_LINE4      0x50  /**< Change this to the address for line 4 on your display */
15
/*@}*/
16

17
//---------------------------------
18

19
//--The-following-definitions-are-corresponding-to-the-PIN-Assignment-(see-above)--
20

21
/** \defgroup PIN_ASSIGNMENT PIN ASSIGNMENT
22
 This pin assignment shows how the display is connected to the PCF8574.
23
*/
24
/*@{*/
25
#define LCD_D4_PIN      4  /**< LCD-Pin D4 is connected to P0 on the PCF8574 */
26
#define LCD_D5_PIN      5  /**< LCD-Pin D5 is connected to P1 on the PCF8574 */
27
#define LCD_D6_PIN      6  /**< LCD-Pin D6 is connected to P2 on the PCF8574 */
28
#define LCD_D7_PIN      7  /**< LCD-Pin D7 is connected to P3 on the PCF8574 */
29
#define LCD_RS_PIN      0  /**< LCD-Pin RS is connected to P4 on the PCF8574 */
30
#define LCD_RW_PIN      1  /**< LCD-Pin RW is connected to P5 on the PCF8574 */
31
#define LCD_EMPTY_PIN   3  /**< this pin is not connected */
32
#define LCD_E_PIN       2  /**< LCD-Pin D4 is connected to P7 on the PCF8574 */

In meiner main habe ich folgendes stehen:
1
#define F_CPU 8000000UL
2

3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include "lcd/i2clcd.h"
6

7
int main(void){
8
  i2c_init();
9
  lcd_init();
10
  unsigned char string[] = "Hi World";
11
  lcd_print(string);
12
  lcd_nextline();
13

14
  lcd_command(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGON);
15

16
    while (1) {
17
    }
18
}

Das Problem ist, dass auf dem Display in der ersten Zeile nur weiße 
Blöcke angezeigt werden. Ich habe herausgefunden, dass das auf eine 
nicht ausgeführte oder fehlerhafte Initialisierung des Displays 
zurückzuführen ist.

Ich habe jetzt den Fehler so eingegrenzt, dass während der 
Initialisierung des Displays (lcd_init) die Funktion i2c_write 
aufgerufen wird.
1
unsigned char i2c_write( unsigned char data )
2
{  
3
    uint8_t   twst;
4
    
5
  // send data to the previously addressed device
6
  TWDR = data;
7
  TWCR = (1<<TWINT) | (1<<TWEN);
8
  
9
  // wait until transmission completed
10
  while(!(TWCR & (1<<TWINT)));
11
  
12
  // check value of TWI Status Register. Mask prescaler bits
13
  twst = TW_STATUS & 0xF8;
14
  if( twst != TW_MT_DATA_ACK) return 1;
15
  
16
  return 0;
17

18
}/* i2c_write */

Es bleibt dabei bei der Abfrage
1
while(!(TWCR & (1<<TWINT)));
hängen.

Mit dem Oszi habe ich herausgefunden, dass SDA währenddessen high ist, 
jedoch SCL low ist. SCL ist auch low, wenn ich das Display nicht am 
ATmega angeschlossen habe.

Vielen Dank schon einmal für eure Hilfe. :)

Viele Grüße
#4924313
Lesenswert?

@ Arbeitnehmer / Dieter:
Vielen Dank für den Hinweis. Ich hatte mich blind auf den Hinweis des 
Verkäufers des I2C Moduls verlassen.

Das Display scheint auf 0x7E zu reagieren (A0-2 = 1).
Werden A0-2 durch die Lötbrücken auf low gezogen?
Beim PCF857 (ohne A) sind bei 0x27 standardmäßig ja auch A0-2 auf 1 
gesetzt.

Allerdings schaltet sich das Display jetzt nach Start des µC aus.
Womöglich ist irgendwo ein DISPLAYOFF Befehl zu häufig?
Ich werde jetzt versuchen damit weiter zu arbeiten.

@ Patrick:
Ich glaube die Verkabelung ist richtig (PIN 28 (SCL) und PIN 27 (SDA)).
Ich gehe jetzt davon aus, dass es tatsächlich ein Addressfehler war. 
(s.o.)
Danke trotzdem für die Antwort.

Viele Grüße
#4924335
Lesenswert?

Hi

Aus gehen liest sich zumindest so, daß das Display Steuerbefehle 
bekommt.

Die Belegung der 8bit des Expander ist bei den verschiedenen Versionen 
nicht identisch!
Bei den 0x27 z.B. Bit 3 die Hintergrundbeleuchtung.
Dort sind verschiedene Versionen gezeigt:
http://arduino-info.wikispaces.com/LCD-Blue-I2C?responseToken=93c153e52892ea62109f6eaf90429aa5

MfG
#4924349
Lesenswert?

Patrick J. schrieb:
> Hi
>
> Aus gehen liest sich zumindest so, daß das Display Steuerbefehle
> bekommt.
>
> Die Belegung der 8bit des Expander ist bei den verschiedenen Versionen
> nicht identisch!
> Bei den 0x27 z.B. Bit 3 die Hintergrundbeleuchtung.
> Dort sind verschiedene Versionen gezeigt:
> 
http://arduino-info.wikispaces.com/LCD-Blue-I2C?responseToken=93c153e52892ea62109f6eaf90429aa5
>
> MfG

Ich habe alle Verbindungen vom Display zum PCF857AT durchgepiepst und 
bin dann auf folgende Verbindungen gekommen:
1
#define LCD_D4_PIN      4  /**< LCD-Pin D4 is connected to P4 on the PCF8574 */
2
#define LCD_D5_PIN      5  /**< LCD-Pin D5 is connected to P5 on the PCF8574 */
3
#define LCD_D6_PIN      6  /**< LCD-Pin D6 is connected to P6 on the PCF8574 */
4
#define LCD_D7_PIN      7  /**< LCD-Pin D7 is connected to P7 on the PCF8574 */
5
#define LCD_RS_PIN      0  /**< LCD-Pin RS is connected to P0 on the PCF8574 */
6
#define LCD_RW_PIN      1  /**< LCD-Pin RW is connected to P1 on the PCF8574 */
7
#define LCD_EMPTY_PIN    3  /**< this pin is not connected */
8
#define LCD_E_PIN      2  /**< LCD-Pin D4 is connected to P2 on the PCF8574 */

Sofern die Beschriftungen der Pins auf dem Display nicht falsch sind, 
sollte das hoffentlich passen.

War das das, was du gemeint hast?

Viele Grüße
#4924373
Lesenswert?

Anbei habe ich den Abschnitt aus dem Datenblatt des HD44780 angehängt in 
dem der Display Mode definiert wird.

Und hier ist der Code der das definiert:
1
#define LCD_DISPLAYMODE      0x08      /**< Set displaymode */
2
  #define LCD_DISPLAYON    LCD_DISPLAYMODE | 0x04  /**<  Display on */
3
  #define LCD_DISPLAYOFF    LCD_DISPLAYMODE | 0x00  /**<  Display off */
4
  #define LCD_CURSORON    LCD_DISPLAYMODE | 0x02  /**<  Cursor on */
5
  #define LCD_CURSOROFF    LCD_DISPLAYMODE | 0x00  /**<  Cursor off */
6
  #define LCD_BLINKINGON    LCD_DISPLAYMODE | 0x01  /**<  Blinking on */
7
  #define LCD_BLINKINGOFF    LCD_DISPLAYMODE | 0x00  /**<  Blinking off */

Für Display_on also b1100.

Meiner Meinung nach ist das auch richtig.
Angehängte Dateien:
#4924395
Lesenswert?

Hi

Hier ging es doch um die Ansteuerung per I2C-Portexpander, oder was habe 
ich verpasst?
Da der Expander nur 8bit hat und Du dort auch noch E,RS,RW mit drüber 
bringen musst, bleiben 4bit für's Display über.
Zum Umschalten auf 4-bit-Betrieb reicht Das, danach 16x2, 
Cursor,Blinken,Display-Shift, dann Display an, fertig.

Wobei im 4-Bit-Betrieb jedes Byte in zwei Nibble gesendet wird, wo die 
Steuer-Bits doppelt gesendet werden.


MfG
#4924417
Lesenswert?

Patrick J. schrieb:
> Hi
>
> Hier ging es doch um die Ansteuerung per I2C-Portexpander, oder was habe
> ich verpasst?
> Da der Expander nur 8bit hat und Du dort auch noch E,RS,RW mit drüber
> bringen musst, bleiben 4bit für's Display über.
> Zum Umschalten auf 4-bit-Betrieb reicht Das, danach 16x2,
> Cursor,Blinken,Display-Shift, dann Display an, fertig.
>
> Wobei im 4-Bit-Betrieb jedes Byte in zwei Nibble gesendet wird, wo die
> Steuer-Bits doppelt gesendet werden.
>
>
> MfG

Hi Patrick,

entschuldige, wenn ich noch nicht alles ganz durchschaue.
Ja es geht um einen I2C-Portexpander mit 8 bit.
Die 4 Datenbits werden kopiert und werden in D0-3 und D4-7 des Displays 
geschrieben:
1
#define LCD_D0        (1 << LCD_D4_PIN)  /**< bit 0 in 1st lower nibble */
2
#define LCD_D1        (1 << LCD_D5_PIN)  /**< bit 1 in 1st lower nibble */
3
#define LCD_D2        (1 << LCD_D6_PIN)  /**< bit 2 in 1st lower nibble */
4
#define LCD_D3        (1 << LCD_D7_PIN)  /**< bit 3 in 1st lower nibble */
5

6
#define LCD_D4        (1 << LCD_D4_PIN)  /**< bit 4 in 2nd lower nibble */
7
#define LCD_D5        (1 << LCD_D5_PIN)  /**< bit 5 in 2nd lower nibble */
8
#define LCD_D6        (1 << LCD_D6_PIN)  /**< bit 6 in 2nd lower nibble */
9
#define LCD_D7        (1 << LCD_D7_PIN)  /**< bit 7 in 2nd lower nibble */
10

11
#define LCD_RS        (1 << LCD_RS_PIN)  /**< RS-bit in 1st and 2nd higher nibble */
12
#define LCD_RW        (1 << LCD_RW_PIN)  /**< RW-bit in 1st and 2nd higher nibble */
13
#define LCD_EMPTY      (1 << LCD_EMPTY_PIN)  /**< empty-bit in 1st and 2nd higher nibble */
14
#define LCD_E        (1 << LCD_E_PIN)  /**< E-bit in 1st and 2nd higher nibble */

So ist es zumindest im Code, den ich habe, realisiert. In der Funktion 
lcd_command werden dann jeweils die oberen und unteren 4 bits 
nacheinander gesendet:
1
void lcd_command(unsigned char command)
2
{
3
  unsigned char lcddata;
4
  lcddata = command;
5
  lcddata >>=  4;
6
  lcd_write(lcddata);
7
  lcddata = command;
8
  lcddata &= 0x0F;
9
  lcd_write(lcddata);  
10
}

Ist das soweit richtig?

Danke für die Hilfe. :)
#4924446
Lesenswert?

Hi

Die LCD_write müsste dann mit den Steuerbits verodern und diese so 
generierten 8bit per I2C ans Display schicken.

Mit der realen Belegung des Display hast Du hier weniger zu tun, da der 
Expander hier vorgibt, was wie zu übertragen ist.

Wenn Du dieses Display bereits an einem anderen µC was anzeigt, bitten 
den Code davon sowie den Code dieses µC, denke, da haben wir Differenzen 
drin.

Komplette Code wäre hier sinnig, z.B. ist in Deiner Funktion lcd_command 
nicht ersichtlich, wo die Steuerbits her kommen und welche Pins wofür 
benutzt werden.

MfG
#4924456
Lesenswert?

Patrick J. schrieb:
> Hi
>
> Die LCD_write müsste dann mit den Steuerbits verodern und diese so
> generierten 8bit per I2C ans Display schicken.
>
> Mit der realen Belegung des Display hast Du hier weniger zu tun, da der
> Expander hier vorgibt, was wie zu übertragen ist.
>
> Wenn Du dieses Display bereits an einem anderen µC was anzeigt, bitten
> den Code davon sowie den Code dieses µC, denke, da haben wir Differenzen
> drin.
>
> Komplette Code wäre hier sinnig, z.B. ist in Deiner Funktion lcd_command
> nicht ersichtlich, wo die Steuerbits her kommen und welche Pins wofür
> benutzt werden.
>
> MfG

Ich habe bis jetzt nur den einen µC, deshalb kann ich es gerade nicht an 
einem anderen µC testen.

Anbei der gesamt Code als zip. Ich hoffe das ist in Ordnung.

Vielen Dank noch einmal.
Angehängte Dateien:
#4924480
Lesenswert?

Hi

Wie Du oben schreibst, siehst Du nur einen Balken.
Init nicht korrekt

Leider komme ich mit der Schreibweise des Code nicht sonderlich zurecht, 
meinem Verständnis nach, dürfte Da rein gar Nichts passieren :O
1
void lcd_init(void);          //-  Display initialization sequence
2

3
/**
4
 \brief Write data to i2c (for internal use)
5
 \param value byte to send over i2c
6
 \return none
7
 */
8
void lcd_write_i2c(unsigned char value);    //-  Write data to i2c
9

10
/**
11
 \brief Write byte to display with toggle of enable-bit
12
 \param value the upper nibble represents  E, RS, RW pins and the lower nibble contains data D0 to D3 pins or D4 to D7 pins
13
 \return none
14
 */
15
void lcd_write(unsigned char value);      //-  Write byte to display with toggle of enable-bit
16

17
/**
Geht dann noch weiter ...
Ist erkenne da nicht, was wirklich zum Init verschickt wird.

MfG
#4924487
Lesenswert?

Patrick J. schrieb:
> Hi
>
> Wie Du oben schreibst, siehst Du nur einen Balken.
> Init nicht korrekt
>
> Leider komme ich mit der Schreibweise des Code nicht sonderlich zurecht,
> meinem Verständnis nach, dürfte Da rein gar Nichts passieren :O
>
1
void lcd_init(void);          //-  Display initialization 
2
> sequence
3
> 
4
> /**
5
>  \brief Write data to i2c (for internal use)
6
>  \param value byte to send over i2c
7
>  \return none
8
>  */
9
> void lcd_write_i2c(unsigned char value);    //-  Write data to i2c
10
> 
11
> /**
12
>  \brief Write byte to display with toggle of enable-bit
13
>  \param value the upper nibble represents  E, RS, RW pins and the lower 
14
> nibble contains data D0 to D3 pins or D4 to D7 pins
15
>  \return none
16
>  */
17
> void lcd_write(unsigned char value);      //-  Write byte to display 
18
> with toggle of enable-bit
19
> 
20
> /**
> Geht dann noch weiter ...
> Ist erkenne da nicht, was wirklich zum Init verschickt wird.
>
> MfG

Hi Patrick,

die Implementierungen der I2C Funktionen stehen in der "twimaster.c".

Mittlerweile habe ich ja auch keine Balken mehr, sondern das Display 
schaltet sich aus.
Die I2C Verbindung steht also scheinbar, nur scheine ich falsche Befehle 
zu schicken, oder ähnliches.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren