Die Nutzung des I2C-Interfaces

am Beispiel des PIC16F876

zurück zu Input/Output , PIC-Grundlagen , PIC-Prozessoren , Elektronik , Homepage

Einige PICs verfügen über einen MSSP-Port (master synchronous serial port). Damit lässt sich entweder ein SPI-Bus (Serial Peripheral Interface) oder ein I2C-Bus (Inter-Integrated Circuit) aufbauen.
Andere PIC-Typen (z.B. dsPIC) haben keinen MSSP, sondern getrennte Hardware für I2C und SPI.

Der SPI-Bus ist eine bidirektionale synchrone Dreidrahtverbindung. Der I2C-Bus ist ein sehr häufig eingesetzter 2-Draht-Bus.
 

PICs ohne I2C-Hardware können den I2C-Bus auch per Software emulieren. Wie das geht steht hier.

zu Beginn eine allgemeine I2C-Beschreibung
Allgemeines
Busverdrahtung
I2C am PIC
Geschwindigkeitseinstellung
Datenfluss allgemein

ab hier wird es spezifisch für 16F876
Initialisierung
Daten auf I2C-Bus schreiben
Daten vom I2C-Bus lesen
Beispiel: Daten zum EEPROM 24C04 schreiben
Beispiel: Daten vom EEPROM 24C04 lesen


Allgemeines

Der I2C-Bus (I2C = IIC = Inter-Integrated-Circuit) wurde von der Firma Philips für die Kommunikation zwischen einzelnen Schaltkreisen innerhalb eines Gerätes entwickelt. Er findet sich z.B. in vielen Geräten der Unterhaltungselektronik. In meinem Videorekorder steuert ein Mikroprozessor den Audioprozessor, den Videoprozessor, den Laufwerkscontroller u.v.m. über den I2C-Bus.

Hinweis:
Auf der Philips-Homepage  gibt es die Dokumentation des I2C-Busses unter dem Titel 'The I2C-bus specification' mit der document order number: 9398 393 40011 zum Download.

Beim I2C-Bus handelt es sich um eine synchrone serielle 2-Drahtverbindung zwischen einem Master und einer beliebigen Anzahl Slaves. Auf der einen Leitung (SCL) wird der Takt übertragen, die andere Leitung (SDA) dient der Übertragung der Daten. Die Daten können vom Controller zum Slave (schreiben) laufen, oder aber auch vom Slave zum Master (lesen). Der Takt wird dabei aber immer vom Master erzeugt. (Der Slave kann allerdings den Low-Teil des Taktes verlängern, indem er ihn so lange auf Low zieht, wie er es für nötig hält.)

Es ist auch möglich an einem Bus mehrere Master zu betreiben (Multi-Master-Bus). In dem Fall ist durch ein Protokoll gesichert, das ein Master den Bus nur übernehmen kann, wenn der Bus gerade nicht in Nutzung durch einen anderen Master ist. Damit werden Buskollisionen verhindert.

Es gibt den I2C-Bus in drei Geschwindigkeiten: mit 100 kHz Takt (Standard-Mode), mit 400 kHz-Takt (Fast-Mode) und mit 3,4 MBit/s (high speed). Der high-speed Modus wird von den PICs aber nicht unterstützt.
Die Hardware der PICs unterstützt I2C-Taktraten bis zu 1MHz, und es gibt auch einige I2C-Bausteine, die für 1 MHz ausgelegt sind (z.B. EEPROMs von Microchip). Ein offizieller Standard ist diese Geschwindigkeit aber wohl nicht.

Da alle Geräte parallel an einem Bus hängen, ist es nötig ein Adresssystem zu nutzen, um anzugeben, wer Daten empfangen bzw. senden soll. Es gibt einen 7-Bit-Adress-System und ein abwärtskompatibles 10-Bit Adress-System, die an einem Bus gemischt verwendet werden können.

Ich werde mich in meinen Erklärungen auf einen einfachen I2C-Bus mit nur einem Master (PIC16F876), einem Slave (EEPROM 24C04), einem Takt von 400 kHz und 7-Bit Adresse (24C04 hat immer eine 7-Bit -Adresse) beschränken. Das dürfte die meisten Anwendungen abdecken.

nach oben

Die Busverdrahtung

Alle Geräte hängen parallel am 2-Draht-Bus. Alle Ausgänge, die auf den Bus treiben, sind open-collector oder open-drain Stufen.Sie können die Busleitung also nur nach Masse ziehen, aber nicht auf High-Pegel (+5V). Deshalb werden für beide Leitungen je ein Hochziehwiderstand benötigt. Durch die Widerstände soll ein Mindeststrom von 3 mA fließen, deshalb sollten sie nicht größer als 1,8 kOhm sein.

+++ACHTUNG+++
Werden die Hochziehwiderstände vergessen, dann liegt der Bus ständig auf Low, und niemand  wird sich trauen, den scheinbar aktiven Bus zu übernehmen. Das System hängt dann.

nach oben

I2C am PIC

Viele PICs besitzen eine MSSP- bzw. SSP-Schnittstelle, die sich als I2C-Interface betreiben lässt. Die MSSP-Hardware unterstützt Master- und Slave-Funktionen. Die SSP-Hardware ist nur für einen Slave gedacht.
Ich beziehe mich zur Erläuterung der Funktion exemplarisch auf den PIC16F876. In anderen PICs können die verwendeten Register auf anderen Adressen oder auch in anderen Bänken liegen.

nach oben

Die Einstellung der Busgeschwindigkeit

Der Takt SCL des I2C-Busses wird im 16F876 vom PIC-Takt abgeleitet. Da der PIC aber mit verschiedensten Takten betrieben werden kann, erledigt dies ein Baud-Raten-Generator (BRG). Das ist ein programmierbarer Frequenzteiler, der den PIC Takt zum gewünschten I2C-Takt herunter teilt. Wie das im Detail zu erfolgen hat, ist weiter unten erläutert.

Zwar lassen sich nicht bei jedem PIC-Takt exakt 100 kHz oder 400 kHz erzeugen, aber so genau muss der Takt auch gar nicht eingehalten werden. Hauptsache der erzeugte Takt ist nicht höher als der vom angeschlossenen Chip akzeptierte Höchsttakt.

nach oben

Der Datenfluss

Bus-Übernahme (Start)

Jede Aktion geht vom Master aus. Sollen Daten auf dem Bus bewegt werden, dann muss der Master den Bus erst einmal übernehmen. Dazu schaut sich der Master die Pegel auf beiden Leitungen (SCL & SDA) an. Nur wenn beide Leitungen High-Pegel haben beginnt er mit der Arbeit (Hochziehwiderstände nicht vergessen!).
Als erstes zieht der Master die Datenleitung SDA auf Masse, während die Taktleitung SCL noch auf High ist. Damit gehört der Bus ihm, und alle am Bus angeschlossenen Geräte erkennen dieses Startsignal als Ankündigung, dass gleich etwas auf dem Bus passieren wird.

+++ACHTUNG+++
Falls sich der Pegel der SDA-Leitung ändert, während SCL auf High liegt, dann wird das immer als Steuersignal interpretiert, also als Busübernahme oder Busfreigabe. Während der normalen Kommunikation darf sich deshalb SDA nie ändern, während SCL auf High liegt!
 

Adressierung

Jeder Datentransfer wird mit der Adressierung eingeleitet, damit geklärt ist, welcher Slave für die Kommunikation mit dem Master erkoren wurde. Es gibt eine 7-Bit Adressierung (7-Bit lange Adresse) und eine 10-Bit Adressierung. Welcher Adresstyp verwendet wird, hängt von den verwendeten Slaves ab.
(Es gibt ein Philips-Dokument vom März 1997 "I2C-bus allocation table" in dem die Zuordnung aller 7-Bit-Adressen zu Schaltkreistypen festgelegt ist.)

Woher kennen die Slaves eigentlich ihre Adressen?
Jeder I2C-Schaltkreis-Typ hat eine feste Adresse, in der aber einige Bits in der Regel über Schaltkreispins festgelegt werden, indem diese Pins fest mit Masse oder Betriebsspannung verbunden werden. Der EEPROM 24C04 hat z.B. die Adresse 1010xxx wobei der Wert von xxx durch die Pegel an den Pins 1, 2 & 3 (A0 ..A3) festgelegt werden. Sind alle drei Pins mit Masse verbunden, so hat der 24C04 also die Adresse 1010000.
 

vom Master zum Slave

Der Master schiebt nach der Übernahme des Busses eine 7-Bit lange Slave-Adresse auf den Bus, dabei sind die einzelnen Bits (MSB zuerst) jeweils mit der steigenden Flanke von SCL gültig. Es folgt als 8. Bit eine 0. Diese 0 ist das Kennzeichen, das Daten zum Slave geschrieben werden sollen.
Alle Slaves am Bus vergleichen nun die gesendete Adresse mit ihrer eigenen Adresse. Stimmt für einen Chip die Adresse überein (und ein Chip sollte sich eigentlich immer angesprochen fühlen, wenn der Programmierer sauber gearbeitet hat), dann zieht dieser Slave die Datenleitung nun seinerseits auf Low und wartet auf den nächsten Takt vom Master (Takt Nr. 9) und hält während dieses Taktes die Datenleitung weiterhin auf Low (Signal ACK). Das ist für den Master das Zeichen dafür, dass ein Empfänger bereit ist.
Der Slave kann  nach dem Ende des neunten Taktes die Taktleitung für eine Weile auf Low halten, und damit den Masters vorübergehend stoppen. Damit kann der Slave den Datenstrom bremsen, wenn er die empfangenen Daten erst intern weiterleiten muss. (Im 100kHz- und 400kHz-Mode ist das sogar bei jedem einzelnen Takt erlaubt.)

Der Master überträgt jetzt 8-Bit lange Datenworte über den Bus, die jeweils von einem 9.Takt gefolgt werden. Der Slave liest die Datenworte ein, und zieht jeweils während des 9. Taktes die Datenleitung auf Low (ACK). Das ist für den Master das Zeichen, das die Daten angenommen wurden, und er weiter machen kann.

Wichtig ist, dass der Zustand der Datenleitung SDA nur geändert wird, während der Pegel der Taktleitung SCL Low ist. Ansonsten kann das Signal versehentlich als Busfreigabe fehlinterpretiert werden, und die Kommunikation bricht zusammen.

vom Slave zum Master

Der Master schiebt nach der Übernahme des Busses eine 7-Bit lange Slave-Adresse auf dem Bus dabei sind die einzelnen Bits (MSB zuerst) jeweils mit der steigenden Flanke von SCL gültig. Es folgt als 8. Bit eine 1. Diese 1 ist das Kennzeichen, das Daten vom Slave gelesen werden sollen.
Alle Slaves am Bus vergleichen nun die gesendete Adresse mit ihrer eigenen Adresse. Stimmt für einen Chip die Adresse überein, dann wartet dieser Slave auf den nächsten Takt vom Master (Takt Nr. 9) und zieht während dieses Taktes die Datenleitung auf Low (Signal ACK). Das ist für den Master das Zeichen dafür, dass ein Sender bereit ist.

Der Slave kann nach dem Ende des neunten Taktes die Datenleitung auf Low halten, und damit den Takt des Masters vorübergehend stoppen. Damit kann der Slave den  Datenstrom bremsen, wenn er die zu sendenden Daten erst intern bereitstellen muss.

Der Master überträgt jetzt jeweils  8-Takte während derer der Slave die Datenbits (MSB zuerst) auf den Datenbus legt. Der Master liest diese 8 Bit nacheinander ein. Danach kann er ein ACK senden, indem er während eines 9. Takts die Datenleitung auf Low zieht.
 

Bus-Freigabe (Stop)
Zum Schluss muss der Master den Bus wieder freigeben.
Normalerweise liegt nach dem Senden oder Empfangen die Taktleitung auf High und die Datenleitung auf Low.
Ausgehend von diesem Zustand schaltet der Master die Datenleitung SDA von Low auf High, während die Taktleitung SCL auf High liegt. Damit ist der Bus wieder frei.
  

nach oben

10-Bit Adressierung

Bisher habe ich mich auf die 7-Bit Adressierung beschränkt, die aber nur 128 verschiedene Adressen zulässt. Parallel existiert aber auch eine 10-Bit-Adressierung, die mit 1024 möglichen Adressen schon mehr Möglichkeiten bietet. Um die 10-Bit-Adressierung zur 7-Bit-Adressierung abwärtskompatibel zu machen, bedient man sich eines einfachen Tricks. Die 10-Bit-Adresse wird mit dem Präfix "11110" zu einer 16-Bit-Zahl verlängert, und dann diese zwei Bytes einfach nacheinander über den Bus übertragen. Chips, die nur die 7-Bit-Adressierung kennen, verwerten natürlich nur das erste Byte, und sehen eine Adresse der Form "11110xx". Diese Adresse ist aber für 7-Bit-Chips nicht vergeben worden. folglich ignorieren diese Chips die Übertagung.
Chips mit 10-Bit-Adressierung dagegen erkennen den typischen Präfix, lesen beide Bytes ein und nutzen davon die letzten 10 Bit als Adresse.

nach oben

MSSP-Modul im Master-Mode

Der weitere Text auf dieser Seite beschreibt die Nutzung des MSSP-Moduls des PIC16F87x als I2C-Interface. Die Hardware dieses Moduls unterstützt sowohl den Master-Mode wie auch den Slave-Mode. Ich benutze in diesem Beispiel den Master-Mode, und steuere einen EEPROM an, der als Slave arbeitet. 

Einige PICs (z.B. PIC16F88) haben anstelle des MSSP-Moduls nur ein SSP-Modul. Das hier fehlende M in der Bezeichnung stand für Master, folglich unterstützt diese Hardware nur den I2C-Slave-Mode. (Es fehlt u.A. die komplette I2C-Takterzeugung.)  Mit entsprechendem Softwareaufwand kann man trotzdem einen I2C-Master-Mode erreichen. Dafür muss die fehlende Hardware durch Software emuliert werden. Microchip spricht dann von I2C firmware controlled Master mode und beschreibt das in der Application Note AN554.

Einige PICs (z.B. PIC16F628) haben gar keine spezielle I2C-Hardware. Aber wie man auch einen PIC ohne MSSP oder SSP als I2C-Master verwenden kann ist auf einer anderen Seite beschrieben.


Initialisierung
Das MSSP-Modul hat 6 Register, die für die I2C-Funktionen von Bedeutung sind:

Einstellung der IO-Ports

Für I2C werden die beiden Pins RC3 und RC4 des PortC benutzt. Sie sind zunächst als Input zu initialisieren, damit sie später vom MSSP-Modul als SCL und SDA benutzt werden können.

; einstellen von RC3 & RC4 auf input
    bsf     STATUS, RP0         ; Bank 1
    movlw   B'00011000'         ; RC3,4 inputs
    iorwf   TRISC, f            ; + RC2=CCP1 output
    bcf     STATUS, RP0         ; Bank 0
 

Einstellung der Busgeschwindigkeit

Die Busgeschwindigkeit wird eingestellt, indem der geeignete Teilerwert (Berechnung siehe oben) in das Adressregister SSPADD (Adresse 93h) geschrieben wird, während der Master gerade nicht den I2C-Bus benutzt, also z.B. während der Initialisierungsphase im Programm. Der neue Teilerwert wird dann umgehend in den BRG übernommen

SSPADD: MSSP-Adress-Register (ADDRESS 93h):


bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
Name: - BRG6 BRG5 BRG4 BRG3 BRG2 BRG1
BRG0
Wert:
-
0 oder 1
0 oder 1
0 oder 1
0 oder 1
0 oder 1
0 oder 1
0 oder 1

SCL = PICtakt  / ( 4 * (BRG+1) )

BRG = (PIC / (4 * SCL)) -1

Die folgende Tabelle enthält sie nötigen SSPADD-Werte für 100 kHz bzw. 400 kHz I2C-Takt bei verschiedenen PIC-Takten. Bei den mit einem '*' gekennzeichneten Werten  lässt sich die Frequenz nicht präzise einstellen. Der Takt ist etwas niedriger, was aber erlaubt ist:
 

PIC-Takt
4 MHz
8 MHz
10 MHz
12 MHz
16 MHz
20 MHz
SSPADD für 100 kHz
9
19
24
29
39
49
SSPADD für 400 kHz
2*
4
6*
7*
9
12*

Um bei einem PIC-Takt von 20 MHz einen I2C-Takt von 400 kHz einzustellen muss also SSPADD mit 12 geladen werden. Das ergibt zwar nur einen Takt von 385 kHz, aber der nächstschnellere Takt  (Wert 11) wäre mit 417 kHz schon nicht mehr in der Spezifikation des 24C04 EEPROMs.

; einstellen des I2C-Taktes auf knapp 400 kHz
    bsf     STATUS, RP0         ; Bank 1
    movlw   d'12'               ; clock = 20/(4*(12+1)) = 385kHz
    movwf   SSPADD              ; für I2C
    bcf     STATUS, RP0         ; Bank 0
 

Aktivieren des I2C-Interfaces

Das I2C-Interface wird im Register SSPCON eingestellt

SSPCON: MSSP-Control-Register (ADDRESS 14h):


bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
Name: WCOL SSPOV SSPEN CKP SSPM3 SSPM2 SSPM1
SSPM0
Wert:
0 oder 1
0 oder 1
0 oder 1
0 oder 1
1
0
0
0

Die Betriebsart des MSSP-Moduls wird mit den unteren 4 Bit dieses Registers eingestellt. Der normale I2C-Master-Mode ergibt sich mit der Einstellung 1000.

    movlw   B'00001000'         ; master mode, clock=Fosc/(4*(SSPADD+1))
    movwf   SSPCON              ;

Nachdem die Betriebsart feststeht, muss das MSSP-Modul nun noch eingeschaltet werden. Das geschieht durch Setzen des Bits SSPEN (SSP enable) im SSPCON-Register. Damit werden die Pins RC3 und RC4 gleichzeitig vom Port C gelöst, und an die I2C-Hardware des PIC angeschlossen.

    bsf     SSPCON, SSPEN       ; MSSP-Modul enable

Damit wäre das I2C-Interface des 16F876  bereit.

nach oben


Daten auf den I2C-Bus schreiben

Um ein Daten auf dem I2C-Bus auszugeben, müssen folgende Schritte durchgeführt werden:

Dabei muss man darauf achten, das der PIC einen Schritt abgeschlossen hat, bevor man mit dem nächsten beginnt.

Bus übernehmen
Um den Master den Bus übernehmen zu lassen, setzt man das Bit SEN im Register SSPCON2. Hat der PIC den Bus übernommen, dann setzt er (als Zeichen des Erfolgs) das Bit SSPIF im Register PIR1. Solange sollte man warten. Danach muss man das SSPIF Bit manuell wieder zurücksetzten.

; I2C-Bus im Master-Mode übernehmen
i2c_on  bcf     PIR1, SSPIF     ; SSPIF Bit löschen
        bsf     STATUS, RP0
        bsf     SSPCON2, SEN    ; Bus Übernahme anweisen
        bcf     STATUS, RP0
i2c_t1
        btfss   PIR1, SSPIF     ; Testen, ob Bus schon übernommen wurde
        goto    i2c_t1          ; nein, noch nicht
        bcf     PIR1, SSPIF     ; ja, der Bus ist mein! nun noch SSPIF zurücksetzen

Adresse / Datenbyte senden
Nun kann man ein Byte senden. Das erste Byte ist immer eine Adresse.  An die 7 Bit der Slave-Adresse wird eine 0 als LSB angehangen. Das ist das Kennzeichen dafür, das der Master auf den Slave schreiben will. Anschließend sendet man die Datenbytes. Prinzipiell unterscheidet sich das Senden von Adressen und Daten aber nicht:

Dafür schiebt man das zu sendende Byte einfach in das Register SSPBUF. Der PIC sendet das Byte dann selbständig. Dann wartet er auf ACK vom Slave. Wurde ACK empfangen, dann setzt er das SSPIF-Bit im Register PIR1. So lange sollte man warten. Danach muss man das SSPIF Bit manuell wieder zurücksetzten.

        movlw   H'A0'           ; '1010 0000' soll gesendet werden
; ein Byte aus W senden
i2c_tx
        movwf   SSPBUF          ; -> zum I2C-Slave übertragen
i2c_t2
        btfss   PIR1, SSPIF     ; ACK schon empfangen?
        goto    i2c_t2          ; nein, noch nicht
        bcf     PIR1, SSPIF     ; ja, Daten sind im Slave, nun noch SSPIF zurücksetzen

Das wiederholt sich nun für alle zu sendenden Bytes.

den Bus wieder freigeben
Abschließend soll der Master den Bus wieder freigeben. Dazu setzt man das Bit PEN im Register SSPCON2. Hat der PIC den Bus wieder freigegeben, dann setzt er  das Bit SSPIF im Register PIR1. Solange sollte man warten. Danach muss man das SSPIF Bit manuell wieder zurücksetzten.

; I2C-Bus wieder freigeben
i2c_off
        bsf     STATUS, RP0
        bsf     SSPCON2, PEN    ; Bus Freigabe anweisen
        bcf     STATUS, RP0
i2c_t8
        btfss   PIR1, SSPIF     ; Bus schon freigegeben?
        goto    i2c_t8          ; nein, noch nicht
        bcf     PIR1, SSPIF     ; ja, alles fertig, nun noch SSPIF zurücksetzen
 

nach oben


Daten vom I2C-Bus lesen

Um ein Daten vom Slave zu lesen, müssen folgende Schritte durchgeführt werden:

Dabei muss man darauf achten, das der PIC einen Schritt abgeschlossen hat, bevor man mit dem nächsten beginnt.

Bus übernehmen
erfolgt genau wie beim Schreiben.

Adresse senden
Nun muss man die Adresse des Slave senden.  An Ihre 7 Bit der  wird eine 1 als LSB angehangen. Das ist das Kennzeichen dafür, das der Master aus den Slave lesen will.
Das Programmstück zum Senden ist mit dem vom I2C-Bus-Schreiben praktisch identisch.

Datenbytes empfangen
Nun will der Slave ein Byte senden, dafür benötigt er aber den Takt vom Master. Es genügt, im Register SSPCON2das Bit RCEN (receive enable) zu setzen, und der PIC erzeugt den Takt und liest die Slave-Daten in das Register SSPBUF ein. Danach setzt er das Bit SSPIF im Register PIR1. Solange sollte man warten. Danach muss man das SSPIF Bit manuell wieder zurücksetzten.

;ein Byte vom Slave empfangen
i2c_rx
        bsf     STATUS, RP0
        bsf     SSPCON2, RCEN   ; Daten Empfang einschalten
        bcf     STATUS, RP0
i2c_r7
        btfss   PIR1, SSPIF     ; Daten Empfang fertig?
        goto    i2c_r7          ; nein, noch nicht
        bcf     PIR1, SSPIF     ; ja, nun noch SSPIF zurücksetzen

        movf    SSPBUF, w       ; empfangene Daten -> W
        movwf   RXData          ; empfangene Daten -> RXData

Falls ein weiteres Byte gelesen werden soll, ist zuvor das ACK-Signal zu senden. Dafür setzte man nun einfach das Bit ACKEN im Register SSPCON2. Nach dem Empfang des letzten Datenbytes ist das aber nicht erforderlich.

        bsf     STATUS, RP0
        bsf     SSPCON2, ACKEN   ; ACK senden
        bcf     STATUS, RP0

Die Routine i2c_rx  wird für alle zu empfangenen Bytes wiederholt.

den Bus wieder freigeben
erfolgt genau wie beim Schreiben.
 

nach oben


Beispiel: Daten in den EEPROM 24C04 schreiben

Ein PIC16F876-20 ist via I2C-Bus mit einem EEPROM 24C04 verbunden worden. Beide Leitungen haben 1kOhm-Widerstände nach Vdd.

+++ ANMERKUNG +++
Dieses Beispiel strebt nicht die höchste Effizienz an, sondern soll das Prinzip erläutern. Generell wäre es sinnvoll beim Speichern vieler Werte im EEPROM ein Seiten- (Page)- weises Schreiben zu benutzen, um den Vorgang zu beschleunigen und den EEPROM zu schonen.
 

Um ein Byte in eine Speicherzelle des 24C04 zu schreiben, muss man zum EEPROM zuerst die Speicher-Adresse der Speicherzelle und danach den zu speichernden Wert übertragen. Der I2C-Bus muss also 2 Byte zum 24C04 übertragen. Vorher muss der 24C04 natürlich adressiert werden.
Der 24C04 hat die 7-Bit-I2C-Adresse 1010000 und wir wollen den Wert 5 in die Speicher-Adresse 3 schreiben. Für die Standardaufgaben sind 4 kleine Unterprogramme zuständig:

Wie ein Schaltkreis via I2C-anzusteuern ist, geht aus seinem Datenblatt hervor. Um ein Byte in einen 24c04 zu schreiben, muss man auf dem I2C-Bus zuerst die Adresse des EEPROM übertragen, dann 2 Byte Adresse (erst high- dann low-Teil) und abschließend das zu schreibenden Datenbyte.
Nachdem der Master den Bus wieder frei gibt, beginnt der 24C04 die betroffene Zelle zu löschen und anschließend mit dem neuen Wert zu beschreiben. Das dauert etwa 10 ms. Während dieser Zeit ist der 24C04 nicht ansprechbar. Er reagiert nicht auf den I2C-Bus. Ab besten man legt eine 10 ms Warteschleife ein, falls man gleich wieder auf den EEPROM zugreifen muss.
 
;**Schreibe Wert 5 auf Speicher-Adresse 3 in 24C04*************
        call    i2c_on          ; Bus aktiv

        movlw   H'A0'           ; 1010 0000
        call    i2c_tx          ; 24C04 zum Schreiben adressieren

        movlw   0x00            ; high Teil der Adresse (Page)
        call    i2c_tx
        movlw   0x03            ; low Teil der  Adresse
        call    i2c_tx

        movlw   0x05            ; Wert der auf Adresse 3 soll
        call    i2c_tx

        call    i2c_off         ; Bus freigeben
; Fertig. Nun beginnt im EEPROM ein Lösch-Schreib-Zyklus
; mit dem der Wert 5 in die EEPROM-Zelle 3 geschrieben wird.
; Das wird etwa 10 ms dauern. Solange ist der 24C04 nicht ansprechbar.
;
        ....                    ; das Programm geht dann irgentwie weiter
 
 

;***I2C UNTERPROGRAMME************************************************************
;
; I2C-Bus im Master-Mode übernehmen
i2c_on  bcf     PIR1, SSPIF     ; SSPIF Bit löschen
        bsf     STATUS, RP0
        bsf     SSPCON2, SEN    ; Bus Übernahme anweisen
        bcf     STATUS, RP0
        goto    i2c_warte

; ein Byte aus W senden
i2c_tx
        movwf   SSPBUF          ; -> zum I2C-Slave übertragen
        goto    i2c_warte

;ein Byte vom Slave empfangen (nach SSPBUF)
i2c_rx
        bsf     STATUS, RP0
        bsf     SSPCON2, RCEN   ; Daten Empfang einschalten
        bcf     STATUS, RP0
        goto    i2c_warte

; I2C-Bus wieder freigeben
i2c_off
        bsf     STATUS, RP0
        bsf     SSPCON2, PEN    ; Bus Freigabe anweisen
        bcf     STATUS, RP0

i2c_warte
        btfss   PIR1, SSPIF     ; fertig?
        goto    i2c_warte       ; nein, noch nicht
        bcf     PIR1, SSPIF     ; ja, alles fertig, nun noch SSPIF zurücksetzen
        return

;***ENDE UNTERPROGRAMME**********************************************************

nach oben


Beispiel: Daten vom EEPROM 24C04 lesen

Wenn man einen Slave via I2C adressiert, dann kann man von ihm entweder nur lesen, oder nur auf ihn schreiben. Um aus einer bestimmten Speicherzelle aber das Datenbyte auszulesen, muss man die Adresse über den I2C-Bus schreiben, und anschließend das Datenbyte lesen. Das geht nur, wenn man dafür den I2C-Bus 2 Mal aktiviert. Das erste man um die Speicher-Adresse zum EEPROM zu übertragen, und ein 2. Mal zum Lesen des Datenbytes.

Der 24C04 hat die I2C-Adresse 1010000 und wir wollen den Wert aus der Speicher-Adresse 3 auslesen. Für die Standardaufgaben sind die Unterprogramme aus dem obigen Beispiel zuständig:

Wie ein Schaltkreis via I2C-anzusteuern ist, geht aus seinem Datenblatt hervor. Um ein Byte in aus einem 24C04 zu lesen, muss man auf dem I2C-Bus zuerst die Adresse des EEPROM übertragen, dann 2 Byte Adresse (erst high- dann low-Teil).
 
;**Stelle EEPROM auf Speicher-Adresse 3 ein*************
        call    i2c_on          ; Bus aktiv

        movlw   H'A0'           ; 1010 0000
        call    i2c_tx          ; 24C04 zum Schreiben adressieren

        movlw   0x00            ; high Teil der Adresse
        call    i2c_tx
        movlw   0x03            ; low Teil der  Adresse
        call    i2c_tx

        call    i2c_off         ; Bus freigeben

Nun steht der Adress-Pointer im 24C04 auf dem Wert 3. Nun können wir den I2C-Bus erneut aktivieren, um ein Byte aus dem 24C04 zu lesen. Das ist unser Datenbyte.

;**Lesen des aktuellen Bytes aus 24C04*************
        call    i2c_on          ; Bus aktiv

        movlw   H'A1'           ; 1010 0001
        call    i2c_tx          ; 24C04 zum Lesen adressieren

        call    i2c_rx
        movfw   SSPBUF          ; I2C Empfangsregister auslesen
        movwf   Datenpuffer     ; Byte in Speicherzelle Datenpuffer retten

        call    i2c_off         ; Bus freigeben

Das war's. Das gelesene Byte steht nun in der (hoffentlich irgendwo per EQU deklarierten) Zelle 'Datenpuffer'.
Es ist übrigens nicht unbedingt nötig, den Bus am Ende der Speicher-Adress-Übertragung freizugeben. Die gleich darauf folgende Bus-Aktivierung würde bei aktivem Bus den Bus kurz freigeben, um ihn dann sofort wieder zu übernehmen.
 

nach oben

zurück zu Input/Output , PIC-Grundlagen , PIC-Prozessoren , Elektronik , Homepage
Autor: sprut
erstellt: 16.10.2002
letzte Änderung: 22.04.2010