The I2C bus is one of the most commonly used communication protocols in embedded systems, serving as a “dedicated highway” between microcontrollers and various sensors and memory devices. Today, let’s discuss how this protocol works and how to use it to read data from temperature and humidity sensors.
I2C Protocol Basics
The I2C protocol uses two wires: SDA (data line) and SCL (clock line). You can think of it as a two-way road where SDA is used for data transmission and SCL controls the traffic lights.
Main features:
-
Master-slave communication: one master device (usually a microcontroller) and multiple slave devices (sensors, etc.) -
Addressing: each slave device has a unique address -
Bidirectional transmission: data can be read and written -
Clock synchronization: all devices follow the rhythm of SCL
Hardware Connection
This is a typical I2C connection diagram:
VCC
|
|
---|---
| | |
| R R (Pull-up resistors, usually 4.7k)
| | |
| | |
SCL--|--|-- SCL (each device)
SDA--|--|-- SDA (each device)
| |
Master Device Slave Device 1, Slave Device 2...
Note: The I2C bus requires pull-up resistors! The first time I connected an I2C device, I forgot this detail, and as a result, communication failed. After struggling for a long time, I discovered this was the reason.
Software Implementation
Taking STM32 as an example, here is a simple program to read data from the SHT20 temperature and humidity sensor:
#include "stm32f10x.h"
#include "i2c.h"
#define SHT20_ADDR 0x40 // I2C address of SHT20
#define TEMP_CMD 0xF3 // Command to measure temperature
#define HUMI_CMD 0xF5 // Command to measure humidity
float readTemperature(void) {
uint8_t data[2];
uint16_t temp;
float temperature;
I2C_Start();
I2C_Send7bitAddress(SHT20_ADDR, I2C_Direction_Transmitter);
I2C_SendData(TEMP_CMD);
I2C_Stop();
delay_ms(100); // Wait for measurement to complete
I2C_Start();
I2C_Send7bitAddress(SHT20_ADDR, I2C_Direction_Receiver);
data[0] = I2C_ReceiveData(1); // Receive high 8 bits
data[1] = I2C_ReceiveData(0); // Receive low 8 bits
I2C_Stop();
temp = (data[0] << 8) | data[1];
temperature = -46.85 + 175.72 * (temp / 65536.0);
return temperature;
}
This code does the following:
-
Sends the command to measure temperature -
Waits for the sensor to complete the measurement -
Reads the measurement result -
Converts the raw data into the actual temperature value
Practical Application Case
In a smart home project, I used the SHT20 sensor to monitor indoor temperature and humidity, and controlled the air conditioning and humidifier based on the data. The code is roughly as follows:
void smartHomeControl(void) {
float temp = readTemperature();
float humi = readHumidity();
if(temp > 28.0) {
turnOnAC();
} else if(temp < 22.0) {
turnOffAC();
}
if(humi < 40.0) {
turnOnHumidifier();
} else if(humi > 60.0) {
turnOffHumidifier();
}
// Check every 5 minutes
delay_ms(300000);
}
Common Issues and Solutions
-
Communication Failure
-
Check the wiring, especially the pull-up resistors -
Confirm the slave device address is correct -
Observe SCL and SDA signals with an oscilloscope
Abnormal Data
-
Check if the conversion formula is correct -
Consider environmental factors, such as whether the sensor is affected by heat sources
Unstable Communication
-
It could be power noise; add a decoupling capacitor -
Is the line too long? I2C is not suitable for long-distance transmission; consider using RS-485
Once in a project, the sensor readings fluctuated wildly, and after much troubleshooting, I found it was installed near the air conditioning outlet. This reminds us that in practical applications, we must pay attention not only to the code and circuitry but also to the sensor’s installation position.
Practical Recommendations
Start by reading a single sensor, then try reading multiple I2C devices simultaneously. You can set up a simple weather station to monitor temperature, humidity, and pressure parameters. In practice, pay special attention to the timing requirements of I2C; using a logic analyzer to observe the communication process can be very helpful in understanding the protocol.
While I2C is simple, it also has its limitations. In high-speed, long-distance, or complex environments, you may need to consider alternative communication methods.