Elektronik-Labor
Projekte
Mikrocontroller
Raspberry
---
// Scan des I2C-Bus auf den DEFAULT-PIN 4 + 5
//
// Dieses Beispiel verwendet die Pico-Arduino Boarderweiterung von Earle Philhower (Version 2.6.3)
// nach Anregung des Buches "RPi Pico Schaltungen und Projekte" von Burkhard Kainka, Seite 5
// Einbindung über die Boardverwalter-URL https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
// unter "Datei | Voreinstellungen" in der Arduino-IDE
//
// Anregung von https://hutscape.com/tutorials/pico-i2c
// Teile der Dokumenation von https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__i2c.html
// und https://github.com/raspberrypi/pico-examples/blob/master/i2c/bus_scan/bus_scan.c
// Umgestellt auf setup/loop und Seriellen Monitor statt UART Schnittstelle
//
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
char Textausgabe[4]; // da sprintf einen Null-Wert anhängt, muss dieses Feld länger sein als die benötigte Textausgabe
bool reserved_addr(uint8_t addr) {
return (addr & 0x78) == 0 || (addr & 0x78) == 0x78; // Adressen der Form "000 0xxx" oder "111 1xxx" sind im I2C-Protokoll für Spezielle Zwecke vorgesehen
}
void setup() {
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning Keine DEFAULT_PIN für I2C definiert
#else
// Hier wird I2C0 mit den DEFAULT SDA und SCL pins (4, 5) verwendet
i2c_init(i2c_default, 100000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
//stdio_init_all(); // Das wäre für UART
Serial.begin(115200);
}
void loop() {
Serial.println("5 Sekunden warten bis Anwender den Seriellen Monitor geöffnet hat.");
sleep_ms(5000);
//printf("\nI2C Bus Scan mit Default-PIN 4 und 5:\n");
//printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
Serial.println("I2C Bus Scan mit Default-PIN 4 und 5:");
Serial.println(" 0 1 2 3 4 5 6 7 8 9 A B C D E F");
for (int addr = 0; addr < (1 << 7); ++addr) {
if (addr % 16 == 0) {
// printf("%02x ", addr); // printf waren aus der Beispieldatei für UART
sprintf(Textausgabe, "%02x ", addr); // sprintf hat dieselben Parameter wie printf, plus das Textfeld in das reinkopiert wird
Serial.print(Textausgabe);
}
// Es wird versucht, 1 Byte zu lesen,
// wenn die Adresse exisitiert, wird die Anzahl von übertragenen Bytes zurückgegeben.
// wenn die Adresse nicht existiert, wird -1 zurückgegeben
int ret;
uint8_t rxdata;
if (reserved_addr(addr))
Serial.print("r ");
else {
ret = i2c_read_blocking(i2c_default, addr, &rxdata, 1, false);
Serial.print(ret < 0 ? ". " : "X ");
}
if (addr % 16 == 15) Serial.println("|");
}
}
#endif
/* So sieht die Ausgabe im Seriellen Monitor aus
I2C Bus Scan mit Default-PIN 4 und 5:
0 1 2 3 4 5 6 7 8 9 A B C D E F
00 r r r r r r r r . . . . . . . . |
10 . . . . . . . . . . . . . . . . |
20 . . . . . . . X . . . . . . . . |
30 . . . . . . . . . . . . . . . . |
40 . . . . . . . . . . . . . . . . |
50 . . . . . . . . . . . . . . . . |
60 . . . . . . . . . . . . . . . . |
70 . . . . . . . . r r r r r r r r |
5 Sekunden warten bis Anwender den Seriellen Monitor geöffnet hat.
Einzelne Adressen findet man auf: https://i2cdevices.org/addresses
*/
---------------
Beliebige I2C-PINs:---
// Scan des I2C-Bus auf anderen als den DEFAULT-PIN 4 + 5
//
// Dieses Beispiel verwendet die Pico-Arduino Boarderweiterung von Earle Philhower (Version 2.6.3)
// nach Anregung des Buches "RPi Pico Schaltungen und Projekte" von Burkhard Kainka, Seite 5
// Einbindung über die Boardverwalter-URL https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
// unter "Datei | Voreinstellungen" in der Arduino-IDE
//
// Anregung von https://hutscape.com/tutorials/pico-i2c
// Teile der Dokumenation von https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__i2c.html
// und https://github.com/raspberrypi/pico-examples/blob/master/i2c/bus_scan/bus_scan.c
// Umgestellt auf setup/loop und Seriellen Monitor statt UART Schnittstelle
//
// Viele Erklärungen zu I2C in
// /home/username/.arduino15/packages/rp2040/hardware/rp2040/2.6.3/pico-sdk/src/rp2_common/hardware_i2c/include/hardware/i2c.h
// ==> hier sind i2c0 und i2c_default definiert
// dort wird auch eingebunden
// /home/username/.arduino15/packages/rp2040/hardware/rp2040/2.6.3/pico-sdk/src/boards/include/boards/pico.h
// ==> Da ist die Definition von
//#define PICO_DEFAULT_I2C 0
//#define PICO_DEFAULT_I2C_SDA_PIN 4
//#define PICO_DEFAULT_I2C_SCL_PIN 5
//
// In der Datei
// /home/username/.arduino15/packages/rp2040/hardware/rp2040/2.6.3/pico-sdk/src/common/pico_stdlib/include/pico/stdlib.h
// wird eingebunden
// /home/username/.arduino15/packages/rp2040/hardware/rp2040/2.6.3/pico-sdk/src/rp2_common/hardware_gpio/include/hardware/gpio.h
// ==> da sind die Pinout in Tabellenform, die erklären welche PIN für i2c0 und welche für i2c1 verwendet werden können
//
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
// Damit das zusammen passt, hier hintereinander die Definitionen
#define I2C_HW i2c1 // Alternativ i2c0 oder i2c1
#define PIN_SDA 2 // mit i2c0 geht: 0, 4, 8, 12, 16, 20, 24, 28
// i2c1 geht: 2, 6, 10, 14, 18, 22, 26
#define PIN_SCL 3 // SCL-pin immer eine Nummer höher als SDA, also 1, 3, 5,...
char Textausgabe[4]; // da sprintf einen Null-Wert anhängt, muss dieses Feld länger sein als die benötigte Textausgabe
bool reserved_addr(uint8_t addr) {
return (addr & 0x78) == 0 || (addr & 0x78) == 0x78; // Adressen der Form "000 0xxx" oder "111 1xxx" sind im I2C-Protokoll für Spezielle Zwecke vorgesehen
}
void setup() {
i2c_init(I2C_HW , 100000);
gpio_set_function(PIN_SDA, GPIO_FUNC_I2C);
gpio_set_function(PIN_SCL, GPIO_FUNC_I2C);
gpio_pull_up(PIN_SDA);
gpio_pull_up(PIN_SCL);
//stdio_init_all(); // Das wäre für UART
Serial.begin(115200);
}
void loop() {
Serial.println("5 Sekunden warten bis Anwender den Seriellen Monitor geöffnet hat.");
sleep_ms(5000);
Serial.print("I2C Bus Scan mit PIN SDA=");
Serial.print(PIN_SDA);
Serial.print(" und SCL=");
Serial.print(PIN_SCL);
Serial.print(" auf I2C-Hardware ");
Serial.println(i2c_hw_index(I2C_HW)); // Verwandelt i2c0 in "0" bzw. i2c1 in "1"
Serial.println(" 0 1 2 3 4 5 6 7 8 9 A B C D E F");
for (int addr = 0; addr < (1 << 7); ++addr) {
if (addr % 16 == 0) {
// printf("%02x ", addr); // printf waren aus der Beispieldatei für UART
sprintf(Textausgabe, "%02x ", addr); // sprintf hat dieselben Parameter wie printf, plus das Textfeld in das reinkopiert wird
Serial.print(Textausgabe);
}
int ret;
uint8_t rxdata;
if (reserved_addr(addr))
Serial.print("r ");
else { // Es wird versucht, 1 Byte zu lesen,
ret = i2c_read_blocking(I2C_HW, addr, &rxdata, 1, false); // wenn die Adresse exisitiert, wird die Anzahl von übertragenen Bytes zurückgegeben.
Serial.print(ret < 0 ? ". " : "X "); // wenn die Adresse nicht existiert, wird -1 zurückgegeben
}
if (addr % 16 == 15) Serial.println("|");
}
}
/* So sieht die Ausgabe im Seriellen Monitor aus
I2C Bus Scan mit PIN SDA=2 und SCL=3 auf I2C-Hardware 1
0 1 2 3 4 5 6 7 8 9 A B C D E F
00 r r r r r r r r . . . . . . . . |
10 . . . . . . . . . . . . . . . . |
20 . . . . . . . X . . . . . . . . |
30 . . . . . . . . . . . . . . . . |
40 . . . . . . . . . . . . . . . . |
50 . . . . . . . . . . . . . . . . |
60 . . . . . . . . . . . . . . . . |
70 . . . . . . . . r r r r r r r r |
5 Sekunden warten bis Anwender den Seriellen Monitor geöffnet hat.
Einzelne Adressen findet man auf: https://i2cdevices.org/addresses
Falsche Kombi von PIN und i2c0 bzw. i2c1 führen zu
I2C Bus Scan mit PIN SDA=2 und SCL=3 auf I2C-Hardware 0
0 1 2 3 4 5 6 7 8 9 A B C D E F
00 r r r r r r r r
==> Schon der erste Versuch eine Adresse zu lesen führt zum Absturz
*/
---------------
Alle I2C-PINs:---
// Scan des I2C-Bus auf dynamisch wechselnden GPIO --> über alle möglichen GPIO
//
// Dieses Beispiel verwendet die Pico-Arduino Boarderweiterung von Earle Philhower (Version 2.6.3)
// nach Anregung des Buches "RPi Pico Schaltungen und Projekte" von Burkhard Kainka, Seite 5
// Einbindung über die Boardverwalter-URL https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
// unter "Datei | Voreinstellungen" in der Arduino-IDE
//
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
char Textausgabe[4]; // da sprintf einen Null-Wert anhängt, muss dieses Feld länger sein als die benötigte Textausgabe
bool reserved_addr(uint8_t addr) {
return (addr & 0x78) == 0 || (addr & 0x78) == 0x78; // Adressen der Form "000 0xxx" oder "111 1xxx" sind im I2C-Protokoll für Spezielle Zwecke vorgesehen
}
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("5 Sekunden warten bis Anwender den Seriellen Monitor geöffnet hat.");
sleep_ms(5000);
scan_hw(i2c0); // Alternativ i2c0 oder i2c1
Serial.println("||");
scan_hw(i2c1); // Alternativ i2c0 oder i2c1
Serial.println("||");
}
void scan_hw(i2c_inst_t* hardware) {
int PIN_SDA = i2c_hw_index(hardware) *2; // Bei i2c0 wird daraus PIN=0, bei i2c1 wird daraus PIN=2
// mit i2c0 geht: 0, 4, 8, 12, 16, 20, 24, 28
// i2c1 geht: 2, 6, 10, 14, 18, 22, 26
Serial.print("i2c");
Serial.print(i2c_hw_index(hardware)); // Verwandelt i2c0 in "0" bzw. i2c1 in "1"
Serial.print(":");
while (PIN_SDA < 29) { // i2c0: 0 ... 28; i2c1: 2 .. 26
Serial.print(" PIN ");
Serial.print(PIN_SDA);
Serial.print("/");
Serial.print(PIN_SDA +1 ); // SCL ist immer ein Pin höher als SDA
scan(hardware, PIN_SDA);
PIN_SDA += 4; // i2c0: 0, 4, 8, ... 28; i2c1: 2, 6, 10, ... 26;
}
}
void scan(i2c_inst_t* hardware, int sda) {
i2c_init(hardware , 100000);
gpio_set_function(sda, GPIO_FUNC_I2C);
gpio_set_function(sda +1, GPIO_FUNC_I2C);
gpio_pull_up(sda);
gpio_pull_up(sda +1);
Serial.print(": "); // Wenn das ausgegeben wird ist init erfolgreich
for (int addr = 0; addr < (1 << 7); ++addr) {
int ret;
uint8_t rxdata;
if (!reserved_addr(addr)) { // Reservierte Adressen werden nicht gelesen
ret = i2c_read_blocking(hardware, addr, &rxdata, 1, false); // Es wird versucht, 1 Byte zu lesen,
if (ret >= 0) { // wenn die Adresse exisitiert, wird die Anzahl von übertragenen Bytes zurückgegeben.
// wenn die Adresse nicht existiert, wird -1 zurückgegeben
sprintf(Textausgabe, "%02x ", addr); // Ausgabe Hexadezimal
Serial.print(Textausgabe); //
}
}
if (addr % 32 == 15) Serial.print("."); // Als "progress-bar"
}
Serial.print("|"); // wird vor deinit ausgegeben
i2c_deinit(hardware);
gpio_set_function(sda, GPIO_FUNC_NULL);
gpio_set_function(sda +1, GPIO_FUNC_NULL);
}
/* So sieht die Ausgabe im Seriellen Monitor aus, wenn erst 20/21 und dann 0/1 angeschlossen wird
i2c0: PIN 0/1: ....| PIN 4/5: ....| PIN 8/9: ....| PIN 12/13: ....| PIN 16/17: ....| PIN 20/21: .27 ...| PIN 24/25: ....| PIN 28/29: ....|||
i2c1: PIN 2/3: ....| PIN 6/7: ....| PIN 10/11: ....| PIN 14/15: ....| PIN 18/19: ....| PIN 22/23: ....| PIN 26/27: ....|||
5 Sekunden warten bis Anwender den Seriellen Monitor geöffnet hat.
i2c0: PIN 0/1: .27 ...| PIN 4/5: ....| PIN 8/9: ....| PIN 12/13: ....| PIN 16/17: ....| PIN 20/21: ....| PIN 24/25: ....| PIN 28/29: ....|||
i2c1: PIN 2/3: ....| PIN 6/7: ....| PIN 10/11: ....| PIN 14/15: ....| PIN 18/19: ....| PIN 22/23: ....| PIN 26/27: ....|||
5 Sekunden warten bis Anwender den Seriellen Monitor geöffnet hat.
Einzelne Adressen findet man auf: https://i2cdevices.org/addresses
*/
---------------