Datenaustausch zwischen zwei (oder mehreren) PIC16Fxx-Mikrocontrollern via I²C in C (Elektronik)

(oder: Wie realisiere ich einen I²C-Slave mit einem PIC16Fxx-Mikrocontroller)

zurück zu Elektronik, Homepage


5. Demonstrationsbeispiele

Das folgende Beispiel dient nur zur Demonstration. Es zeigt eine mögliche Einbindung der zuvor beschriebenen ISR (Interrupt-Service-Routine) für den I²C-Slave. Neben einem PIC16Fxx als I²C-Slave dient ein weiterer Mikrocontroller vom Typ PIC16Fxx als I²C-Master. Weitere I²C-Slaves sind ein I/O-Expander vom Typ PCF8574 zur 8-Bit-Eingabe mittels Jumper und ein zweiter I/O-Expander vom gleichen Typ PCF8574 zur 8-Bit-Ausgabe mittels Leuchtdioden (LEDs).

Die Aufgabe des I²C-Masters ist es nun:

  1. 8-Bit-Wert vom I²C-Eingabemodul (mit PCF8574) lesen und am PIC-I²C-Slave am Port D mittels 8 Leuchtdioden (LEDs) ausgeben.
  2. 8-Bit-Wert vom PIC-I²C-Slave vom Port A einlesen und am I2C-Ausgabemodul (mit PCF8574) anzeigen (mittels 8 Leuchtdioden).
nach oben

5.1. Schaltung (Hardware)

Die Abbildung 7 zeigt die gesamte Schaltung für dieses Demonstrationsbeispiel.

Demonstrationsbeispiel, Schaltung

Der schwarz gezeichnete Schaltungsteil kennzeichnet den PIC-I²C-Slave. Dieser Schaltungsteil entspricht der Schaltung aus Abbildung 2. Zusätzlich sind hier die Jumper und Pull-Up-Widerstände am Port A, sowie die Leuchtdioden und die dazugehörigen Vorwiderstände am Port D (grau dargestellt). Der externe Oszillator X1 mit den Kondensatoren C2 und C3 sowie dem Widerstand R2 werden hier nicht benötigt, da der interne Oszillator verwendet wird. Diese sind daher ebenfalls grau gekennzeichnet. Weiters sind die Jumper JP1 bis JP10 so wie in Abbildung 7 zu setzen. JP1 bis JP6 definieren die I2C-Slave-Adresse. Hier 0011000 R/W. Als Mikrocontroller für den I²C-Slave wurde hier der Typ PIC16F887 verwendet.

Der zweite Mikrocontroller (IC2) ist ebenfalls vom gleichen Typ (PIC16F887) und dient hier als I²C-Master. Dieser Schaltungsteil ist genau wie in Abschnitt 4.1 beschrieben. (Wichtig sind hier die Pull-Up-Widerstände an den I/O-Pins SCL, SDA und INT).

An den I²C-Bus sind neben dem PIC-I²C-Slave (rund um IC1) auch die beiden I/O-Expander vom Typ PCF8574 angeschlossen (IC3 und IC4). Wichtig sind die I²C-Slave-Adressen die hier ebenfalls mit Jumpern ausgewählt werden können. Bei IC3 sind die Jumper für A1 und A2 gesteckt, während bei IC4 nur der Jumper für A2 gesteckt ist. Es versteht sich von selbst, dass beide I/O-Expander unterschiedliche Slaveadressen besitzen müssen, und dass die Slaveadresse des PIC-I²C-Slave sich von denen der I/O-Expander unterscheiden muss!

Die Spannungsversorgung besteht hier aus einem Labornetzgerät und beträgt 5V.

nach oben

5.2. Software für 1. Demo (Slave)

Beim ersten Demonstrationsbeispiel sendet der I2C-Master nur ein Datenbyte zum PIC-I²C-Slave, bzw. liest anschließend auch nur ein Datenbyte vom PIC-I²C-Slave.

Beachte:
Da bei diesem ersten Demonstrationsbeispiel nur ein Datenbyte gesendet bzw. nur ein Datenbyte gelesen wird, vereinfacht sich das Flussdiagramm (aus Abbildung 5, 3.2. Software). Es sind nämlich kein Lesezeiger und kein Schreibzeiger notwendig. Siehe auch 5.3. Anmerkungen zur Software für 1. Demo (Slave)
Listing 1 (Teil 1)
Listing 1 (Teil 2)
Listing 1 (Teil 3)
Listing 1 (Teil 4)
Listing 1 (Teil 5)
Listing 1 (Teil 6)
Listing 1 (Teil 7)
Listing 1 (Teil 8)
nach oben

5.3. Anmerkungen zur Software für 1. Demo (Slave)

Der Quellcode für dieses Demonstrationsbeispiel wurde in C mit der freien Demoversion des mikroC-Compilers erstellt7.

Die Software (für den PIC-I²C-Slave) besteht im Wesentlichen aus den folgenden Programmteilen:

Hauptprogramm:
Die Aufgabe des Hauptprogramms (Zeilen 473 bis 481) ist hier "nur" das Initialisieren des Mikrocontrollers. Dies erfolgt mit dem Unterprogramm Init (Zeile 476). Alles andere erfolgt in der Interrupt-Service-Routine (ISR).

Unterprogramm Init:
Das Unterprogramm Init (Zeilen 152 bis 463) dient zur Initialisierung des Mikrocontrollers. Hier werden die benötigten Hardwaremodule konfiguriert. Für den PIC-I²C-Slave sind das zunächst der interne Oszillator (Zeile 158), sämtliche Ports als Ein- oder Ausgang kunfigurieren und als digitale Ein-/Ausgabepins konfigurieren (Zeilen 193 bis 292). Wichtig ist dass die Portpins (SDA und SCL) als Eingang konfiguriert werden.
Ganz wichtig ist hier natürlich das SSP-Modul, denn dieses ist für die Kommunikation via I²C zuständig. Im Register SSPCON wird u.a. ausgewählt dass der Mikrocontroller im I²C-Slave-Mode betrieben wird (Zeile 296). Wichtig ist auch dass der I²C-Slave über eine Slave-Adresse verfügt. Dafür ist das Register SSPADD zuständig. Da bei diesem Demonstrationsbeispiel die Slave-Adresse am Port B des Mikrocontrollers ausgewählt werden kann muss diese vom Port B gelesen werden und die entsprechenden Bits müssen in das Register SSPADD geschrieben werden. Beachte: Bit 0 gibt die Datenflussrichtung aus Sicht des Masters an (also Master schreibt Daten oder liest Daten, Zeilen 403 bis 407). Als letzter Schritt muss noch der SSP-Interrupt freigegeben werden. Bit SSPIE im Register PIE1 (Zeile 411). Weiters die Globale Interruptfreigabe (Bit GIE im Register INTCON), sowie das Bit PEIE ebenfalls im Register INTCON (Zeile 437).

Interrupt-Service-Routine (kurz: ISR):
Die SSP-ISR (Zeilen 79 bis 130) wird jedesmal aufgerufen wenn ein gesamtes Datenbyte vom SSP-Hardware-Modul empfangen wurde und dieses für den PIC-Slave mit der Adresse im Register SSPADD bestimmt ist. Jedesmal wenn diese SSP-ISR aufgerufen wird muss eine der folgenden vier Fälle ausgeführt werden (vgl. Flussdiagramm in Abbildung 5 aus Abschnitt 3.2.) jedoch hier ohne Lese- und Schreibezeiger, da nur ein Datenbyte gelesen bzw. geschrieben (gesendet) wird.).

Fall 1: Schreibzugriff aus Sicht des Masters, zuletzt wurde die Slave-Adresse empfangen (Bits: SSPSTAT.R_W = 0, SSPSTAT.D_A = 0):
In diesem Fall muss der Mikrocontroller (Slave) die empfangenen Daten aus dem SSP-Buffer (Register SSPBUF) lesen, kann den Inhalt von SSPBUF aber verwerfen, da es nur die Adresse und keine Daten enthält (Zeile 89). Hier wird der Inhalt von SSPBUF in ein Dummy-Register geschrieben. Wichtig ist das dass Register SSPBUF gelesen wird, weil dadurch Steuerbits für das Hardwaremodul verändert werden. Wichtig sind auch die folgenden Codezeilen 90 bis 93. Das SSP-Interrupt-Flag (SSPIF) muss ebenfalls gelöscht werden, da sonst dieser Interrupt sofort wieder ausgelöst wird!

Fall 2: Schreibzugriff aus Sicht des Masters, zuletzt wurde ein Datenbyte empfangen (Bits: SSPSTAT.R_W = 0, SSPSTAT.D_A = 1):
Jetzt handelt es sich tatsächlich um die Nutzdaten. Bei diesem Demonstrationsbeispiel wird nur ein 1 Datenbyte übertragen. Daher sind dies die einzigen Nutzdaten und können vom Register SSPBUF gelesen und in ein eigenes Register gespeichert werden, oder so wie hier direkt am Port D ausgegeben werden (Zeile 99). Auch hier sind die folgenden Codezeilen 101 bis 103 wichtig und dürfen nicht weggelassen werden!

Fall 3: Lesezugriff aus Sicht des Masters, zuletzt wurde die Slave-Adresse empfangen (Bits: SSPSTAT.R_W = 1, SSPSTAT.D_A = 0):
In diesem Fall müssen die zu sendenden Nutzdaten in das Register SSPBUF geschrieben werden. Hier, bei diesem Demonstrationsbeispiel ist dies der Inhalt von Port A (Zeile 114). Auch hier sind die folgenden Codezeilen 116 bis 118 wichtig und dürfen nicht weggelassen werden!

Fall 4: Lesezugriff aus Sicht des Masters, zuletzt wurde ein Datenbyte gesendet (Bits: SSPSTAT.R_W = 1, SSPSTAT.D_A = 1):
Meiner Ansicht nach dürfte bei diesem Demonstrationsbeispiel dieser Fall gar nicht auftreten, da vom Master nur ein Datenbyte gelesen werden darf. Daher wird in diesem Fall nur der Inhalt einer Dummy-Variable (cDummy) in das Register SSPBUF geschrieben (Zeile 124). Auch hier sind die folgenden Codezeilen 125 bis 127 wichtig und dürfen nicht weggelassen werden!

Mehr als das Lesen des SSPBUF-Registers oder das Schreiben in das SSPBUF-Register ist in der Interrupt-Service-Routine (ISR) nicht zu tun. Alles andere übernimmt das Hardware-Modul SSP des Mikrocontrollers.

Sonstiges:
Am Beginn des Quellcodes befinden sich die folgenden Definitionen und Einstellungen:

Ein kleiner Nachteil beim mikroC-Compiler ist, dass die Konfigurationsbits für den PICMikrocontroller in der IDE gesetzt werden müssen. Ich persönlich würde diese lieber im Quellcode mit einer geeigneten Anweisung setzen.

Hier sind die notwendigen Einstellungen für den PIC16F887 für dieses Demonstrationsbeispiel (für Slave und Master):

nach oben

5.4. Software für 1. Demo (Master)

Für den I²C-Bus-Master wurde hier ebenfalls ein Mikrocontroller vom Typ PIC16F887 verwendet. Dieser hat hier folgende Aufgabe: Jedes mal wenn sich bei IC3 (PCF8574) zumindest ein Port-Pin (P0 bis P7) ändert erzeugt dieser Chip einen Interrupt, indem der Ausgang INT (Pin 13) den Pegel von High auf Low ändert. Daraufhin soll der Master diesen (geänderten) Eingang lesen und am PIC-I²C-Slave (am Port D) ausgeben. Danach soll der Master die Daten vom PIC-I²C-Slave (vom Port A) lesen und am IC4 (PCF8574) ausgeben.

Der Quellcode für den I²C-Bus-Master (mit dem PIC16F887, IC2) ist zur besseren Übersicht in mehrere Dateien aufgeteilt:

Zuerst die Datei I2C_Demo_PIC_Master.c:

Listing 2 (Teil 1)
Listing 2 (Teil 2)
Listing 2 (Teil 3)
Listing 2 (Teil 4)

Datei PCF8574.H:

Listing 3

Datei PCF8574.C:

Listing 4 (Teil 1)
Listing 4 (Teil 2)
Listing 4 (Teil 3)
nach oben

5.5. Anmerkungen zur Software für 1. Demo (Master)

Auch dieser Quellcode wurde in C mit der freien Demoversion des mikroC-Compilers erstellt.

Die Software (für den PIC-I²C-Master) besteht im Wesentlichen aus den folgenden Programmteilen:

Hauptprogramm:
Zuerst muss der Mikrocontroller initialisiert werden. Diese Aufgabe übernehmen die Unterprogramme Init(), Zeile 153 und I2C_Init(), Zeile 156.

Danach werden zum ersten Mal die Portpins vom I²C-Eingabemodul mit dem PCF8574 (IC3) gelesen und am I2C-PIC-Slave ausgegeben. Das Lesen vom I²C-Eingabemodul geschieht mit dem Unterprogramm I2C_PCF8574_ReadData (Zeile 159). Übergabeparameter ist hier die Moduladresse (3-Bit entsprechend den Pins A2 bis A0). Hier der Wert 1, da A0 offen ist - also den Pegel High besitzt, während A1 und A2 via Jumper auf low-Pegel liegen (vgl. Schaltung in Abbildung 7, Abschnitt 5.1).
Für das Ausgeben der Daten am I²C-PIC-Slave muss zunächst die I²C-Startbedingung erzeugt werden (Zeile 161) anschließend die Adresse des I²C-PIC-Slave inkl. Schreibzugriff (Zeile 162, hier 0b00110000 da die Jumper JP1, JP2, JP3 und JP6 gesetzt sind, siehe Abbildung 7. Das letzte niederwertigste Bit gibt die Zugriffsrichtung an. Hier 0 da es sich um einen Schreibzugriff aus Sicht des Masters handelt.) Anschließend werden die Daten an den I²C-PIC-Slave geschrieben (Zeile 163) und zum Schluss die Stopbedingung (Zeile 164).

Der umgekehrte Weg, also das Lesen von Daten vom I²C-PIC-Slave und Ausgeben am I²C-Ausgabemodul mit dem PCF8574 (IC4) ist ähnlich: Für das Lesen vom I²C-PIC-Slave muss zunächst (wieder) die I²C-Startbedingung erzeugt werden (Zeile 168) anschließend die Adresse des I²C-PIC-Slave hier inkl. Lesezugriff (Zeile 169). Das letzte niederwertigste Bit ist hier 1 da es sich um einen Lesezugriff aus Sicht des Masters handelt. Gefolgt vom Lesen der Daten vom I²C-PIC-Slave (Zeile 170) und zum Schluss wieder die Stopbedingung (Zeile 171). Der Übergabeparameter noACK bedeutet, dass keine weiteren Daten gelesen werden.
Das Schreiben der gelesenen Daten (diese befinden sich im Register cTemp) am I²C-Ausgabemodul erfolgt mit dem Unterprogramm I2C_PCF8574_WriteData (Zeile 174). Übergabeparameter sind hier die Moduladresse (auch hier 3-Bit, entsprechend den Pins A2 bis A0. Hier der Wert 3, da A0 und A1 offen sind - also den Pegel High besitzen, während A2 via Jumper auf low-Pegel liegen) und die zu schreibenden Daten. Beachte. Die Leuchtdioden beim Ausgabemodul sind gegen +5V geschaltet. D.h. damit eine Leuchtdiode leuchtet muss am Portpin Px low anliegen. Daher muss das Register cTemp invertiert werden bevor es am I²C-Ausgabemodul ausgegeben werden kann (Zeile 199).

Nun befindet sich das Hauptprogramm in einer Endlosschleife. Jedesmal wenn am I²C-Eingabemodul ein Portpin verändert wird erzeugt der PCF8574 einen so genannten Interrupt, indem der Pin 13 (INT) von High nach Low übergeht. Dieser Interrupt-Pin ist sozusagen die fünfte Leitung des I²C-Buses und kann mit einem beliebigen I/O-Pin des Mikrocontrollers verbunden werden. Hier ist es der Portpin RC5 (vgl. Schaltung in Abbildung 7, Abschnitt 5.1). In meiner Software erhält dieser Portpin die Bezeichnung nINTPCF8574 (Zeile 47). Immer wenn dieser Portpin low ist, also wenn am I²C-Eingabemodul zumindest ein Portpin verändert wurde soll der geänderten Eingang gelesen und am PIC-I²C-Slave ausgeben werden (Zeilen 184 bis 189). Danach sollen die Daten vom PIC-I²C-Slave gelesen und am I²C-Ausgabemodul ausgeben werden (Zeilen 193 bis 200).

Hinweise:

Beachte:
Die Unterprogramme und Funktionen I2c_Init(), I2c_Start(), I2c_Stop(), I2c_Wr() und I2c_Rd() stellt der mikroC-Compiler zur Verfügung. Diese müssen hier nicht mittels include-Anweisung eingebunden werden. Diese Unterprogramme und Funktionen steuern dass SSP-Hardware-Modul im I²C-Master-Mode.

Unterprogramm Init:
Das Unterprogramm Init (Datei: I2C_Demo_PIC_Master.c, Zeilen 81 bis 130) dient zur Initialisierung des Mikrocontrollers. Hier wird der interne Oszillator konfiguriert (also auf 4MHz eingestellt, Zeile 84) und die Pins des Port C für den I²C-Bus als Ein- oder Ausgang definiert (Zeile 120). Die anderen Ports (A, B, D und E) werden hier nicht benötigt, und müssen daher auch nicht konfiguriert werden.

Im Gegensatz zum Slave muss hier das SSP-Hardware-Module für den Mastermode nicht initialisiert werden. Diese Aufgabe übernimmt das Unterprogramm I2c_Init(), welches vom microC-Compiler zur Verfügung gestellt wird.

Unterprogramme I2C_PCF8574_WriteData und I2C_PCF8574_ReadData:
Das Unterprogramm I2C_PCF8574_WriteData (Datei: PCF8574.C, Zeilen 293 bis 308) dient zum Schreiben eines 8-Bit-Wertes (Adresse oder Daten) zum PCF8574, während das Unterprogramm I2C_PCF8574_ReadData (Datei: PCF8574.C, Zeilen 228 bis 347) einen 8-Bit-Wert vom PCF8574 liest. Aufgrund der Einfachheit und der ausführlichen Kommentare ist hier eine weitere Erklärung glaube ich nicht notwendig.

Sonstiges:
Am Beginn des Quellcodes (in der Datei I2C_Demo_PIC_Master.c) befinden sich die folgenden Definitionen und Einstellungen:

Ein kleiner Nachteil beim mikroC-Compiler ist, dass die Konfigurationsbits für den PIC-Mikrocontroller in der IDE gesetzt werden müssen. Ich persönlich würde diese lieber im Quellcode mit einer geeigneten Anweisung setzen.

Hier sind die notwendigen Einstellungen für den PIC16F887 für dieses Demonstrationsbeispiel (für Master und Slave):

nach oben

5.6. Software für 2. Demo (Slave)

Beim zweiten Demonstrationsbeispiel sendet der I²C-Master mehrere Datenbytes (hier vier) zum PIC-I²C-Slave, bzw. liest anschließend auch mehrere Datenbytes (auch vier) vom PIC-I²C-Slave.

Listing 5 (Teil 1)
Listing 5 (Teil 2)
Listing 5 (Teil 3)
Listing 5 (Teil 4)
Listing 5 (Teil 5)
Listing 5 (Teil 6)
Listing 5 (Teil 7)
Listing 5 (Teil 8)
nach oben

5.7. Anmerkungen zur Software für 2. Demo (Slave)

Auch bei diesem zweiten Demonstrationsbeispiel wurde der Quellcode in C mit der freien Demoversion des mikroC-Compilers erstellt, und die Software für den PIC-I²C-Slave besteht aus den gleichen, aber angepassten, Programmteilen wie beim ersten Demonstrationsbeispiel. Nämlich aus:

Wichtig zu erwähnen ist, dass es bei diesem zweiten Demonstrationsbeispiel zweckmäßig ist die empfangenen Daten und die zu sendenden Daten in je einem Array zu speichern (hier: cI2CReadBuffer[] und cI2CWriteBuffer[]).

Hauptprogramm:
Die Aufgabe des Hauptprogramms (Zeilen 494 bis 510) ist hier zunächst das Initialisieren des Mikrocontrollers. Dies erfolgt mit dem Unterprogramm Init (Zeile 497). Das Bereitstellen der zu übertragenden Daten und die Weiterverarbeitung der empfangenen Daten erfolgt in der Endlosschleife. Bei diesem Demonstrationsbeispiel soll nur das vierte empfange Byte am Port D ausgegeben werden (Zeile 503), während der Zustand von Port A zweimal zum I²C-Master übertragen werden soll. Das zweite und dritte Datenbyte sind hier beliebige konstante Werte (Zeilen 505 bis 508).
Alles andere erfolgt in der Interrupt-Service-Routine (ISR).

Beachte:
Die Bezeichnungen der Variablen cI2CReadBuffer[] und cI2CWriteBuffer[]) erfolgen aus Sicht des Masters!

Unterprogramm Init:
Das Unterprogramm Init (Zeilen 165 bis 479) dient auch hier zur Initialisierung des Mikrocontrollers. Es ist gleich wie beim ersten Demonstrationsbeispiel.

Interrupt-Service-Routine (kurz: ISR):
Die SSP-ISR (Zeilen 88 bis 143) wird auch hier jedesmal aufgerufen wenn ein gesamtes Datenbyte vom SSP-Hardware-Modul empfangen wurde und dieses für den PIC-Slave mit der Adresse im Register SSPADD bestimmt ist. Jedes mal wenn diese SSP-ISR aufgerufen wird muss eine der folgenden vier Fälle ausgeführt werden (vgl. Flussdiagramm in Abbildung 5 aus Abschnitt 3.2.). Im Gegensatz zum ersten Demonstrationsbeispiel müssen hier auch die Lese- und Schreibezeiger richtig behandelt werden, da hier mehr als ein Datenbyte gelesen bzw. geschrieben (gesendet) werden).

Fall 1: Schreibzugriff aus Sicht des Masters, zuletzt wurde die Slave-Adresse empfangen (Bits: SSPSTAT.R_W = 0, SSPSTAT.D_A = 0):
In diesem Fall muss der Mikrocontroller (Slave) die empfangenen Daten aus dem SSP-Buffer (Register SSPBUF) lesen kann den Inhalt von SSPBUF aber verwerfen, da es nur die Adresse und keine Daten enthält (Zeile 98). Hier wird der Inhalt von SSPBUF in ein Dummy-Register geschrieben. Wichtig ist das dass Register SSPBUF gelesen wird, weil dadurch Steuerbits für das Hardwaremodul verändert werden. Neu ist bei diesem Demonstrationsbeispiel das Initialisieren des Schreib-Zeiger cI2CWriteBufferIndex (aus Sicht des Masters, Zeile 101). Wichtig sind auch hier die folgenden Codezeilen 99 und 100. Das SSP-Interrupt-Flag SSPIF muss ebenfalls gelöscht werden, da sonst dieser Interrupt sofort wieder ausgelöst wird (Zeile 102)!

Fall 2: Schreibzugriff aus Sicht des Masters, zuletzt wurde ein Datenbyte empfangen (Bits: SSPSTAT.R_W = 0, SSPSTAT.D_A = 1):
Jetzt handelt es sich tatsächlich um Nutzdaten. Diese befinden sich im SSP-Buffer-Register SSPBUF. Daher den Inhalt dieses Registers in das eigene Array cI2CWriteBuffer[] an der Stelle auf den der Index-Zeiger cI2CWriteBufferIndex zeigt schreiben (Zeile 109). Diesen Index-Zeiger anschließend um eins erhöhen (Zeile 111), damit beim nächsten Aufruf dieser ISR der nächste empfangene Wert an die nächste Stelle im Array cI2CWriteBuffer[] geschrieben wird.
Auch hier sind die folgenden Codezeilen 112 bis 114 wichtig und dürfen nicht weggelassen werden!

Fall 3: Lesezugriff aus Sicht des Masters, zuletzt wurde die Slave-Adresse empfangen (Bits: SSPSTAT.R_W = 1, SSPSTAT.D_A = 0):
In diesem Fall muss das erste zu sendende Datenbyte in das Register SSPBUF geschrieben werden. Daher das erste Datenbyte (mit dem Index 0) vom eigene Array cI2CReadBuffer[] lesen und in das Register SSPBUF schreiben (Zeile 125). Als nächstes den Lese-Zeiger (aus Sicht des Masters) cI2CReadBufferIndex initialisieren (Zeile 126).
Auch hier sind die folgenden Codezeilen 127 bis 129 wichtig und dürfen nicht weggelassen werden!

Fall 4: Lesezugriff aus Sicht des Masters, zuletzt wurde ein Datenbyte gesendet (Bits: SSPSTAT.R_W = 1, SSPSTAT.D_A = 1):
Im Gegensatz zum ersten Demonstrationsbeispiel tritt hier auch dieser Fall auf. Hier muss zunächst der Lese-Index-Zeiger cI2CReadBufferIndex um eins erhöht werden (Zeile 135). Anschließend den Inhalt des Lesearray, auf den der Lesezeiger zeigt lesen und in das Register SSPBUF schreiben (Zeile 136).
Auch hier sind die folgenden Codezeilen 138 bis 140 wichtig und dürfen nicht weggelassen werden!

Mehr als das Lesen des SSPBUF-Registers oder das Schreiben in das SSPBUF-Register ist auch bei diesem zweiten Demonstrationsbeispiel in der Interrupt-Service-Routine (ISR) nicht zu tun. Alles andere übernimmt auch hier das Hardware-Modul SSP des Mikrocontrollers.

Sonstiges:
Am Beginn des Quellcodes befinden sich die folgenden Definitionen und Einstellungen:

Die Konfigurationsbits für den PIC16F887-Mikrocontroller sind hier gleich wie beim ersten Demonstrationsbeispiel.

nach oben

5.8. Software für 2. Demo (Master)

Natürlich müssen auch beim Master Änderungen vorgenommen werden.

/p>

Auch bei diesem zweiten Demonstrationsbeispiel ist der Quellcode für den I²C-Bus-Master (mit dem PIC16F887, IC2) zur besseren Übersicht in mehrere Dateien aufgeteilt:

Die Dateien PCF8574.C und PCF8574.H unterscheiden sich nicht zum ersten Demonstrationsbeispiel und werden hier daher auch nicht mehr behandelt.

Hier die Datei I2C_Demo_PIC_Master.c:

Listing 6 (Teil 1)
Listing 6 (Teil 2)
Listing 6 (Teil 3)
Listing 6 (Teil 4)
nach oben

5.9. Anmerkungen zur Software für 2. Demo (Master)

Auch dieser Quellcode wurde in C mit der freien Demoversion des mikroC-Compilers erstellt.

Die Software (für den PIC-I²C-Master) besteht auch hier im Wesentlichen aus den folgenden Programmteilen:

Hier nur kurz die Änderungen im Hauptprogramm. Das Unterprogramm Init bleibt hier unverändert:
Das Hauptprogramm ist - verglichen mit dem ersten Demonstrationsbeispiel, Master - etwas änger. Grund dafür ist nur dass jetzt jeweils vier Datenbytes (anstelle von einer, beim ersten Demonstrationsbeispiel) gesendet bzw. gelesen werden müssen. Dies ist, glaube ich, im Quellcode sehr gut erkennbar. Dies ist auch der einzige Unterschied. Anstelle der temporären Register cTemp1 bis cTemp4 könnte auch ein Array verwendet werden, doch dies ist hier nicht unbedingt notwendig.

Zum Abschluss noch ein Wort zu den Konfigurationsbits. Auch diese sind hier gleich wie beim ersten Demonstrationsbeispiel.

nach oben

7 Die freie Demoversion ist nur auf eine Programmspeichergröße von 2k begrenzt. Ansonst voll kompatibel zur Vollversion. Die Demoversion ist auf der Firmen-Webseite [3] downloadbar

nach oben


zurück zu Elektronik, Homepage

Autor: Stefan Buchgeher
Erstellt: 5. August 2014
Letzte Änderung: