Armins AVR-Buch - I2C_Bus_auch_TWI_genannt

Zuletzt geändert am 15.01.2021, 01:22:20

I2C_Bus_auch_TWI_genannt


(armin77, 11.02.2013, 09:25:14)

Der I2C Bus bei Atmel auch TWI genannt, ist ein einfacher serieller Bus der von Phillips entwickelt wurde.
Dieser kommt mit drei Leitungen aus. SDA, SCL und GND.
Es gibt eine riesige Anzahl von Bauteilen die sich damit betreiben lassen.
Der I2C Bus ist ein Master Slave Bus. Das heißt, daß es einen Master z.b. den AVR und mehrere Slave, wie
zum Beispiel den PCF8574 gibt.
Wie schon geschrieben sind außer GND nur zwei Pins des AVR nötig.
Das Ansprechen der Slave`s geschieht über eine 8 Bit Adresse. Ein Teil der Adresse ist Bauteil abhängig und
daher fest.
Der andere Teil der Adresse ist frei wählbar und wird zum Beipiel beim PCF8574 mit den Pins A0 bis A2 eingestellt.
Damit lassen sich bis zu acht PCF8574 an einem Bus adressieren.
Das letzte Bit der Adresse zeigt an ob gelesen (Bit0=1) oder geschrieben (Bit0=0) werden soll.

Bild adressei2c.JPG

Wichtig:

Beide Leitungen (SDA und SCL) benötigen einen Pull-Up Widerstand.
Dieser sollte zwischen 4,7k bis 10k Ohm sein.

Bild I2Cplanjpe.JPG


Ansteuern von Ausgängen

Wie steuert man nun z.b. den PCF8574 an?
Wie wir oben in der Tabelle sehen hat der PCF8574 die Basisadresse 64 (40h), wenn A0 bis A2 auf GND angeschlossen sind.
Wollen wir weitere PCF8574 an den Bus anschließen müssen wir A0 bis A2 entsprechend anders beschalten und die Adresse
dann aus der Tabelle ablesen.
SCL ist an PortC.5 und SDA ist an PortC.4 des AVR angeschlossen.
An Pin 6 des PCF8574 schließen wir eine LED über einen Transistor an.

Bild I2Cplan2.JPG

Hier ist ein Beispielprogramm um die LED am PCF8574 blinken zu lassen.


$regfile = "m8def.dat"
$Crystal=10000000
$hwstack=32
$swstack=32
$framesize=32

Config Sda = Portc.4
Config Scl = Portc.5

I2cinit

Do
I2cstart : I2cwbyte &H40 : I2cwbyte 4 : I2cstop
Wait 2
I2cstart : I2cwbyte &H40 : I2cwbyte 0 : I2cstop
Wait 2
Loop
End



Oben der bekannte Programmkopf mit Angabe des AVR Typs, der Taktfrequenz und den Stackwerten:

$regfile = "m8def.dat"
$Crystal=10000000
$hwstack=32
$swstack=32
$framesize=32


Dann legen wir die Ports für SDA und SCL fest und initialisieren den I2C Bus.
Damit werden SDA und SCL auf "1" gesetzt. Der Ruhezustand des I2C Bus.

Config Sda = Portc.4
Config Scl = Portc.5

I2cinit


Dann wird der I2C Bus Start Befehl gesendet. Hierzu wird erst SDL auf '0' gesetzt und anschließend SCL.
Danach wird die Adresse des Bausteins übermittelt.
Der angesprochende Baustein sendet nun eine Bestätigung, ein ACK-Signal (Acknowledge) in dem er die SDA Leitung auf "0" zieht.
Ist kein Baustein an dieser Adresse oder nicht bereit bleibt SDA auf "1" und es wird ein 'NACK' (No Acknowledge) empfangen.
Ist alles in Ordnung werden die Daten übermittelt. Also das Einschalten der LED.
Zum Schluß wird noch die Stop Bedingung gesendet. Dabei wird erst SCL auf '1' gesetzt und anschließend SDA auf "1"

I2cstart : I2cwbyte &H40 : I2cwbyte 4 : I2cstop


Es wird also der Pin 6 eingeschaltet.
Jetzt schalten wir ihn wieder aus.

I2cstart : I2cwbyte &H40 : I2cwbyte 0 : I2cstop


Dies funktioniert genauso wie beim einschalten.


Einlesen von Ports

Nun kann man auch den PCF8574 als Eingabebaustein nutzen.
Dazu müssen wir ihm sagen, daß wir jetzt nicht schreiben sondern lesen wollen.
Damit wird aus Bit0 (siehe Tabelle oben) eine "1". Die Adresse lautet nun für das lesen des PCF8574 nun 65 (41h)
Wir schließen nun einen Taster an Pin 6 des PCF8574 und eine LED an Port b.1 des AVR.

Bild I2Cplan3.JPG

Hier dazu ein kleines Programm:

$regfile = "m8def.dat"
$Crystal=1000000
$hwstack=40
$swstack=16
$framesize = 32

Config Portb.1 = Output
Dim Daten As Byte

Config Sda = Portc.4
Config Scl = Portc.5

I2cinit

Do

I2cstart : I2cwbyte &H41 : I2crbyte Daten , Nack : I2cstop

If Daten = 4 Then
Portb.1=1
Else
Portb.1 = 0
End If

Waitms 300

Loop
End


Es ist wieder der bekannte Programmkopf zu sehen mit Angabe des AVR,Taktfequenz und Stackwerten.
Dann wird Portb.1 an der die LED angeschlossen ist als Ausgang definiert.
Um die empfangenen Daten des I2C Bus zu speichern, deklarieren wir eine Variable Daten.
Dann wieder die Angabe der Ports für SDA und SCL und das initialisieren des I2C Bus.

Jetzt wird es interessant.
Mit I2cstart öffnen wir den Bus. Dann senden wir wieder die Baustein Adresse. Da wir jetzt lesen wollen ist Bit0 nun "1".
Die Adresse lautet nun 65 (41h).
Als nächstes lesen wir den PCF8574 aus und speichern die Daten in der Variablen Daten. Dies geschieht mit dem I2crbyte-Befehl.
Der Befehl 'Nack' sagt dem AVR, daß er nach dem Empfangen des Datenbytes ein 'No Acknowledge' senden soll.
Das bedeutet, daß wir keine weiteren Daten vom PCF8574 haben wollen.
Es gibt aber auch Bausteine, bei denen es nötig ist, ganze Datenpakete zu übertragen.
Hier muss dann so lange 'Ack' gesendet werden, bis alle Byte`s komplett sind.
Zum Schluß senden wir die Stop-Bedingung und geben den Bus wieder frei.

Nun werten wir die Variable aus. Wurde der Taster am PCF8574 gedrückt wurde der Wert "4" gesendet und wir schalten die Led
an Portb..1 des AVR ein. Ansonsten bleibt sie aus..