Introduction
Inter-Integrated Circuit (I2C) is a vital communication protocol widely used in embedded systems for interfacing microcontrollers with various sensors and peripheral devices. In this blog post, we will explore the implementation of I2C communication using the PIC16F877 microcontroller. Our focus will be on connecting a temperature and humidity sensor, providing a practical guide from circuit setup to code implementation.
Design
The PIC16F877 features a built-in MSSP (Master Synchronous Serial Port) module that supports I2C in both Master and Slave modes. For our project, the PIC16F877 will operate in Master mode.
Circuit Setup
- Microcontroller: PIC16F877.
- Sensor: Generic I2C-compatible temperature and humidity sensor.
- Pull-up Resistors: 4.7kΩ on both SDA and SCL lines.
- Connections: SDA (Serial Data Line) and SCL (Serial Clock Line) connected to corresponding pins on the PIC.
Circuit schematic:
[ PIC16F877 ]---[ SDA ]---[ Sensor ]
|
[4.7kΩ]
|
[Vcc]
[ PIC16F877 ]---[ SCL ]---[ Sensor ]
|
[4.7kΩ]
|
[Vcc]
Implementation
We will program the PIC16F877 using MPLAB X IDE and the XC8 compiler. The following code initializes the I2C module and reads data from the sensor.
#include <xc.h>
#define _XTAL_FREQ 20000000 // 20 MHz Crystal
// I2C Master initialization
void I2C_Master_Init(const unsigned long c) {
SSPCON = 0b00101000; // SSP Module as Master
SSPCON2 = 0x00;
SSPADD = (_XTAL_FREQ / (4 * c)) - 1; // Setting Clock Speed
SSPSTAT = 0x00;
TRISC3 = 1; // Setting SCL and SDA as input
TRISC4 = 1;
}
// I2C Wait Ready
void I2C_Wait() {
while ((SSPCON2 & 0x1F) || (SSPSTAT & 0x04)); // Wait for idle and ready status
}
// I2C Start
void I2C_Start() {
I2C_Wait();
SEN = 1; // Initiate start condition
}
// I2C Read
unsigned char I2C_Read(unsigned char ack) {
unsigned char received;
I2C_Wait();
RCEN = 1;
I2C_Wait();
received = SSPBUF; // Receive data
I2C_Wait();
ACKDT = (ack) ? 0 : 1; // Acknowledge bit
ACKEN = 1; // Acknowledge sequence
return received;
}
// Main Function
void main() {
I2C_Master_Init(100000); // Initialize I2C Master with 100kHz clock
I2C_Start(); // Start I2C communication
// Device address and read temperature
I2C_Write(0x90); // Device address
unsigned char temperature = I2C_Read(0); // Read temperature
I2C_Stop(); // Stop I2C communication
while (1) {
// Application logic
}
}
Debugging
During implementation, you might encounter common issues such as no acknowledgment received from the sensor or incorrect readings. To debug:
- Check Connections: Ensure all hardware connections are secure.
- Logic Analyzer: Use a logic analyzer to trace the SDA and SCL lines for proper signaling.
- Pull-up Resistors: Verify the values; sometimes different environmental conditions require adjustment of resistor values.
Results and Conclusion
Upon successful implementation, the PIC16F877 reads temperature and humidity data transmitted by the sensor over I2C. This setup demonstrates the effectiveness of PIC microcontrollers in managing communication with peripheral devices, making it suitable for a wide range of applications in embedded systems.
In this tutorial, we’ve walked through setting up an I2C communication on a PIC16F877, from circuit design to programming and debugging. This example acts as a foundation for integrating more complex devices and sensors, pushing the boundaries of what can be achieved with microcontrollers in embedded systems.