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)
Gast #4054296
Lesenswert?
• ▲
▼
1
  i2c_start(TASTER_I2C_DEVICE+I2C_WRITE);
2
  i2c_write(MCP23008_OLAT);
3
  i2c_start(TASTER_I2C_DEVICE+I2C_READ);
4
  uint8_t regvalue = i2c_readAck();
5
  i2c_stop();

Ok, alles klar, funktioniert nun wunderbar.
Danke!
Gast #4054730
Lesenswert?
• ▲
▼
Ich habe noch was:
1
    while(1)
2
    {        
3
    _delay_ms(100);
4
    lcd_command(LCD_CLEAR);
5
    uint8_t regvalue = mcp23008_reg_read(TASTER_I2C_DEVICE,MCP23008_GPIO);
6
    i2c_stop();
7
    show_value(regvalue);
8
      
9
    
10
    }

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

Geht es auch eleganter?
#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

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.