I2C Protocol Application: Sensor Interface and Data Reading
I2C Protocol Application: Sensor Interface and Data Reading
Hello everyone, I am Daodao. Today, let’s talk about the I2C protocol, which many sensors use to communicate with microcontrollers. Although it only uses two wires, it can connect multiple devices, making it a master of saving wires. However, if not used correctly, it can easily get stuck on data reading. Today, I will explain it from a practical perspective.
What is I2C?
In simple terms, I2C is like a small alley where many “residents” (I2C devices) live. The alley has only two paths:
-
SCL: Equivalent to a traffic police officer’s gesture, controlling the communication rhythm.
-
SDA: The path for information transmission between devices.
Special Reminder: Both of these wires need pull-up resistors; otherwise, the signal will float. I have encountered many beginners who forget to add pull-ups to the signal line, leading to incorrect data readings, and it takes a long time to discover this issue.
Hardware Connection Details
VCC
|
[Pull-up Resistor]
|
MCU --- SCL ---- Sensor 1 ---- Sensor 2
|
[Pull-up Resistor]
|
MCU --- SDA ---- Sensor 1 ---- Sensor 2
Several easily overlooked wiring details:
-
Pull-up Resistor Value is generally chosen between 2.2K and 10K; too high causes slow signal rise, too low increases power consumption.
-
Connecting too many devices on the bus increases load capacitance, affecting communication speed.
-
Keep connection wires short; otherwise, they are prone to interference.
Code Implementation
// I2C Initialization Configuration
void I2C_Init(void)
{
// Configure GPIO as open-drain output mode
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Idle state, both pulled high
I2C_SCL_HIGH();
I2C_SDA_HIGH();
}
// Send Start Signal
void I2C_Start(void)
{
SDA_OUT(); // Set SDA as output
I2C_SDA_HIGH();
I2C_SCL_HIGH();
delay_us(4); // Suggested delay of more than 4us
I2C_SDA_LOW(); // When SCL is high, SDA falling edge = start signal
delay_us(4);
I2C_SCL_LOW(); // Hold I2C bus, prepare to send data
}
// Send Stop Signal
void I2C_Stop(void)
{
SDA_OUT();
I2C_SCL_LOW();
I2C_SDA_LOW();
delay_us(4);
I2C_SCL_HIGH();
I2C_SDA_HIGH(); // When SCL is high, SDA rising edge = stop signal
delay_us(4);
}
Practical Case: Reading Temperature and Humidity Sensor
Taking the SHT20 sensor as an example, its address is 0x40, and the data reading process is as follows:
uint8_t ReadTemperature(void)
{
uint8_t temp[2];
I2C_Start();
I2C_Send_Byte(0x40 << 1 | 0x00); // Write device address
I2C_Wait_Ack();
I2C_Send_Byte(0xF3); // Send command to measure temperature
I2C_Wait_Ack();
delay_ms(85); // Wait for measurement to complete
I2C_Start();
I2C_Send_Byte(0x40 << 1 | 0x01); // Read device address
I2C_Wait_Ack();
temp[0] = I2C_Read_Byte(1); // Read high byte
temp[1] = I2C_Read_Byte(0); // Read low byte
I2C_Stop();
return Calculate_Temperature(temp); // Convert to actual temperature value
}
Pitfalls and Solutions
-
Communication Failure
-
Symptoms: Always unable to read data or data is incorrect.
-
Solution: First, use an oscilloscope to check the waveforms of SCL and SDA; most issues can be seen in the waveforms.
-
Common Causes: Pull-up resistor not connected, timing incorrect, ground line not connected properly.
-
Data Occasionally Incorrect
-
Possible cause: Large power ripple; add a 100nF bypass capacitor.
-
During wiring, keep signal lines away from strong electricity and switching power supplies.
-
The Same Code Doesn’t Work with a Different Sensor
-
Each sensor may have different timing requirements.
-
Carefully check the timing diagrams in the manufacturer’s manual, especially setup time and hold time.
Recommended Debugging Tools
-
Oscilloscope: The most intuitive way to observe waveforms.
-
Logic Analyzer: Can analyze I2C protocol and directly see data content.
-
I2C Debugging Tool: Can simulate master or slave, convenient for testing a specific device.
Practical Suggestions
Hardware Aspects:
-
Reserve I2C interface on the PCB for easy expansion.
-
Use twisted pair for signal lines for better interference resistance.
-
Reserve pull-up resistor positions for easy testing with different values.
Software Aspects:
-
Write a simple I2C test program to verify hardware functionality.
-
Add a timeout mechanism to prevent the program from running away.
-
Add checksums for important data.
Safety Reminder: Be cautious with power supply voltage when debugging; do not connect the power supply incorrectly to avoid damaging components.
Practical Exercises:
-
Use an oscilloscope to observe the start and stop signal waveforms of I2C.
-
Try reading devices with different I2C addresses.
-
Test the impact of different pull-up resistors on communication.