Also... Nachdem ich aktuell etwas Schwierigkeiten mit besagtem Thema hatte
möchte ich für die "Mit-Dummies" und Anfänger in der Richtung Hilfestellung geben.

Dazu habe ich begonnen simple (absichtlich primitive) kurze programme zu erstellen
mit denen man den MCP kennenlernen kann.

Mir ist klar, das man das meiste evtl. mit der hälfte Code hätte lösen können...
aber es soll eben für "Neueinsteiger" lesbar und eingängig sein!

Bitte schaut euch dazu diese Codes durch und gebt fleissig Kritik.


Testprogramm "Simpler_Ausgangstest":MCP23017_Simpler_Ausgangstest.bas

Code:
'**********************************************************************
'** Programmbeschreibung **
'**********************************************************************
'** Funktionstest MCP23017 !!!
'** Alle GPA und GPB werden auf Ausgang eingestellt und getoggelt.
'** So Kann man ganz einfach (z.B. mit LED + passendem Vorwiderstand)
'** an den Pins testen, ob der MCP23017 reagiert.
'** Der MCP erhöht in der Standardeinstellung bei jedem folgenden
'** Schreib/Lesezugriff AUTOMATISCH die Registeradresse!
'**
'** Anschlüsse in diesem Test verwendet:
'** >SDA und SCL direkt mit dem Kontroller verbinden und
'**  jeweils einen Widerstand als Pullup gegen + verbinden (Ca 4 bis 5 kOhm).
'** >+ und - direkt anschliessen.
'** >Resetpin mit + verbinden.
'** >A0/A1/A2 (Adresspins) mit - verbinden.
'**********************************************************************
$regfile = "M328pdef.dat"
$crystal = 16000000
$baud = 38400

'**********************************************************************
'** Pins
'**********************************************************************
Config Sda = Portc.4                                        ' I2C Data.
Config Scl = Portc.5                                        ' I2C Clock.
Config I2cdelay = 10                                        ' Geschwindigkeit des I2C-Bus

'**********************************************************************
'** Subroutinen
'**********************************************************************
' Subroutine fürs senden der Daten an den MCP23017.
Declare Sub I2c_mcp23016_write(byval Reg As Byte , Byval Abyte As Byte , Byval Bbyte As Byte)

'**********************************************************************
'** Variablen/Konstanten
'**********************************************************************
' Die Adresse des MCP23017 in Hexform (mit A0/A1/A2 jeweils 0 bzw auf Gnd gelegt)
Const Mcp23016_adress_w = &H40                              ' Write Adresse des MCP23017: 0 1 0 0 _0 0 0_ 0
Const Mcp23016_adress_r = &H41                              ' Read Adresse des MCP23017: 0 1 0 0 _0 0 0_ 1 (hier nicht verwendet)

Dim Reg As Byte                                             ' enthält das Start-Register, in das geschrieben bzw. aus dem gelesen wird

Dim Abyte As Byte                                           ' Diese Variablen werden zum Schreiben verwendet
Dim Bbyte As Byte


'**********************************************************************
'** Haupt-Programm
'**********************************************************************
'Neustart
Waitms 100                                                  ' Kurze Pause bei Neustart


Mcp_initialisieren:
Reg = &H00                                                  ' erstmal beim Register IODIRA mit Schreiben beginnen
Call I2c_mcp23016_write(reg , &H00 , &H00)                  ' IODIRA und IODIRB alle auf Ausgänge einstellen


Testfunktion:
Do
 Reg = &H14                                                 ' jetzt beim Register OLATA mit Schreiben beginnen

 Call I2c_mcp23016_write(reg , &HFF , &HFF)                 ' OLATA und OLATB ... beide auf 1 stellen
 Portb.0 = 1                                                ' Alle Ausgänge einschalten
 Waitms 75


 Call I2c_mcp23016_write(reg , &H00 , &H00)                 ' OLATA und OLATB ... beide auf 0 Stellen
 Portb.0 = 0                                                ' Alle Ausgänge ausschalten
 Waitms 75
Loop

End


'**********************************************************************
'**  Subroutinen
'**********************************************************************
' Daten auf MCP23017 schreiben/senden
Sub I2c_mcp23016_write(byval Reg As Byte , Byval Abyte As Byte , Byval Bbyte As Byte)
 I2cstart                                                   'Start senden
 I2cwbyte Mcp23016_adress_w                                 'Adresse fürs Schreiben senden
 I2cwbyte Reg                                               'Registeradresse die als erstes beschrieben werden soll
 I2cwbyte Abyte                                             'Erstes Daten-Byte Senden
 I2cwbyte Bbyte                                             'Zweites Daten-Byte senden (wird automatisch ins nächste Register geschrieben)
 I2cstop                                                    'Stop senden
 Waitus 50                                                  'Kurze Wartezeit einhalten um den I2C-Bus wieder "frei zu machen"
End Sub


Testprogramm "Register_Auslesen":MCP23017_Register_auslesen.bas

Code:
'**********************************************************************
'** Programmbeschreibung **
'**********************************************************************
'** Funktionstest MCP23017 !!!
'** Alle Register des MCP23017 werden ausgelesen und noch als Beispiel
'** GPIOA und GPIOB einzeln ausgelesen.
'** Der MCP erhöht in der Standardeinstellungbei jedem folgenden
'** Schreib/Lesezugriff AUTOMATISCH die Registeradresse!
'**
'** Anschlüsse in diesem Test verwendet:
'** >SDA und SCL direkt mit dem Kontroller verbinden und
'**  jeweils einen Widerstand als Pullup gegen + verbinden (Ca 4 bis 5 kOhm).
'** >+ und - direkt anschliessen.
'** >Resetpin mit + verbinden.
'** >A0/A1/A2 (Adresspins) mit - verbinden.
'**********************************************************************
$regfile = "M328pdef.dat"
$crystal = 16000000
$baud = 38400

'**********************************************************************
'** Pins
'**********************************************************************
Config Sda = Portc.4                                        ' I2C Data.
Config Scl = Portc.5                                        ' I2C Clock.
Config I2cdelay = 10                                        ' Geschwindigkeit des I2C-Bus

'**********************************************************************
'** Subroutinen
'**********************************************************************
' Subroutine fürs senden der Daten an den MCP23017.
Declare Sub I2c_mcp23016_write_two(byval Reg As Byte , Byval Abyte As Byte , Byval Bbyte As Byte)
Declare Sub I2c_mcp23016_read_all
Declare Sub I2c_mcp23016_read_one(byval Reg As Byte)
'**********************************************************************
'** Variablen/Konstanten
'**********************************************************************
' Die Adresse des MCP23017 in Hexform (mit A0/A1/A2 jeweils 0 bzw auf Gnd gelegt)
Const Mcp23016_adress_w = &H40                              ' Write Adresse des MCP23017: 0 1 0 0 _0 0 0_ 0
Const Mcp23016_adress_r = &H41                              ' Read Adresse des MCP23017: 0 1 0 0 _0 0 0_ 1

Dim Reg As Byte                                             ' enthält das Start-Register, in das geschrieben bzw. aus dem gelesen wird

Dim Abyte As Byte                                           ' Diese Variablen werden zum Schreiben verwendet
Dim Bbyte As Byte

'Variablen jeweils für die einzelnen Registerinhalte
Dim Aa As Byte
Dim Ab As Byte
Dim Ba As Byte
Dim Bb As Byte
Dim Ca As Byte
Dim Cb As Byte
Dim Da As Byte
Dim Db As Byte
Dim Ea As Byte
Dim Eb As Byte
Dim Fa As Byte
Dim Fb As Byte
Dim Ga As Byte
Dim Gb As Byte
Dim Ha As Byte
Dim Hb As Byte
Dim Ia As Byte
Dim Ib As Byte
Dim Ja As Byte
Dim Jb As Byte
Dim Ka As Byte
Dim Kb As Byte
Dim Xx As Byte
'Die Menge an Variablen ist zwar unangebracht und kann leicht "eleganter" gelöst werden...
'soll hier aber den Code "einfacher" gestalten um die Vorgänge besser zu zeigen

'**********************************************************************
'** Haupt-Programm
'**********************************************************************
'Neustart
Waitms 100                                                  ' Kurze Pause bei Neustart



Do

Alle_register_auslesen:
   Reg = &H00                                               ' Register, bei dem mit dem Auslesen angefangen werden soll
   Print ">Alle Register Auslesen..."

   Call I2c_mcp23016_read_all                               ' Auslesen beginnen

   Print ">IODIRA  : " ; Bin(aa)
   Print ">IODIRB  : " ; Bin(ab)
   Print ">IOPOLA  : " ; Bin(ba)
   Print ">IOPOLB  : " ; Bin(bb)
   Print ">GPINTENA: " ; Bin(ca)
   Print ">GPINTENB: " ; Bin(cb)
   Print ">DEFVALA : " ; Bin(da)
   Print ">DEFVALB : " ; Bin(db)
   Print ">INTCONA : " ; Bin(ea)
   Print ">INTCONB : " ; Bin(eb)
   Print ">IOCON   : " ; Bin(fa)
   Print ">IOCON   : " ; Bin(fb)
   Print ">GPPUA   : " ; Bin(ga)
   Print ">GPPUB   : " ; Bin(gb)
   Print ">INTFA   : " ; Bin(ha)
   Print ">INTFB   : " ; Bin(hb)
   Print ">INTCAPA : " ; Bin(ia)
   Print ">INTCAPB : " ; Bin(ib)
   Print ">GPIOA   : " ; Bin(ja)
   Print ">GPIOB   : " ; Bin(jb)
   Print ">OLATA   : " ; Bin(ka)
   Print ">OLATB   : " ; Bin(kb)
   Print ">"
   Waitms 100

Einzelnes_register_auslesen:                                ' hier als Beispiel GPIOA und GPIOB
   Reg = &H12                                               ' Register das ausgelesen werden soll
   Call I2c_mcp23016_read_one(reg)                          ' Auslesen beginnen
   Print ">Gelesenes Register " ; Hex(reg) ; " (Hex) enthaelt die Werte: " ; Bin(xx)
   Print ">"
   Waitms 100

   Reg = &H13                                               ' Wie zuvor nur diesmal das Register Hex13 auslesen
   Call I2c_mcp23016_read_one(reg)
   Print ">Gelesenes Register " ; Hex(reg) ; " (Hex) enthaelt die Werte: " ; Bin(xx)
   Print ">"
   Waitms 100


   Wait 3                                                   ' 3 Sekunden warten bevor von vorne begonnen wird

Loop

End


'**********************************************************************
'**  Subroutinen
'**********************************************************************
' Daten auf MCP23017 schreiben/senden (hier nicht verwendet)
Sub I2c_mcp23016_write_two(byval Reg As Byte , Byval Abyte As Byte , Byval Bbyte As Byte)
   I2cstart                                                 'Start senden
   I2cwbyte Mcp23016_adress_w                               'Adresse fürs Schreiben senden
   I2cwbyte Reg                                             'Registeradresse die als erstes beschrieben werden soll
   I2cwbyte Abyte                                           'Erstes Daten-Byte Senden
   I2cwbyte Bbyte                                             'Zweites Daten-Byte senden (wird automatisch ins nächste Register geschrieben)
   I2cstop                                                  'Stop senden
   Waitus 50                                                'Kurze Wartezeit einhalten um den I2C-Bus wieder "frei zu machen"
End Sub


' Daten vom MCP23017 abrufen (hier z.b. ALLE Register nacheinander)
Sub I2c_mcp23016_read_all
   I2cstart                                                 'Start senden
   I2cwbyte Mcp23016_adress_w                               'Adresse fürs Schreiben senden
   I2cwbyte Reg                                             'Registeradresse die als erstes gelesen werden soll
   I2cstop                                                  'Stop senden
   I2crepstart                                              'RepeatedStart senden
   I2cwbyte Mcp23016_adress_r                               'Adresse fürs Lesen senden. Der MCP folgt dieser Aufforderung mit der Ausgabe des Registerinhalts
   I2crbyte Aa , Ack                                        'Registerinhalt in Variable übernehmen und mit "Ack" zum weiteren senden auffordern
   I2crbyte Ab , Ack                                        'usw.
   I2crbyte Ba , Ack                                        'usw.
   I2crbyte Bb , Ack
   I2crbyte Ca , Ack
   I2crbyte Cb , Ack
   I2crbyte Da , Ack
   I2crbyte Db , Ack
   I2crbyte Ea , Ack
   I2crbyte Eb , Ack
   I2crbyte Fa , Ack
   I2crbyte Fb , Ack
   I2crbyte Ga , Ack
   I2crbyte Gb , Ack
   I2crbyte Ha , Ack
   I2crbyte Hb , Ack
   I2crbyte Ia , Ack
   I2crbyte Ib , Ack
   I2crbyte Ja , Ack
   I2crbyte Jb , Ack
   I2crbyte Ka , Ack
   I2crbyte Kb , Nack                                       'Registerinhalt in Variable übernehmen und mit "Nack" beenden
   I2cstop                                                  'Stop senden
   Waitus 50                                                'Kurze Wartezeit einhalten um den I2C-Bus wieder "frei zu machen"
End Sub

' Daten vom MCP23017 abrufen (hier z.b. nur EIN Register)
Sub I2c_mcp23016_read_one
   I2cstart                                                 'Start senden
   I2cwbyte Mcp23016_adress_w                               'Adresse fürs Schreiben senden
   I2cwbyte Reg                                             'Registeradresse die als erstes gelesen werden soll
   I2cstop                                                  'Stop senden
   I2crepstart                                              'RepeatedStart senden
   I2cwbyte Mcp23016_adress_r                               'Adresse fürs Lesen senden. Der MCP folgt dieser Aufforderung mit der Ausgabe des Registerinhalts
   I2crbyte Xx , Nack                                       'Registerinhalt in Variable übernehmen und mit "Nack" beenden
   I2cstop                                                  'Stop senden
   Waitus 50                                                'Kurze Wartezeit einhalten um den I2C-Bus wieder "frei zu machen"
End Sub
Grüsse, Joe