I2C Kommunikation Fehlerhaft

Gast #4054211
Lesenswert?

Hallo,

An einem ATMega168 betreibe ich einen I2C BUS mit 100kHz. Als Lib 
verwende ich den von Peter F.
Als I2C Slave ist ein MCP23008 im Einsatz.
Für Testzwecke habe ich folgenden Code
1
  i2c_init();
2
  
3
  i2c_start(TASTER_I2C_DEVICE+I2C_WRITE);
4
  i2c_write(MCP23008_IODIR);
5
  i2c_write(0b11011111);
6
  i2c_stop();
7
  
8
      
9
  i2c_start(TASTER_I2C_DEVICE+I2C_WRITE);
10
  i2c_write(MCP23008_GPIO);
11
  i2c_write(0b11011111);
12
  i2c_stop();
13
  
14
  
15
      
16
  
17
  i2c_start(TASTER_I2C_DEVICE+I2C_READ);
18
  i2c_write(MCP23008_OLAT);
19
  uint8_t regvalue = i2c_readAck();
20
  i2c_stop();


Problem:
Ich bekomme 255 als Ergebnis geliefert.
Warum bekomme ich bei Index 20 (Log Auszug im Anhang) einen NACK und 
keinen ACK?

Grüße, Robert A.
Angehängte Dateien:
#4054284
Lesenswert?

Die Sequenz muss lauten
1
  start( Adresse + Write );
2
  write( Registernummer von der zu lesen ist )
3
  restart( Adresse + Read );
4
  read
5
  stop

Um das Register auszuwählen, von dem du lesen willst, musst du zuerst 
mittels write die Adresse übermitteln und dann mit einem Restart auf 
Lesen umschalten.


http://ww1.microchip.com/downloads/en/DeviceDoc/21919e.pdf
(Seite 6 und folgende)
#4054760
Lesenswert?

Robert A. schrieb:

> Das ist wohl die bescheurteste Zustandsabfrage der IO Pins am MCP23008
> wenn diese als Augang konsifguriert worden sind?!
>
> Geht es auch eleganter?

Wenn sie als Ausgang konfiguriert sind, dann haben sie ja wohl die 
Werte, die du als letztes an die Ausgänge geschrieben hast (ausser du 
hast ein elektrisches Problem). Merk dir, was du zuletzt ausgegeben hast 
und du brauchst den MCP nicht befragen.
#4054768
Lesenswert?

Karl Heinz schrieb:
> Robert A. schrieb:
>
>> Das ist wohl die bescheurteste Zustandsabfrage der IO Pins am MCP23008
>> wenn diese als Augang konsifguriert worden sind?!
>>
>> Geht es auch eleganter?
>
> Wenn sie als Ausgang konfiguriert sind, dann haben sie ja wohl die
> Werte, die du als letztes an die Ausgänge geschrieben hast (ausser du
> hast ein elektrisches Problem). Merk dir, was du zuletzt ausgegeben hast
> und du brauchst den MCP nicht befragen.


Falls du allerdings 'Eingang' anstatt 'Ausgang' meintest.

Was spricht dagegen, das ganze mit ein bischen Makromagie verschwinden 
zu lassen? Zumal:
1
    uint8_t regvalue = mcp23008_reg_read(TASTER_I2C_DEVICE,MCP23008_GPIO);
2
    i2c_stop();
3
    show_value(regvalue);

was macht der i2c_stop da?
Warum macht den der reg_read nicht automatisch?

Persönlich halte ich nicht viel davon, im Funktionsnamen die 
Bauteilbezeichnung einzubringen. Denn das hilft mir als aussenstehender 
nicht wirklich weiter. Was mir aber weiter hilft, das ist wenn ich zb 
weiss, dass in diesem Baustein zb die Konfigurationsschalter sitzen. 
Warum dann nicht
1
#define KONFIG_KEYS   mcp23008_reg_read(TASTER_I2C_DEVICE,MCP23008_GPIO)
2

3
....
4

5

6
  while( 1 ) {
7
    _delay_ms(100);
8
    lcd_command(LCD_CLEAR);
9

10
    show_value( KONFIG_KEYS );
11
  }

über den LCD_CLEAR kann man geteilter Meinung sein, aber abgesehen davon 
ist das so unelegant dann auch wieder nicht.

Oder man definiert sich eine Funktion, die die Aufrufargumente vom MCP 
ergänzt
1
uint8_t ConfigKeys()
2
{
3
  return mcp23008_reg_read(TASTER_I2C_DEVICE, MCP23008_GPIO);
4
}
5

6
....
7

8
  while( 1 ) {
9
    _delay_ms(100);
10
    lcd_command(LCD_CLEAR);
11

12
    show_value( ConfigKeys() );
13
  }

Eleganz liegt im Auge des Betrachters. In der Programmierung besteht 
Eleganz des öfteren darin, den Code so gut lesbar wie möglich zu machen. 
Erreicht wird das dadurch, dass man Details an anderen Stellen 
'versteckt'. Mich interessiert nicht, wie die Config Keys abgefragt 
werden, welches Device dazu zuständig ist. Ich ruf einfach die Funktion 
auf und die Funktion weiss über die Details Bescheid.
Damit ist
1
    show_value( ConfigKeys() );
die 'eleganteste' Methode, um die Werte von den Dip-Switches auszulesen 
und anzuzeigen. Wenn mir die Darstellung nicht gefällt, dann ist 
'show_value()' dafür zuständig; wenn die Dip-Switches 'umziehen' dann 
ist ConfigKeys() dafür zuständig. Saubere Arbeitstrennung und bei 
Veränderungen leicht anpassbar.

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