Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
microcontrollertechnik:11_i2c_schnittstelle [2023/11/19 01:54]
mexleadmin
microcontrollertechnik:11_i2c_schnittstelle [2024/03/11 00:03] (aktuell)
mexleadmin
Zeile 1: Zeile 1:
-====== 10 I2C Schnittstelle ======+====== 11 I2C Schnittstelle ======
 <WRAP group>  <WRAP group> 
 <WRAP column 30%> <WRAP column 30%>
Zeile 8: Zeile 8:
  
   - wissen wie die Kommunikation zwischen I2C Master und Slave funktioniert   - wissen wie die Kommunikation zwischen I2C Master und Slave funktioniert
 +
 +Im Video wird eine Library für die Kommunikation verwendet. Wir werden in untenstehenden Beispiel die Register selbst schreiben.
  
 </WRAP> <WRAP column 65%> </WRAP> <WRAP column 65%>
 ==== Video ==== ==== Video ====
    
 +{{youtube>evTYfGX8cgQ?size=700x400}}
 +
 +<WRAP hide>
 {{youtube>7aZ43cl7o_w?size=700x400}} {{youtube>7aZ43cl7o_w?size=700x400}}
 +</WRAP>
  
 </WRAP> </WRAP> </WRAP> </WRAP>
Zeile 37: Zeile 43:
 </WRAP> </WRAP>
  
-**Übertragung**\\+=== Übertragung === 
 Für die I2C Übertragung "trommelt" der Master-IC auf der Taktleitung (SCL). Bei jedem "Trommelschlag" (SCL=High), darf der Slave die Datenleitung (SDA) lesen. \\ Für die I2C Übertragung "trommelt" der Master-IC auf der Taktleitung (SCL). Bei jedem "Trommelschlag" (SCL=High), darf der Slave die Datenleitung (SDA) lesen. \\
 D.h. während der Datenübertragung bleibt die Datenleitung bei SCL=High konstant. \\ D.h. während der Datenübertragung bleibt die Datenleitung bei SCL=High konstant. \\
Zeile 149: Zeile 155:
 ===== Software ===== ===== Software =====
  
-==== einfache Anwendung ====+==== einfache Anwendung - nur Polling ====
  
 Im ersten Schritt ist im folgenden eine einfache Anwendung dargestellt. \\ Im ersten Schritt ist im folgenden eine einfache Anwendung dargestellt. \\
Zeile 177: Zeile 183:
 --> III. Code in Microchip Studio # --> III. Code in Microchip Studio #
  
-==== TWI Master ====+<fs x-large>**I2C Master**</fs>
  
 <WRAP group><WRAP column 40%><sxh c; first-line: 1> <WRAP group><WRAP column 40%><sxh c; first-line: 1>
Zeile 195: Zeile 201:
  Hardware : Simulide 1.0.0 >R810  Hardware : Simulide 1.0.0 >R810
      
- Software : Entwicklungsumgebung: AtmelStudio 7.0+ Software : Entwicklungsumgebung: Microchip Studio 7.0
    C-Compiler: AVR/GNU C Compiler 5.4.0    C-Compiler: AVR/GNU C Compiler 5.4.0
      
Zeile 236: Zeile 242:
 void I2C_transmitStop(); void I2C_transmitStop();
    
-uint8_t TWI_Address =  TWI_ADRESS; +uint8_t TWI_Address =  TWI_ADRESS; // Variable der I2C Adresse
 uint8_t TWI_Data    = 0b00000000; // Variable für die I2C Daten uint8_t TWI_Data    = 0b00000000; // Variable für die I2C Daten
    
Zeile 251: Zeile 257:
         I2C_transmitDataOrAddress(TWI_Data); // Daten senden         I2C_transmitDataOrAddress(TWI_Data); // Daten senden
         I2C_transmitStop(); // Stoppbit schreiben         I2C_transmitStop(); // Stoppbit schreiben
- // ggf. kann am Ende der ÜBertragung ein _delay_us(1) zur Synchronisierung helfen+ _delay_us(1); // erst durch den Delay ist ein Triggern im Simulide möglich 
     }     }
 } }
Zeile 260: Zeile 266:
 void I2C_Init() void I2C_Init()
 { {
-    TWSR = CLR_BIT(TWSR, TWPS0); // Es wird kein Prescaler verwendet:  +    CLR_BIT(TWSR, TWPS0); // Es wird kein Prescaler verwendet:  
-    TWSR = CLR_BIT(TWSR, TWPS1); // Deshalb TWPS0 = 0 und TWPS1 = 0+    CLR_BIT(TWSR, TWPS1); // Deshalb TWPS0 = 0 und TWPS1 = 0
     TWCR = 0;                    // Control Register zurücksetzen     TWCR = 0;                    // Control Register zurücksetzen
     TWBR = ((F_CPU/F_SCL)-16)/2; // die Bitrate wird mittels CPU Frequenz und Serial Clock Frequenz ermittelt     TWBR = ((F_CPU/F_SCL)-16)/2; // die Bitrate wird mittels CPU Frequenz und Serial Clock Frequenz ermittelt
Zeile 295: Zeile 301:
 </sxh> </sxh>
 </WRAP><WRAP column 55%> </WRAP><WRAP column 55%>
- + \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\
-''/*============================================================================='' +
- +
-Ändern Sie auch hier wieder die Beschreibung am Anfang des C-Files, je nachdem was Sie entwickeln  \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\+
 ''Deklarationen ==================================='' ''Deklarationen ===================================''
 \\ \\ \\ \\
-  - Hier wird wieder geprüft ob die Frequenz des Quarz bereits eingestellt wurde und falls nicht - dessen Frequenz eingestellt. \\ \\ \\ \\ +  - Hier wird die Frequenz des Quarz direkt eingestellt.  
-  - Die Header-Dateien entsprechen denen der letzten Programme. \\ \\ \\ \\ \\  +  Weiterhin wird eine Konstante für die I2C Frequenz definiert \\ \\  
-  - Auch die Makros entsprechen denen der letzten Programme. \\ \\ \\ \\ \\  +  - Die Header-Dateien und die Bit-ändernden Makros entsprechen denen der letzten Programme. \\ \\ \\ \\ \\ \\ 
-  - Die Konstanten entsprechen denen der letzten Programme. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\  +  - Die weiteren Konstanten sind: 
-  Auch die anfänglichen Variablen entsprechen denen der letzten Programme. Hierbei sind alle vier Schalter berücksichtigt.\\ \\ \\ \\ \\ \\ \\  +    Konstante für die Pullups 
-  Wird die Taste S1 gedrückt, so wird ''sw1_neu'' gesetzt. ''sw1_alt'' entspricht dem vorherigen Wert. Gleiches gibt es für die anderen Taster. \\ \\ \\ \\ \\ \\ \\  +    - Konstante für die Invertierung der Schalterstellungen 
-  - Wird eine ansteigende Flanke der Taste S1 gedrückt, so wird ''sw1_slope'' gesetzt. Das heißt, wenn die Taste gerade von 'nicht gedrückt' auf 'gedrückt' gewechselt hat, so wird ''sw1_slope'' gesetzt. Gleiches gibt es für die anderen Taster. \\ \\ \\   +    Konstante für die I2C Adresse  \\ \\ \\ \\ \\ 
-  - Bei den Funktionsprototypen sind einige bekannte Unterprogramme vorhanden. Details werden weiter unten erklärt. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\+  - Zwei globale Variablen beinhalten die I2C Adresse und die Daten \\ \\
  
 ''Hauptprogramm ========================='' ''Hauptprogramm =========================''
  
-  - Zunächst werden zwei Initialisierungsroutinen aufgerufen (siehe weiter unten) +  - es werden zunächst die Pull-up Widerstände aller Pins an Port B aktiviert, um die Schalter einlesen zu können 
-  - Dann werden die "__T__imer/__C__ounter __C__ontrol __R__egister" des Timers __2__ ''TCCR2A'' und ''TCCR2B'' gesetzt. Der Timer 2 ist im wesentlichen mit dem Timer 0 aus dem [[4_up_down_counter|Up/Down Counter]] vergleichbar. Er ist ein 8-Bit Timer und auch hier wird der "Normal Mode" zum hochzählen genutzt. Auch hier gibt das Register ''TCCR2B'' den Prescaler an+  - in der Haupschleife läuft: 
-  - Auch hier gibt es eine "__T__imer __I__nterrupt __M__a__SK__" ''TIMSK2''. Auch hier wird mit dem Bit ''TOIE2'' ("__T__imer __O__verflow __I__nterrupt __E__nable") der Interrupt bei Überlauf aktiviert+    - Zu Beginn eine Iitialisierung der I2C SchnittstelleDie wiederholte Initialisierung vermeidet Probleme der I2C Zustandsmaschine. 
-  - Mit dem Befehl ''sei()'' wird die Bearbeitung von Interrupts aktiv +    - Als nächstes wird die startende Flanke gesendet
-  - in der Endlosschleife ist nur eine switch-case Anweisung zu findenDiese stellt den Auswahlteil einer Zustandsmaschine dar: \\ {{drawio>Zustandsmaschine.svg}} \\ Aus jedem Unterprogramm wird wieder zurück ins Hauptmenü gesprungen+    Das erste Byte auf dem I2C Bus ist die AdressebyteDieses setzt sich aus der Adresse und einem Bit zusammenwelches angibt, ob der Slave nur zuhören (''0'') oder antworten (''1'') soll. 
-  Beim ''case 1...4'' wird zunächst das jeweilige Programm aufgerufenNachdem Rückkehr aus diesem Programm wird zunächst der ''modus'' wieder auf 0 zurückgesetztsodass beim nächsten Durchlauf der Schleife der ''case 0'' ausgeführt wird. Jeder case wird mit ''break'' beendet+    - Nun wird der Zustand das Port B als I2C Daten eingelesen.  
 +    - Diese werden per I2C übertragen. 
 +    - Und zum Schluss wird das Stopp Bit gesendet \\ \\
  
-''Interrupt Routine ========================='' +'' I2C Initialisierung ========================='' 
-  - Mit dem Befehl ''ISR()'' wird eine Interrupt Service Routine für den  __OV__er__F__low Interrupt für __TIMER2__ angelegt.  +  - Durch das Zurücksetzen der Bits ''TWPS0'' und ''TWPS1'' wird kein Prescaler (bzw. einer von 1gewählt 
-  - Der Überlauf-Interrupt durch den Timer2 wird erst bei Überlauf des 8-Bit Wert ausgeführt. Auch hier ergibt sich durch den Prescaler und Modus (''TCCR2A'' und ''TCCR2B''eine Periode von $T_{\rm ISR}= 0,16\bar{6}~\rm ms$. +  - Auch das Kontrollregister wird zurückgesetzt 
-  - Die Ermittlung von ''Timertick'', ''vorteiler'', ''takt10ms'', ''hundertstel'' und ''takt100ms'' ist hier wieder gleich dem im [[4_up_down_counter|Up/Down Counter]].  +  - im Bitraten Register wird die I2C Frequenz eingestellt \\ \\ \\ \\ 
-  - Eine große Änderung ist, dass bereits im Interrupt alle 10ms die Unterfunktion ''readButton()'' aufgerufen wird.  \\ \\ \\ \\ \\ \\ \\ \\ \\ \\  \\ \\ \\ \\ \\ \\ +'' I2C Startbit senden =============='' 
-'' Funktion Tasten einlesen =============='' +  - Es soll die I2C Schnittstelle aktiviert (''TWEN'' setzenund das Startbit gesendet (''TWSTA'' setzenwerden. Das Schreiben einer ''1'' in ''TWINT'' löscht dieses Interruptflag 
-\\ \\ \\ +  - Nach dem Ändern des Konrollregisters muss die Abarbeitung abgewartet werden. Dies ist daran zu erkennen, das ''TWINT'' gleich ''1'' wird \\ \\ \\  
-  - In dieser Funktion werden zunächst die Stellungen aller Taster eingelesen (vgl. ''counterCounting(void)'' bei [[4_up_down_counter|Up/down Counter]]). \\ \\ \\ +'' I2C Adressbyte/Daten senden ========================='' 
-  - Neu hier ist, dass über ''if ( (sw1_neu==0) & (sw1_alt==1) )'' die positive Flanke (=aufsteigende Flankeerkannt wird und dies im Flag ''sw1_slope'' gespeichert wird. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +  - Bevor Daten übertragen werden sollenmüssen diese erst in das I2C Datenregister geschrieben werden
- +  - Wieder die I2C Schnittstelle aktivieren (''TWEN'' setzen) und das Inrerruptflag löschen (''TWINT'' setzen
-''Initialisierung Display-Anzeige ========================='' +  - auch hier muss wieder die Abarbeitung abgewartet werden \\ \\ \\ 
-  - Die Funktion ''initDisplay()'' wird zu Beginn des Programms aufgerufen und führt zunächst die Initialisierung des Displays aus. +'' I2C Stoppbit senden ========================='' 
-  - Danach wird der erste Text auf den Bildschirm geschrieben und damit der Programmname dargestellt. +  - Das Stoppbit wird wieder im Kontrollregister aktiviert 
-  - Nach zwei Sekunden wird der Auswahlbildschirm angezeigt. +  - Hier ist kein Warten notwendig 
- +
-\\ \\ \\ \\ \\ \\ +
- +
-''Anzeige Hauptmenu ========================='' +
-  - Da der Auswahlbildschirm mit dem Hauptmenu nicht nur beim Start, sondern auch nach jeder Rückkehr aus Unterprogrammen dargestellt werden musswird der Auswahlbildschirm in einem neuen Unterprogramm angezeigt. +
- +
-\\ \\ \\ \\ \\ +
- +
-''/* Teilprogramm 1: Blinkende LED ====='' +
- +
-Hier ist das Programm der [[1_hello_blinking_world|Blinking LED]] etwas angepasst eingefügt.  +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\  +
-  - Zunächst wird ein Unterprogramm zur Anzeige das Displays aufgerufen +
-  - ''SET_BIT(DDRB, DDB0)'' wandelt den Anschluss B0 in einen Ausgang um +
-  - Die Schleife wird solange ausgeführt, bis die Flanke des Schalters 1 über ''sw1_slope'' erkannt wurde +
-  - Beim Aktivieren der LED wird auch auf dem Display eine ''1'' geschrieben.  \\ \\ \\ \\ +
-  - Nach einer Sekunde wird die LED ausgeschalten und auf dem Display eine ''0'' geschrieben.  \\ \\ \\ \\ +
-  - Nach Beendigung der Schleife werden alle Flanken gelöscht. Damit wird verhindert, dass beim Aufruf des Hauptmenus sofort ein Sprung in ein Unterprogramm ausgeführt wird. +
- +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
-''/* Teilprogramm 2: Soundgenerierung ===='' +
- +
-Hier ist das Programm [[2_sound_und_timer|Sound und Timer]] etwas angepasst eingefügt.  +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
- +
-  - Die Port Initialisierung, um Lautsprecher und LED anzusteuern, wurde übernommen. +
-  - Hier wird Timer 0 genutzt, um das gepulste Signal an den Lautsprecher zu verändern. +
-  - Die while-Schleife wird wieder abgebrochen, wenn die Taste 1 gedrückt wurde. +
-  - Neben dem Herunterzählen der Periodenlänge (über ''OCR0A--''), wird auch der Periodenzähler ausgegeben. Die Ausgabe ähnelt ''counterDisplay'' aus dem Programm [[4_up_down_counter|Up/Down Counter]]. +
-  - Da die for-Schleife zum Herunterzählen der Periodenlänge sehr lange dauert (etwa 2 Sekunden) wird auch darin der Tastendruck der Taste 1 abgefragt werden. \\ \\ \\ \\ \\  +
-  - Falls die Taste 1 gedrückt wurde, wird sowohl __in der for__-Schleife, als auch __nach der while__-Schleife der Timer gestoppt und die Flanken zurückgesetzt. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
-  - Das Heraufzählen der Frequenz gleich dem Herunterzählen, bis auf die Werte der for-Schleife. +
- +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
-''/* Teilprogramm 3: Logische Funktionen ===='' +
- +
-Hier ist das Programm [[3_logische_funktionen|Logische Funktionen]] etwas angepasst eingefügt.  +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
- +
-  - Durch den Anschluss des Tasters zwischen Port und Masse erzeugt ein geschlossener ein LOW Signal (logisch 0). Hier sollen aber nun der Tastendruck dem Wert HIGH (logisch 1) entsprechen. Aus diesem Grund sind die Tasterwerte in den Bedingungen negiert, z.B. ''(__**!**__sw3_alt)&&(__**!**__sw4_alt)'' +
- +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
-''/* Teilprogramm 4: Up-Down-Counter ===='' +
- +
-Hier ist das Programm [[4_up_down_counter|Up/Down Counter]] etwas angepasst eingefügt.  +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
- +
-  - Im wesentlichen gleicht das Programm dem bereits bekanntem. Es kann aber auf die bereits berechnete Flanken ''sw2_slope'' bis ''sw4_slope'' zurückgegriffen. +
- +
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
-''Auswahl im Hauptmenu ermitteln =========='' +
- +
-  - Je nach gedrückter Taste wird hier die Variable ''modus'' gesetzt+
    
 </WRAP></WRAP> </WRAP></WRAP>
  
---TWI Slave +<fs x-large>**I2C Slave**</fs>
-==== TWI Slave ====+
  
-<WRAP> +<WRAP group><WRAP column 40%><sxh c; first-line: 1>
-<sxh c; first-line: 1>+
 /* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
- +  
  Experiment 10:   I2C Kommunikation  Experiment 10:   I2C Kommunikation
  =============    ===============================  =============    ===============================
 +  
 + Dateiname : I2C_SimpleSlave.c
 +  
 + Autoren : Tim Fischer       (Hochschule Heilbronn, Fakultaet TE)
 +  
 + Datum : 18.11.2023
 +  
 + Version : 1.0
 +   
 + Hardware :  Simulide 0.5.16-RC5
 +  
 + Software :  Entwicklungsumgebung: Microchip Studio 7.0
 +    C-Compiler: AVR/GNU C Compiler 5.4.0
 +   
 + Funktion : TBD
    
- Dateiname I2C_SimpleMaster.c+ Displayanzeige keine
    
- Autoren    Tim Fischer       (Hochschule Heilbronn, Fakultaet T1)+ Tastenfunktion Die Tastenstellung der Dip-Schalter an Port B werden als Wert über I2C weitergegeben. 
 +   Dabei zählt ein gedrückter Schalter (= hellgrünals logisches High Signal
    
- Datum      23.06.2021+ Jumperstellung  keine
    
- Version    1.0+ Fuses im uC keine
      
- Hardware:  Simulide 0.5.16-RC5 +    
-  +// ----------------------------------------------------------------------------*/
- Software:  Entwicklungsumgebung: AtmelStudio 7.0 +
-            C-Compiler: AVR/GNU C Compiler 5.4.0 +
-  +
- Funktion: tbd +
- +
- +
      
-// ----------------------------------------------------------------------------*/ 
-  
 // Deklarationen ============================================================== // Deklarationen ==============================================================
 +  
 +// Festlegung der Quarzfrequenz
 +#define F_CPU 8000000UL // CPU Frequenz von 8MHz
 +#define F_SCL   100000L // Baudrate von 100 kHz
    
-// Festlegung der Quarzfrequenz 
-#define F_CPU 16000000UL 
-#define F_SCL 10000L //100 kHz 
- 
 // Include von Header-Dateien // Include von Header-Dateien
 #include <avr/interrupt.h> #include <avr/interrupt.h>
 + 
 // Konstanten // Konstanten
-#define SET_BIT(BYTE, BIT) ((BYTE) |=  (1 << (BIT))) // Bit Zustand in Byte setzen +#define SET_BIT(BYTE, BIT)  ((BYTE) |=  (1 << (BIT))) // Bit Zustand in Byte setzen 
-#define CLR_BIT(BYTE, BIT) ((BYTE) &= ~(1 << (BIT))) // Bit Zustand in Byte loeschen +#define CLR_BIT(BYTE, BIT)  ((BYTE) &= ~(1 << (BIT))) // Bit Zustand in Byte loeschen 
-#define TGL_BIT(BYTE, BIT)  ((BYTE) ^=  (1 << (BIT))) // Bit Zustand in Byte wechseln (toggle)+#define TGL_BIT(BYTE, BIT)  ((BYTE) ^=  (1 << (BIT))) // Bit Zustand in Byte wechseln (toggle)
  
 +#define SET_ALL_TO_OUT (0xFF) // Konstante für die Aktivierung der Port Ausgänge
 +#define TWI_ADRESS (0b0001010) // Konstante für die I2C Adresse
 +#define TWI_ADRESS_MASK (0b0001010) // Konstante für die I2C Adress-Maske
 + 
 //Funktionsprototypen //Funktionsprototypen
 void I2C_Init(); void I2C_Init();
 void I2C_setAddress(char Address); void I2C_setAddress(char Address);
 char I2C_readData(); char I2C_readData();
- +  
-uint8_t TWI_Address  0b0001010+uint8_t TWI_Address         TWI_ADRESS; // Variable der I2C Adresse  
-uint8_t TWI_AddressMask 0b11111110+uint8_t TWI_AddressMask     TWI_ADRESS_MASK; // Variable Zum maskieren der eingehenden Adresse 
 + 
 int main(void) int main(void)
 { {
- DDRD0xFF; // Auf DDRC die Daten ausgeben +    DDRBSET_ALL_TO_OUT; // Auf DDRC die Daten ausgeben 
- I2C_setAddress(TWI_Address); // eigene Adresse setzen +    I2C_setAddress(TWI_Address); // eigene Adresse setzen 
- +     
     while (1)      while (1) 
     {     {
- PORTD = I2C_readData(); // Daten an PortC ausgeben+        PORTB = I2C_readData(); // Daten an PortC ausgeben
     }      } 
 } }
 + 
 ////////////////////////////////////////////////// //////////////////////////////////////////////////
 // Setzen der I2C Adresse auf die der Slave hört // Setzen der I2C Adresse auf die der Slave hört
 ////////////////////////////////////////////////// //////////////////////////////////////////////////
-void I2C_setAddress(char Address) +void I2C_setAddress(char Address)                       
 { {
- TWAR = (Address<<1); // Adresse in das Pseudoregister schreiben +    TWAR = (Address<<1); // Adresse in das Pseudoregister schreiben 
- TWAMR= TWI_AddressMask; // Adressmaske in das Pseudoregister schreiben +    TWAMR= TWI_AddressMask;                             // Adressmaske in das Pseudoregister schreiben 
- TWCR = (1<<TWEA)|(1<<TWEN); // Enable Ack, Enable Interupt und Enable TIW +    TWCR = (1<<TWEA)|(1<<TWEN);                         // Enable Ack, Enable Interupt und Enable TIW
 } }
 + 
 ////////////////////////////////////////////////// //////////////////////////////////////////////////
 // Auslesen der übermittelten Daten  // Auslesen der übermittelten Daten 
 ////////////////////////////////////////////////// //////////////////////////////////////////////////
-char I2C_readData() +char I2C_readData()                     
 { {
- while (!(TWCR & (1<<TWINT))); // warte solange bis TWINT gesetzt ist +    while (!(TWCR & (1<<TWINT))); // warte solange bis TWINT gesetzt ist 
- return TWDR; // übermittle Daten+    return TWDR;                                        // übermittle Daten
 } }
- 
 </sxh> </sxh>
-</WRAP>+</WRAP><WRAP column 55%> 
 + \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ 
 +''Deklarationen ==================================='' 
 +\\ \\ 
 +  - Hier wird die Frequenz des Quarz direkt eingestellt.  
 +  - Weiterhin wird eine Konstante für die I2C Frequenz definiert \\ \\  
 +  - Die Header-Dateien und die Bit-ändernden Makros entsprechen denen der letzten Programme. \\ \\ \\ \\  
 +  - Die weiteren Konstanten sind: 
 +    - Konstante für die das Setzen der Pins als Ausgang 
 +    - Konstante für die I2C Adresse   
 +    - Konstante für die Maskierung der Adresse \\ \\ \\ \\ \\ 
 +  - Zwei globale Variablen beinhalten die I2C Adresse und die Maske für die eingelesene Adresse \\ \\  
 + 
 +''Hauptprogramm ========================='' 
 + 
 +  - Es werden alle Pins an Port B als Ausgang geschalten 
 +  - Die I2C Adresse, auf welche der Slave hört, wird gesetzt \\ \\ 
 +  - In der Haupschleife läuft nur das Setzen des Port B anhand der eingelesenen I2C Daten \\ \\ \\ \\ \\ 
 + 
 +'' Setzen der I2C Adresse auf die der Slave hört ========================='' 
 +  - Die Adresse wird in das Adressbyte geschrieben.  
 +  - Die Adressmaske wird in das Maskenbyte geschrieben. Durch die Maske lässt sich ein Slave auch mit verschiedenen Adressen ansprechen, da die Maske angibt, welche Bits nicht berücksichtigt werden sollen (mit ''0''
 +  - Im Kontrollregister wird die "Rückbestätigung" and den Master (Acknowledge) aktiviert (''TWEA'' setzen) und das I2C Modul aktiviert (''TWEN'' setzen). Hier darf ''TWINT'' nicht geändert werden! 
 +'' Auslesen der übermittelten Daten =============='' 
 +  - Hier wird solange gewartet, bis I2C Daten vorliegen 
 +  - Nach dem Ändern des Konrollregisters muss die Abarbeitung abgewartet werden. Dies ist daran zu erkennen, das ''TWINT'' gleich ''1'' wird 
 +  
 +</WRAP></WRAP>
  
 <-- <--
  
  
-==== komplexere Anwendung ==== +==== komplexere Anwendung - mit Interrupt ==== 
-Als Beispiel wurde die Temperaturmessung gewählt + 
-  {{microcontrollertechnik:twi_slave_master.zip}}+Als Beispiel wurde hier die Temperaturmessung aus Lektion 8 gewählt. \\ 
 +Das Projekt und die Simulation ist hier zu finden {{microcontrollertechnik:ad_wandler_i2c.zip}} 
 + 
 +Bitte nutzen Sie diese als Vorlage, wen Sie eine I2C Schnittstelle implementieren wollen. Da in diesem Programmstand alles über Interrupts läuft, können auch weitere Funktionen abgearbeitet werden. 
 + 
 +===== weiterführende Unterlagen =====
  
 ==== Bibliotheken ==== ==== Bibliotheken ====
Zeile 491: Zeile 483:
   * alternative und schlanke Implementierung des Slaves von [[https://github.com/thegouger/avr-i2c-slave|The Gouger (GitHub)]] \\ (Kopie vom 16.01.22: {{microcontrollertechnik:avr-i2c-slave-master.zip}})   * alternative und schlanke Implementierung des Slaves von [[https://github.com/thegouger/avr-i2c-slave|The Gouger (GitHub)]] \\ (Kopie vom 16.01.22: {{microcontrollertechnik:avr-i2c-slave-master.zip}})
  
-===== Beispiele =====+==== Beispiele ====
  
-  * Simulide: ''...\share\simulide\examples\Arduino\sofware_i2c_lcd\i2c_lcd-arduino'' (hierbei wird Software I2C eingesetzt) +  * In Simulide ist eine Umsetzung von Software I2C zu finden: ''...\share\simulide\examples\Arduino\sofware_i2c_lcd\i2c_lcd-arduino''  
-  * Software I2C+  * Eine vollständige Implementierung des Codes für den I2C Master ist in der Library von Peter Fleury zu finden: [[http://www.peterfleury.epizy.com/avr-software.html|library]], [[http://www.peterfleury.epizy.com/doxygen/avr-gcc-libraries/group__pfleury__ic2master.html|Dokumentation]] 
-    * Library von Peter Fleury: [[http://www.peterfleury.epizy.com/avr-software.html|library]], [[http://www.peterfleury.epizy.com/doxygen/avr-gcc-libraries/group__pfleury__ic2master.html|Dokumentation]] +  Eine Implementierung eines [[Software I2C Slave]], also eines I2C an einem beliebigen Pin durch Bitmaipulation, habe ich bereitgestellt. Es soll jedoch stets bevorzugt werden die vorhandenen Hardware I2C zu nutzen.
-    * [[Software I2C Slave]]+
  
-===== weiterführende Unterlagen ===== +==== Beschreibung ==== 
-  Die "[[https://mu.microchip.com/practical-i2c-introduction-implementation-and-troubleshooting|Microchip University]]" hat auch eine schöne Einführung in I2C. Hier wird aber nicht die Implementierung in Microchip Studio auf einem AVR-Chip gezeigt, sondern in MPLAB X auf einem PIC. D.h. der Code ist nicht direkt übertragbar.+ 
 +Die "[[https://mu.microchip.com/practical-i2c-introduction-implementation-and-troubleshooting|Microchip University]]" hat auch eine schöne Einführung in I2C. Hier wird aber nicht die Implementierung in Microchip Studio auf einem AVR-Chip gezeigt, sondern in MPLAB X auf einem PIC. D.h. der Code ist nicht direkt übertragbar.