Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
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/08/29 19:37] (aktuell) mexleadmin |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== | + | ====== |
<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. | ||
</ | </ | ||
==== Video ==== | ==== Video ==== | ||
+ | {{youtube> | ||
+ | |||
+ | <WRAP hide> | ||
{{youtube> | {{youtube> | ||
+ | </ | ||
</ | </ | ||
- | |||
==== Statemachine für Datenpaket ==== | ==== Statemachine für Datenpaket ==== | ||
Zeile 37: | Zeile 42: | ||
</ | </ | ||
- | **Übertragung**\\ | + | === Übertragung |
Für die I2C Übertragung " | Für die I2C Übertragung " | ||
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 154: | ||
===== Software ===== | ===== Software ===== | ||
- | ==== einfache Anwendung ==== | + | ==== einfache Anwendung |
Im ersten Schritt ist im folgenden eine einfache Anwendung dargestellt. \\ | Im ersten Schritt ist im folgenden eine einfache Anwendung dargestellt. \\ | ||
Zeile 177: | Zeile 182: | ||
--> III. Code in Microchip Studio # | --> III. Code in Microchip Studio # | ||
- | ==== TWI Master | + | <fs x-large> |
<WRAP group>< | <WRAP group>< | ||
Zeile 195: | Zeile 200: | ||
| | ||
| | ||
- | | + | |
C-Compiler: AVR/GNU C Compiler 5.4.0 | C-Compiler: AVR/GNU C Compiler 5.4.0 | ||
| | ||
Zeile 236: | Zeile 241: | ||
void I2C_transmitStop(); | void I2C_transmitStop(); | ||
- | uint8_t TWI_Address = TWI_ADRESS; | + | uint8_t TWI_Address = TWI_ADRESS; |
uint8_t TWI_Data | uint8_t TWI_Data | ||
Zeile 251: | Zeile 256: | ||
I2C_transmitDataOrAddress(TWI_Data); | I2C_transmitDataOrAddress(TWI_Data); | ||
I2C_transmitStop(); | I2C_transmitStop(); | ||
- | // | + | _delay_us(1); |
} | } | ||
} | } | ||
Zeile 260: | Zeile 265: | ||
void I2C_Init() | void I2C_Init() | ||
{ | { | ||
- | | + | CLR_BIT(TWSR, |
- | | + | CLR_BIT(TWSR, |
TWCR = 0; | TWCR = 0; | ||
TWBR = ((F_CPU/ | TWBR = ((F_CPU/ | ||
Zeile 295: | Zeile 300: | ||
</ | </ | ||
</ | </ | ||
- | + | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | |
- | ''/ | + | |
- | + | ||
- | Ändern Sie auch hier wieder die Beschreibung am Anfang des C-Files, je nachdem was Sie entwickeln | + | |
'' | '' | ||
\\ \\ | \\ \\ | ||
- | - Hier wird wieder geprüft ob die Frequenz des Quarz bereits | + | - Hier wird die Frequenz des Quarz direkt |
- | - Die Header-Dateien entsprechen denen der letzten Programme. \\ \\ \\ \\ \\ | + | |
- | - Auch die Makros entsprechen denen der letzten Programme. | + | - Die Header-Dateien |
- | - Die Konstanten | + | - Die weiteren |
- | - 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 '' | + | - Konstante für die Invertierung |
- | - Wird eine ansteigende Flanke der Taste S1 gedrückt, so wird '' | + | - Konstante |
- | - Bei den Funktionsprototypen sind einige bekannte Unterprogramme vorhanden. Details werden weiter unten erklärt. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | - Zwei globale Variablen beinhalten |
'' | '' | ||
- | - Zunächst werden zwei Initialisierungsroutinen aufgerufen (siehe weiter unten) | + | - es werden |
- | - Dann werden die " | + | - in der Haupschleife läuft: |
- | - Auch hier gibt es eine " | + | - Zu Beginn |
- | - Mit dem Befehl '' | + | - Als nächstes |
- | - in der Endlosschleife ist nur eine switch-case Anweisung zu finden. Diese stellt den Auswahlteil einer Zustandsmaschine dar: \\ {{drawio> | + | - Das erste Byte auf dem I2C Bus ist die Adressebyte. Dieses setzt sich aus der Adresse und einem Bit zusammen, welches angibt, ob der Slave nur zuhören ('' |
- | - Beim '' | + | - Nun wird der Zustand das Port B als I2C Daten eingelesen. |
+ | - Diese werden per I2C übertragen. | ||
+ | - Und zum Schluss wird das Stopp Bit gesendet \\ \\ | ||
- | '' | + | '' |
- | - Mit dem Befehl | + | - Durch das Zurücksetzen der Bits '' |
- | - Der Überlauf-Interrupt durch den Timer2 wird erst bei Überlauf des 8-Bit Wert ausgeführt. Auch hier ergibt sich durch den Prescaler | + | - Auch das Kontrollregister wird zurückgesetzt |
- | - Die Ermittlung von '' | + | - im Bitraten Register wird die I2C Frequenz eingestellt |
- | - Eine große Änderung ist, dass bereits | + | '' |
- | '' | + | - Es soll die I2C Schnittstelle aktiviert |
- | \\ \\ \\ | + | - Nach dem Ändern des Konrollregisters muss die Abarbeitung abgewartet werden. Dies ist daran zu erkennen, das '' |
- | - In dieser Funktion werden zunächst | + | '' |
- | - Neu hier ist, dass über '' | + | - Bevor Daten übertragen |
- | + | - Wieder | |
- | '' | + | - auch hier muss wieder |
- | - Die Funktion | + | '' |
- | - 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 |
- | + | ||
- | \\ \\ \\ \\ \\ \\ | + | |
- | + | ||
- | '' | + | |
- | - Da der Auswahlbildschirm mit dem Hauptmenu nicht nur beim Start, sondern auch nach jeder Rückkehr aus Unterprogrammen dargestellt | + | |
- | + | ||
- | \\ \\ \\ \\ \\ | + | |
- | + | ||
- | ''/ | + | |
- | + | ||
- | 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 | + | |
- | - '' | + | |
- | - Die Schleife wird solange ausgeführt, | + | |
- | - Beim Aktivieren der LED wird auch auf dem Display eine '' | + | |
- | - Nach einer Sekunde wird die LED ausgeschalten und auf dem Display eine '' | + | |
- | - 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. | + | |
- | + | ||
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
- | ''/ | + | |
- | + | ||
- | Hier ist das Programm [[2_sound_und_timer|Sound | + | |
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
- | + | ||
- | - Die Port Initialisierung, | + | |
- | - Hier wird Timer 0 genutzt, um das gepulste Signal an den Lautsprecher zu verändern. | + | |
- | - Die while-Schleife wird wieder abgebrochen, | + | |
- | - Neben dem Herunterzählen der Periodenlänge | + | |
- | - 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 | + | |
- | - Falls die Taste 1 gedrückt wurde, wird sowohl __in der for__-Schleife, | + | |
- | - Das Heraufzählen der Frequenz gleich dem Herunterzählen, | + | |
- | + | ||
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
- | '' | + | |
- | + | ||
- | 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. '' | + | |
- | + | ||
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
- | ''/ | + | |
- | + | ||
- | Hier ist das Programm [[4_up_down_counter|Up/ | + | |
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
- | + | ||
- | - Im wesentlichen gleicht das Programm dem bereits bekanntem. Es kann aber auf die bereits berechnete Flanken '' | + | |
- | + | ||
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
- | '' | + | |
- | + | ||
- | - Je nach gedrückter Taste wird hier die Variable '' | + | |
</ | </ | ||
- | --> TWI Slave # | + | <fs x-large>**I2C Slave**</ |
- | ==== TWI Slave ==== | + | |
- | < | + | < |
- | <sxh c; first-line: 1> | + | |
/* ---------------------------------------------------------------------------- | /* ---------------------------------------------------------------------------- | ||
- | + | | |
| | ||
| | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
- | Dateiname : I2C_SimpleMaster.c | + | Displayanzeige : keine |
- | Autoren | + | Tastenfunktion : Die Tastenstellung der Dip-Schalter an Port B werden als Wert über I2C weitergegeben. |
+ | Dabei zählt ein gedrückter Schalter | ||
- | Datum | + | Jumperstellung : keine |
- | Version | + | Fuses im uC : keine |
| | ||
- | | + | |
- | + | // ----------------------------------------------------------------------------*/ | |
- | | + | |
- | C-Compiler: AVR/GNU C Compiler 5.4.0 | + | |
- | + | ||
- | | + | |
- | + | ||
- | + | ||
| | ||
- | // ----------------------------------------------------------------------------*/ | ||
- | |||
// Deklarationen ============================================================== | // Deklarationen ============================================================== | ||
+ | | ||
+ | // Festlegung der Quarzfrequenz | ||
+ | #define F_CPU 8000000UL // | ||
+ | #define F_SCL | ||
- | // Festlegung der Quarzfrequenz | ||
- | #define F_CPU 16000000UL | ||
- | #define F_SCL 10000L //100 kHz | ||
- | |||
// Include von Header-Dateien | // Include von Header-Dateien | ||
#include < | #include < | ||
+ | |||
// Konstanten | // Konstanten | ||
- | # | + | #define SET_BIT(BYTE, |
- | #define CLR_BIT(BYTE, | + | #define CLR_BIT(BYTE, |
- | #define TGL_BIT(BYTE, | + | #define TGL_BIT(BYTE, |
+ | #define SET_ALL_TO_OUT (0xFF) // | ||
+ | #define TWI_ADRESS (0b0001010) // | ||
+ | #define TWI_ADRESS_MASK (0b0001010) // | ||
+ | |||
// | // | ||
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 = | + | uint8_t TWI_Address |
- | uint8_t TWI_AddressMask = 0b11111110; | + | uint8_t TWI_AddressMask |
+ | |||
int main(void) | int main(void) | ||
{ | { | ||
- | DDRD= 0xFF; // Auf DDRC die Daten ausgeben | + | DDRB= SET_ALL_TO_OUT; // Auf DDRC die Daten ausgeben |
- | I2C_setAddress(TWI_Address); | + | I2C_setAddress(TWI_Address); |
- | + | | |
while (1) | while (1) | ||
{ | { | ||
- | PORTD | + | PORTB = I2C_readData(); |
} | } | ||
} | } | ||
+ | |||
////////////////////////////////////////////////// | ////////////////////////////////////////////////// | ||
// 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<< | + | |
- | TWAMR= TWI_AddressMask; | + | TWAMR= TWI_AddressMask; |
- | TWCR = (1<< | + | TWCR = (1<< |
} | } | ||
+ | |||
////////////////////////////////////////////////// | ////////////////////////////////////////////////// | ||
// Auslesen der übermittelten Daten | // Auslesen der übermittelten Daten | ||
////////////////////////////////////////////////// | ////////////////////////////////////////////////// | ||
- | char I2C_readData() | + | char I2C_readData() |
{ | { | ||
- | while (!(TWCR & (1<< | + | |
- | return TWDR; // übermittle Daten | + | return TWDR; // übermittle Daten |
} | } | ||
- | |||
</ | </ | ||
- | </ | + | </ |
+ | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | ||
+ | '' | ||
+ | \\ \\ | ||
+ | - 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 \\ \\ | ||
+ | |||
+ | '' | ||
+ | |||
+ | - 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 \\ \\ \\ \\ \\ | ||
+ | |||
+ | '' | ||
+ | - 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 '' | ||
+ | - Im Kontrollregister wird die " | ||
+ | '' | ||
+ | - Hier wird solange gewartet, bis I2C Daten vorliegen | ||
+ | - Nach dem Ändern des Konrollregisters muss die Abarbeitung abgewartet werden. Dies ist daran zu erkennen, das '' | ||
+ | |||
+ | </ | ||
<-- | <-- | ||
- | ==== komplexere Anwendung ==== | + | ==== komplexere Anwendung |
- | Als Beispiel wurde die Temperaturmessung gewählt | + | |
- | | + | Als Beispiel wurde hier die Temperaturmessung |
+ | Das Projekt und die Simulation ist hier zu finden | ||
+ | |||
+ | 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 ===== | ||
+ | |||
+ | Die detaillierte Beschreibung zu I2C findet sich in des {{microcontrollertechnik: | ||
==== Bibliotheken ==== | ==== Bibliotheken ==== | ||
Zeile 491: | Zeile 484: | ||
* alternative und schlanke Implementierung des Slaves von [[https:// | * alternative und schlanke Implementierung des Slaves von [[https:// | ||
- | ===== Beispiele | + | ==== Beispiele ==== |
- | * Simulide: '' | + | * In Simulide |
- | * Software | + | * Eine vollständige Implementierung des Codes für den I2C Master ist in der Library von Peter Fleury |
- | * Library von Peter Fleury: [[http:// | + | * Eine Implementierung eines [[Software I2C Slave]], also eines I2C an einem beliebigen Pin durch Bitmaipulation, |
- | * [[Software I2C Slave]] | + | |
- | ===== weiterführende Unterlagen ===== | + | ==== Beschreibung |
- | | + | |
+ | Die " |