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)