Reading data from I2C or SPI sensors with microcontrollers (like Arduino, STM32, or ESP32) involves understanding the protocol, wiring, and communication steps. Below is a concise guide for both interfaces.
1. Reading from I2C Sensors
I2C Basics
- 2-wire interface (SDA = data, SCL = clock).
- 7-bit addressing (common sensors: 0x68 for MPU6050, 0x27 for LCD, etc.).
- Master-slave communication (microcontroller = master, sensor = slave).
Steps to Read Data
(1) Wiring
(Add pull-up resistors (4.7kΩ) if not built into the sensor.)
(2) Scan for I2C Address (Optional)
cpp #include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); Serial.println("Scanning I2C devices..."); for (byte addr = 0; 0x00 < 0x80; addr++) { Wire.beginTransmission(addr); if (Wire.endTransmission() == 0) { Serial.print("Found device at: 0x"); Serial.println(addr, HEX); } } } void loop() {}
(3) Read Data (Example: BMP280)
cpp #include <Wire.h> #define BMP280_ADDR 0x76 // Check datasheet void setup() { Wire.begin(); Serial.begin(9600); // Configure sensor (refer to datasheet) Wire.beginTransmission(BMP280_ADDR); Wire.write(0xF4); // Control register Wire.write(0x27); // Normal mode, 1x temp/pressure oversampling Wire.endTransmission(); } void loop() { // Read temperature (2 bytes) Wire.beginTransmission(BMP280_ADDR); Wire.write(0xFA); // Temp MSB register Wire.endTransmission(); Wire.requestFrom(BMP280_ADDR, 2); // Request 2 bytes int16_t temp = (Wire.read() << 8) | Wire.read(); float real_temp = temp / 100.0; // BMP280 scaling Serial.print("Temperature: "); Serial.println(real_temp); delay(1000); }
2. Reading from SPI Sensors
SPI Basics
4-wire interface:
- SCK = Clock (from master)
- MOSI = Master Out Slave In (data to sensor)
- MISO = Master In Slave Out (data from sensor)
- SS/CS = Slave Select (chip enable, active LOW)
Full-duplex (simultaneous send/receive).
Faster than I2C (MHz speeds possible).
Steps to Read Data
(1) Wiring
(Some sensors use SDI/SDO instead of MOSI/MISO.)
(2) Read Data (Example: BME280)
cpp #include <SPI.h> #define BME_CS 10 // Chip Select pin void setup() { SPI.begin(); pinMode(BME_CS, OUTPUT); Serial.begin(9600); } void loop() { // Read temperature (SPI) digitalWrite(BME_CS, LOW); // Activate sensor SPI.transfer(0xFA); // Send register address uint8_t msb = SPI.transfer(0x00); // Dummy write to read uint8_t lsb = SPI.transfer(0x00); digitalWrite(BME_CS, HIGH); // Deactivate sensor int16_t temp = (msb << 8) | lsb; float real_temp = temp / 100.0; Serial.print("Temperature: "); Serial.println(real_temp); delay(1000); }
Key Differences & Tips
- Missing pull-up resistors → communication fails.
- Address conflicts (check datasheet).
✔ SPI:
- Forgetting to toggle CS → no response.
- Clock polarity/phase mismatch (use SPI_MODE0, SPI_MODE3 as per sensor).
Libraries for Easier Use
- I2C: Wire.h (Arduino), HAL_I2C (STM32).
- SPI: SPI.h (Arduino), HAL_SPI (STM32).
-
Sensor-Specific:
- Adafruit_Sensor (BME280, MPU6050).
- SparkFun_ADS1015 (ADC over I2C).
Final Advice
- Check the datasheet for register maps and protocols.
- Start with known libraries before writing raw I2C/SPI.
- Use logic analyzers (Saleae, PulseView) if communication fails.
Both protocols are powerful—I2C for simplicity, SPI for speed!
Top comments (0)