3.7 🚧 I2C Schnittstelle
[MezData: Links-I2C] [Portexpander HLF 8574] [Temperatursensor LM75A] [Druck- und Temperatursensor BMP280] [MezData: Discovery-Room][stm32-I2C-Lib][Elektrische Gedanken]
Einlesen in die Theorie der Schnittstelle
- Mit 2 Leitungen viele Komponenten anschließen. Lesen: [Wikipedia: I2C]
- Wozu und wer hat I2C-Schnittstelle „erfunden“?
- Wie lauten die Bezeichnungen der Bus-Leitungen und wofür stehen die Abkürzungen?
- Zeichnen Sie ein Blockschaltbild mit einem Controller und zwei Targets.
- Erklären Sie OpenCollector- bzw. OpenDrain-Ausgänge und warum PullUp-Widerstände nötig sind.
- Was ist ein „Wired-AND“?
- Bei welchen Zustand von SCL werden die Daten von SDA übernommen?
- Arduino-Wire-Operationen
Befehl / Beispiel | Beschreibung |
---|---|
#include <Wire.h> // I2C-Library | I2C Library laden |
Wire.begin(); Wire.begin(SDA, SCL); // Alternative Leitungen festlegen | Schnittstelle starten |
Wire.setClock(frequenz); | Optional die Übertragungsfrequenz anpassen, voreingestellt sind 100000 Hz siehe [Arduino-Doku] |
Schreiben in Baustein | Adresse des Bausteins angeben und mit Wire.write() in einen Puffer schreiben, am Ende Daten absenden aus dem Puffer mit Wire.endTransmission() an den Baustein senden. |
Wire.beginTransmission(0x27); | Daten sollen zu Zieladresse 0x27 gesendet werden, der Datenpuffer wird geleert. Der Datenpuffer ist normalerweise 32 Byte groß (Kann geändert werden) |
Wire.write(0x00) | 0x00 in den Datenpuffer schreiben |
Wire.write(„Hallo“) | „Hallo“ in den Datenpuffer schreiben |
Wire.write(data, length) | Den Inhalt eines Datenfeldes in den Puffer schreiben. |
error= Wire.endTransmission(); | Die Daten aus dem Puffer an die Zieladresse versenden und den Bus wieder frei geben. Wenn error==0 hat ein Slave mit ACKs geantwortet und die Daten verarbeitet. |
Wire.endTransmission(false); | Die Daten aus dem Puffer an Zieladresse versenden und den Bus noch nicht frei geben. (Weil danach gleich Daten gelesen werden sollen mit Restart) |
Lesen aus Baustein | Den Baustein adressieren und #Bytes lang Daten anfordern und in den Puffer schreiben. |
Wire.requestFrom(adress,#Bytes) | #Bytes werden vom Baustein mit adress angefordert und in den Puffer abgelegt. Beim letzten Byte wird ein NAK vom Master gesendet. |
x=Wire.read() | Ein Byte wird aus dem Puffer gelesen und der Pufferzeiger um 1 erniedrigt. |
x=Wire.available() | Gibt die Anzahl der noch zu lesenden Bytes im Puffer zurück. |
Mit Portexpander HLF8574T zwei LED über I2C im Wechsel leuchten lassen
Die LED-Anoden sind VDD (5V) verbunden. P1 und P0 des PCF8574-Moduls sind über 330Ω Widerstände an die Kathoden angeschlossen. Somit leuchten die LED, wenn an den P-Ausgängen eine 0 anliegt. Hintergrund: Die Ausgänge des HLF8574T liefern nur kurz bei einem Schreibvorgang höhere Ströme und sonst nur 100µA bei log. 1 (siehe Datenblatt HLF8574T). An den Bus können mehrere Targets angeschlossen werden. Damit sie unterscheidbar sind bekommt jedes Target eine eigene Adresse [RN-Wissen: I2C-Adressierung]. Bei unserem Modul sind die Bit A6..A3 fest (0b0100000 = 0x20). Mit den Jumpern (die blauen Dinger unter A2) können die Bit A2..0 von uns eingestellt werden. Somit ist für uns die Targetadresse von 0b0100000 = 0x20 bis 0b0100111 = 0x27 wählbar. Zunächst sei sie 0x20.
#include <Wire.h> // I2C-Library
#define ADRESSE 0x20 // Adresse des Bausteins im I2C-Bus, siehe Vorgabe des Herstellers
void setup() {
Wire.begin(); //Alternatives PinMapping: Wire.begin(SDA, SCL);
}
void loop() {
Wire.beginTransmission(ADRESSE); // Vorbereitung der Übertragung
Wire.write (0xfe); // 0b1111 1110 in Puffer schreiben: Rote LED soll leuchten
Wire.endTransmission(); // Puffer an Slave senden und Bus freigeben
delay(500);
Wire.beginTransmission(ADRESSE); // Vorbereitung der Übertragung
Wire.write (0xfd); // 0b1111 1101 in Puffer schreiben: Grüne LED soll leuchten
Wire.endTransmission(); // Puffer an Slave senden und Bus freigeben
delay(500);
}
Bei der Übertragung mit Oszilloskop zuschauen
Die Geschichte zu dem Bild: SCL und SDA sind high. Ein Master will senden und zieht SDA auf GND, dies ist die Startbedingung. Um A6 zu übertragen zieht der Master SCL auf GND und legt den Wert von A6 auf SDA. Dann lässt er SCL los und dessen Pegel geht durch den PullUp-Widerstand auf high, jetzt wissen die Slaves, dass das Datenbit auf SDA gültig ist und übernehmen A6. Das Spiel wiederholt sich bis A0 und R/!W-Bit. Wenn bei einem Slave die gewünschte Adresse mit der eingestellen Adresse übereinstimmt zieht er die SDA-Leitung auf GND und gibt sein Ack=OK: Ich bin bereit für Daten. Der Master sendet nun 8 Bit Daten, der Slave quittiert dies mit weiteren Ack=OK Antworten. Hier wurde nur ein Byte zum Slave übertragen. Am Ende lässt der Master SCL und dann SDA los, dies ist die Stoppbedingung, damit zeigt er das Ende der Übertragung an.
Im nächsten Bild wird die Übertragung für grüne LED leuchten lassen gezeigt.
Was passiert, wenn kein Slave antwortet? Im Programm die Adresse von 0x20 auf 0x21 geändert. Kein Modul fühlt sich nun angesprochen und gibt sein Ack=OK:
Wird nun am Modul A0 auf + gejumpert fühlt es sich wieder angesprochen:
I2C-LCD ansteuern
Auf unserem Multifunction-Board befindet sich ein LCD-Modul, das über I2C angesprochen wird, leider an PA11 und PA12, die kein I2C können, daher müssen Drahtbrücken gesetzt werden.
Wenn man das LCD-Modul umdreht findet sich ein Bekannter, der Portexpander HLF8574T. Was macht der da? Tatsächlich sind die meisten preiswerten LCD-Module mit dem Chip HD44780 ausgestattet und der braucht mindestens 6 Leitungen. Daher wird zum sparen gerne ein I2C-Port-Expander verwendet [BLIT2008-Board-LCD]. Beim LCD-Modul gibt es keine Jumper sondern Lötbrücken gegen GND. Sind sie alle offen ist die Target-Adresse 0x27.
Es gibt einen Unterschied bei der Festadresse zwischen HLF8574T und HLF8574A:
HLF8574T: 0x20 HLF8574A: 0x38
Um auf dem LCD was auszugeben gibt es praktische Librarys:
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27
void setup() {
lcd.begin(16, 2); // initialize the lcd
lcd.clear();
lcd.setBacklight(255);
lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
lcd.print("MezMedia.de");
}
void loop() {
}
Den I2C-Bus abscannen um alle Targets zu finden
Oft gibt es das Problem, dass man ein Target verbindet, es aber scheinbar nicht antwortet. Hier ein kurzes Programm, dass alle Adressen abscannt und alle Targets auflistet. Modifizierter Code von dieser Seite: [i2c_scanner]
#include <Wire.h>
void setup(){
Wire.begin();
Serial.begin(9600);
Serial.println("\nI2C Scanner");
}
void loop(){
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ){
Wire.beginTransmission(address); // Target anfunken
error = Wire.endTransmission(); // hat es geantwortet?
if (error == 0){ // kein Fehler also Antwort
Serial.print("I2C Target gefunden bei Adresse 0x");
if (address<16) Serial.print("0");
Serial.println(address,HEX);
nDevices++;
}
else if (error==4){ // Fehler
Serial.print("Unbekannter Fehler bei Adresse 0x");
if (address<16) Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0) Serial.println("Keine I2C Targets gefunden\n");
else Serial.println("fertig\n");
delay(5000);
}
Temperatur mit LM75A messen und auf LCD ausgeben
Nun habe ich die Formelsammlung gelesen und darin den LM75 entdeckt, dabei soll ein Byte übertragen und als Antwort zwei Byte empfangen werden. Also so ein Modul, allerdings mit einen LM75A bestellt: [amazon]
Angeschossen, den Scanner angeworfen und unter Adresse 0x48 antwortet es.
Allerdings wenn man auf der Unterseite mit dem Finger über die Kontakte für die einstellbare Adresse kommt ändert sie sich, die Eingänge A2..A0 hingen in der „Luft“. Ok, mit dem Lötkolben Lötbrücken setzen. Aus Neugier habe ich geprüft, ob die VCC-Kontakte der Brücken mit VCC verbunden sind: Leider nein, untereinander haben sie zwar Kontakt, aber eine Verbindung zu VCC konnte ich nicht feststellen. Die GNDs sind miteinander verbunden. Falls eine andere Adresse als 0x48 eingestellt werden sollte würde es mich nicht wundern, wenn es spinnt…
Gut zu erkennen sind die PullUp-Widerstände von 10kΩ für SDA und SCL auf der Platine.
Also den LM75A ohne Library selber auslesen können, damit wir uns intensiver mit I2C-Kommunikation beschäftigen -RTFM: [Temperatursensor LM75A]
In der Forsa wird der LM75 dokumentiert, der kann nur 9 Bit Auflösung der Temperatur, beim LM75A sind es 11 Bit.
Der LM75 hat interne Register?
Beim HLF8574 war es einfach, es gab nur ein 1 Byte Register, das gelesen oder beschrieben werden konnte: Target-Adresse auswählen und 1 Byte transferieren.
Beim LM75 gibt es 4 interne Register. Ein „Pointer“-Register merkt sich welches dieser Register gemeint ist. Beim Schreiben muss immer der Pointerwert für Zielregister 0..3 gesendet werden. Beim Lesen wird einfach das zuletzt eingestellte Register verwendet. Will man ein anderes Register lesen muss zuerst der Pointer geändert werden. Steht alles mit Beispielen in der Doku. Muss ich das alles wissen um einfach die Temperatur auslesen zu können? Nein!
Voreingestellt ist Register 0 und dort steht in zwei Bytes die Temperatur: Zwei Bytes lesen und gut ist. Hier die Kodierung der Temperatur in den zwei Bytes:
MSByte | LSByte | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
LM75 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | x | x | x | x | x | x | x |
LM75A | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | x | x | x | x | x |
Es ist total einfach: Im MSByte steht die Temperatur mit Vorzeichen (Bit 7) in °C, will man es genauer haben kriegt man beim LM75 noch die halben Grade im LSByte und beim LM75A die achtel Grade geliefert. Hier mein Test-Programm:
#include <Wire.h> // I2C-Library
#include <LiquidCrystal_PCF8574.h> // LCD
#define ADRESSE 0x48 //0b01001000 LM75A Adresse
LiquidCrystal_PCF8574 lcd (0x27);
signed char byteH; // das MSB mit Vorzeichen (signed ist wichtig) in Grad C
unsigned char byteL; // das LSB die 8tel Grad ohne Vorzeichen
float temp;
void setup() {
Serial.begin(9600);
Wire.begin(); //Alternatives PinMapping: Wire.begin(SDA, SCL);
lcd.begin(16, 2); // initialize the lcd
lcd.clear();
lcd.setBacklight(255);
lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
lcd.print("LM75A TempSensor");
}
void loop() {
Wire.requestFrom(ADRESSE, 2); // 2 Bytes von Modul in Pufferspeicher lesen
byteH = Wire.read(); // Hole das 1. Byte aus Pufferspeicher
byteL = Wire.read(); // Hole das 2. Byte aus Pufferspeicher
//byteH=0b11111111; // zum Testen ob -0.125 laut Doku rauskommt
//byteL=0b11100000;
temp = ((byteH<<3) + (byteL>>5))*0.125; // LM75A mit 0.125 Grad Auflösung
lcd.setCursor(0, 1);
lcd.print(temp);
delay(1000);
}
Welche Temperatur wird gemessen, wie warm ist gerade der Sensor?
Lösung
22,62 °C
Nach dem 2. Byte sendet der Master NAK, was könnte das bedeuten? An dieser Stelle wäre ein Studium des Datenblatts [Temperatursensor LM75A] ab Seite 11 dienlich.
🧑🔬 Wie funktioniert Wire.requestFrom(ADRESSE, 2)
Befehl / Beispiel | Beschreibung |
---|---|
Wire.requestFrom(ADRESSE, 2); | 2 Bytes vom Slave ADRESSE in den Puffer laden. |
bla = Wire.read(); | Übertrage Byte aus Pufferspeicher in bla und „entferne es aus dem Puffer“ |
Wire.available() | Gibt die Anzahl noch lesbarer Bytes aus dem Pufferspeicher zurück. |
Wofür ist Wire.available() nütze? Wire.requestFrom(Adr,#Bytes) adressiert den Baustein mit Adr und verlangt einfach #Bytes, d.h. er liest #Bytes oft von dem Baustein Bytes in einen Puffer (max. 32 Bytes). Nach dem letzten zu lesenden Byte sendet der Master ein NAK, damit weis der Slave, dass die Anforderung zu Ende ist. Nach dem die Daten im Puffer sind können sie mit Wire.read() dort abgeholt werden, dabei wird ein IndexZeiger erhöht, man bekommt immer das nächste Byte.
Wire.available() gibt die Anzahl der noch verfügbaren Bytes im Puffer zurück.
🧐 Was geschieht, wenn der LM75A mehr Bytes liefern soll als er kann?
Dafür ein Test mit Wire.requestFrom(ADRESSE, 3);
Nach dem Datenblatt kann der Baustein 2 Bytes lesend liefern. Nun wird von ihm verlangt 3 Bytes zu bringen, nach dem 2. Byte gibt der Master kein NAK für das Ende sondern ein ACK und liefert weiter Takte über SCK. Der Baustein hat aber nichts mehr zu sagen, er schweigt, zieht SDA nicht mehr auf GND, es finden sich dann 0xFF im Puffer. Wenn ich 10 Bytes vom Baustein mit Wire.requestFrom(Adr,10) lese sind auch 10 Bytes im Puffer, egal ob der Baustein nach Byte 2 nur noch schweigt und 0xFF liefert.
Fehler in der Arduino-Forsa: Wire.endTransmission() ist nach Wire.requestFrom(…) sinnlos, sogar falsch.
DS3231 Extremely Accurate I2C-Integrated RTC/TCXO/Crystal
[AZ-Delivery RTC DS3231 Modul🔗] beinhaltet [DS3231: Datenblatt 🔗] und EEPROM [AT24C32 🔗]
Überfliegen Sie das Datenblatt es DS3231 und beantworten Sie diese Fragen:
- Kann die Slave-Adresse des Bausteins geändert werden, wie lautet die Baustein-Basis-Adresse, wie ist der Subadressbereich?
- Wie viele interne Register hat der Baustein?
- Wie viele Bit haben die Register?
- Zählt der Register-Pointer bei Schreib und Lesezugriffen hoch, gibt es einen Wrap-Around (Sprung von maximaler Adresse nach 0)?
- Wie sieht der Transfer aus, wenn der Master zum Slave sendet?
- Wie sieht der Transfer aus, wenn Master vom Slave Daten abruft?
Lösung
- Nein, die Adresse ist fix und lautet 0x68
- Er hat (0x12+1) = 19 Register.
- Die Register haben 8 Bit.
- Der Adresspointer zählt bei Schreib- und Lesezugriffen hoch und springt nach Adresse 0x12 wieder auf 0.
- Figure 3: Slave-Adresse Write, Register-Pointer setzen, Daten senden, Busfreigabe.
- Figure 4: Slave-Adresse Read, Daten lesen (beginnend mit dem Register-Pointer, der dabei erhöht wird), letztes Lesen mit NAK, Busfreigabe.
Figure 5: Slave-Adresse Write, Register-Pointer setzen, Restart, Slave-Adresse Read, Daten lesen, letztes Lesen mit NAK, Busfreigabe.
Testprogramm
#include <Wire.h> // I2C-Library
#define RTC 0x68 // DS3231
void setup() {
Wire.begin(); //Alternatives PinMapping: Wire.begin(SDA, SCL);
Wire.beginTransmission(RTC); // Übertragung zu RTC vorbereiten
Wire.write(0x00); // Registerpointer auf 0 setzen
Wire.write(0x00); // 0 Sekunden
Wire.write(0x59); // 59 Minuten
Wire.write(0x23); // 23 Uhr
Wire.write(0x4); // Donnerstag (1=Mo..7=So)
Wire.write(0x15); // 15
Wire.write(0x02); // 02
Wire.write(0x24); // 2024
Wire.endTransmission(); // Daten zum Slave übertragen
}
void loop() {
Wire.beginTransmission(RTC); // Übertragung vorbereiten
Wire.write(0x00); // Register-Pointer auf 0
Wire.endTransmission(false); // übertragen ohne Busfreigabe
Wire.requestFrom(RTC,7); // hol die 7 Bytes in den Puffer
delay(1000);
}
Das Stellen der Uhr ist einfach, das Lesen der Uhrzeit hat mich etwas beschäftigt.
Um die Uhrzeit aus zu lesen wird der interne Register-Pointer im DS3231 auf 0 gesetzt mit
Wire.beginTransmission(RTC); // vorbereiten
Wire.write(0x00); // Register-Pointer auf 0
Wire.endTransmission(false); // übertragen
und dann werden die Bytes mit
Wire.requestFrom(RTC,7)
angefordert, es werden folgend vom Slave Sekunden, Minuten usw. zum Master übertragen. Nach Vorgabe in der Doku muss nach dem Write der Bus nicht freigegeben werden, es kann gleich mit dem Request begonnen werden.
Falls nur die Uhrzeit gelesen werden soll reicht eine Übertragung der ersten 3 Register mit
Wire.requestFrom(RTC,3).
🧑🔬 Welchen Wert hat jetzt der Register-Pointer, wie könnte das ermittelt werden?
Wire.endTransmission() verstehen
Mit Wire.endTransmission() wird der Inhalt des Puffers an den Slave gesendet und der Bus wieder frei gegeben.
Die Freigabe des Busses kann mit endTransmission(false) vermieden werden (Restart), um gleich mit Wire.requestFrom(RTC,7) mit dem Lesen zu beginnen.
Siehe Wire-Arduino-Referenz 🔗
Aufgabe: Die gelesenen Daten auswerten mit Wire.read() und Ausgabe auf dem LCD. Ergänzen Sie den Code:
#include <Wire.h> // I2C-Library
#include <LiquidCrystal_PCF8574.h> // LCD
#define RTC 0x68 // DS3231
LiquidCrystal_PCF8574 lcd (0x27);
signed char byteH; // das MSB mit Vorzeichen (signed ist wichtig) in Grad C
unsigned char byteL; // das LSB die 8tel Grad ohne Vorzeichen
float temp;
void setup() {
Wire.begin(); //Alternatives PinMapping: Wire.begin(SDA, SCL);
lcd.begin(16, 2); // initialize the lcd
lcd.clear();
lcd.setBacklight(255);
lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
Wire.beginTransmission(RTC); // Uhrzeit stellen
Wire.write(0x00); // Registerpointer auf 0 setzen wegen Sekunden
Wire.write(0x00); // 0 Sekunden
Wire.write(0x23); // 23 Minuten
Wire.write(0x16); // 16 Uhr
Wire.write(0x4); // Donnerstag (1=Mo..7=So)
Wire.write(0x15); // 15
Wire.write(0x02); // 02
Wire.write(0x24); // 2024
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(RTC);
Wire.write(0x00); // Registerpointer auf 0 setzen
Wire.endTransmission(false); // übertragen ohne Busaufgabe
Wire.requestFrom(RTC,3); // hol die 3 Bytes in den Puffer
char sekunden = Wire.read();
...
lcd.setCursor(0, 0);
lcd.printf("%02x:%02x:%02x",stunden,minuten,sekunden); // Zeit ausgeben
delay(1000);
}
Lösung
char minuten = Wire.read();
char stunden = Wire.read();
Aufgabe: Die Temperatur des Chips steht in 0x11 und 0x12 (Doku lesen). Ergänzen Sie das Programm um die Code-Sequenz um sie an Position (10,0) der LCD-Anzeige ausgeben zu können.
Lösung
Wire.beginTransmission(RTC);
Wire.write(0x11); // Registerpointer auf MSB Temperatur setzten
Wire.endTransmission(false);
Wire.requestFrom(RTC,2); // hol die 7 Bytes in den Puffer
byteH = Wire.read(); // Hole das 1. Byte aus Pufferspeicher
byteL = Wire.read(); // Hole das 2. Byte aus Pufferspeicher
temp = ((byteH<<2) | (byteL>>6))*0.25; // mit 0.25 Grad Auflösung
lcd.setCursor(10, 0);
lcd.print(temp);
EEPROM AT24C32
Netterweise ist in dem RTC-Modul noch ein EEPROM [AT24C32 🔗] verbaut. In diesem Baustein wollen wir nun eine Botschaft schreiben.
Überfliegen Sie das Datenblatt und beantworten Sie diese Fragen:
- Kann die Slave-Adresse des Bausteins geändert werden, wie lautet die Baustein-Basis-Adresse, wie ist der einstellbare Adressbereich?
- Wie viel Byte Speicher hat der Baustein und wie ist er organisiert?
Lösung
- Der Baustein hat 3 Pins zum Einstellen einer Sub-Adresse. Die Basisadresse ist 0x50 (Figure 1.) Der Adressbereich ist 0x50..0x57.
- 4Ki Byte Speicher, organisiert in 256 Seiten mit 32 Bytes.
🧑🔬 Das EEPROM hat es in sich: Beim Schreiben mehrerer Bytes muss beim Überschreiten der Seitengrenze (Seite ist 32Byte groß) beachtet werden, dass wieder bei Byte 0 der Seite weiter geschrieben wird. Beim Lesen mehrerer Bytes wird dagegen auf die nächste Seite gesprungen..
Wire.write(„Bla“): Hier ergibt sich das Problem, das die 0 am Ende des Strings nicht ins EEPROM geschrieben wird, somit weis man beim Lesen später nicht wann der String zu Ende ist. Abhilfe: Nach String schreiben noch Wire.write(0) schreiben..
Aufgabe: Erstellen Sie ein Programm. Schreiben Sie bei der Initialisierung „Ich beschreibe ein EEPROM“ ab Speicheradresse 0 in das EEPROM und geben Sie in der loop() den Text wieder auf der seriellen Schnittstelle aus. Der Baustein hat die I2C Adresse 0x57.
Lösungsvorschlag
#include <Wire.h> // I2C-Library
#define EEPROM 0x57 // AT24C32
void setup() {
Serial.begin(9600);
Wire.begin(); //Alternatives PinMapping: Wire.begin(SDA, SCL);
char text[] = "Ich beschreibe ein EEPROM";
Serial.printf("Textlaenge: %d\n",sizeof(text));
Wire.beginTransmission(EEPROM); // Übertragung vorbereiten
Wire.write(0x00); // Speicheradresse High
Wire.write(0x00); // Speicheradresse Low
Wire.write(text); // Text senden, die Null am Ende des Strings wird verschluckt
Wire.write(0); // Notwendig,damit String terminiert ist
Wire.endTransmission(); // an Slave senden
}
void loop() {
char botschaft[32]; // Textbotschaft
int bIndex=0; // Index für Botschaft
char c;
Wire.beginTransmission(EEPROM);
Wire.write(0x00); // Speicheradresse High
Wire.write(0x00); // Speicheradresse Low
Wire.endTransmission(false);
Wire.requestFrom(EEPROM,32); // hol 32 Bytes in den Puffer
while(Wire.available()&&bIndex<sizeof(botschaft)){
c=Wire.read();
botschaft[bIndex]=c;
bIndex++;
if(c==0) break;
}
Serial.println(botschaft);
Serial.println(bIndex);
delay(5000);
}
Luftdruck und Temperatursensor BMP280
Siehe –>3.5 Sensoren. Der Lerneffekt bzgl. I2C-Bus ist dabei nicht besonders hoch, der Sensor ist komplex und es wird auch geraten die Library dafür zu verwenden.
Für ein Projekt, das sich mit dem Sensor beschäftigt aber brauchbar.
I2C-Schnittstelle Eckpunkte
- Ist eine Serielle Schnittstelle
- Arbeitet nach dem Master-Slave Prinzip
- Haben einen gemeinsamen Takt (bzw. synchronisieren ihren Takt) – Standard-Übertragungsrate beimI2C-Bus ist 100kBit/s und maximale Übertragungsrate ist 3,4 Mbit/s
- 1 Master kann bis zu 127 Slaves ansprechen
- Halbduplex (bidirektional)
- 2-Draht-Bus: SDA und SCL
- Ablauf: Im Ruhezustand sind (SDA=1 und SCL=1)
Start-Condition (SDA=0 und SCL=1) Geräteadresse (7 Bit) – Ack (1 Bit) – Daten (8-Bit) – Ack (1 Bit) – … – Stop-Condition (SDA und SCL auf High)
Fragen zu I2C
- Werden die Daten beim I2C-Bus in Halb- oder Vollduplex übertragen, erklären Sie den Unterschied beider Begriffe.
- Benennen Sie die Leitungen, die beim I2C-Bus verwendet werden und erklären Sie deren Funktion.
- Wofür sind PullUp-Widerstände erforderlich?
- Wie viele Teilnehmer kann der Bus bei 8 Bit-Adressierung inclusive der reservierten Adressen haben?
- Was versteht man unter Hersteller- und Subadresse?
- Wie wird unterschieden ob ein Teilnehmer lesen oder senden soll?
- Wird zuerst LSB oder MSB gesendet?
Aufgaben und abprüfbares Wissen
Sobald man alte und einfache Module verlässt wird es kompliziert, Details werden in die Nutzung von Library zu den Sensoren verlagert.
Falls man eigene Targets entwickelt siehe MezData: Discovery-Game sieht es schon spannender aus.
Schnipsel und ToDo
- Grösse von PullUp und Serienwiderstand -> Link. Wann müssen wir uns um die PullUps selber kümmern?
- ¡Selbst gebaute Targets siehe Discovery-Game! Event-Programmierung bei Bus-Action.
- Alternative Ports für I2C verwenden.
14 Segementanzeige mit HT16K33
Synopsis: [https://www.amazon.de/dp/B08NP883DT] [Datenblatt] [An Introduction to 14-Segment LED Displays with the HT16K33 Driver] [A HT16K33 Display Library for easy printing to LED Modules] []
🤐 PICKIT SERIAL I2C DEMO BOARD
Habe ich nicht, ich frage mich, wozu ich diese Chips kaufen sollte, kommt aber wohl in Abi-Aufgaben dran.. [PICKIT SERIAL I2C DEMO BOARD 🔗] [UsersGuide 🔗]
[EEPROM 24LC02B 🔗] [Temperatursensor MCP9800 🔗] [12-Bit A/D MCP3221 🔗] [10-Bit D/A TC1321 🔗] [🔥 8-Bit I/O Expander MCP23008 🔗]
🪦 SAA 1064 ernsthaft?
In Abi-Aufgaben fand ich den SAA 1064. Der Chip ist sowas von out, ich finde kein Datenblatt mehr bei nxp.com!
Ein Kommentar