ad space

Scanning I2C Devices with PIC16F877A

The I2C (Inter-Integrated Circuit) bus is a popular communication protocol used for connecting various peripherals to microcontrollers. One of the challenges when working with I2C devices is identifying their addresses. In this tutorial, we will explore how to create an I2C scanner using the PIC16F877A microcontroller to detect connected I2C devices and display their addresses on the serial monitor.

Hardware Requirements

To get started, you will need the following components:

  • PIC16F877A Microcontroller
  • I2C-compatible device (e.g., an I2C EEPROM or sensor)
  • Breadboard and jumper wires
  • MPLAB X IDE and XC8 Compiler
  • USB to serial converter (for serial communication)

Circuit Diagram

Here's a simple circuit diagram to connect the PIC16F877A to an I2C device:

circuit_diagram of I2C address scanner
 Make sure to connect the I2C device's SDA and SCL pins to the corresponding pins on the PIC16F877A (typically, RC4 for SDA and RC3 for SCL). Don’t forget to include pull-up resistors (4.7kΩ) on both the SDA and SCL lines.

Software Setup

  1. Open MPLAB X IDE and create a new project for the PIC16F877A.
  2. Set up the XC8 compiler for the project.
  3. Include the necessary libraries for I2C communication.

Here’s a simple I2C scanner code for the PIC16F877A:

#include <xc.h>
#include <stdio.h>
#include <stdint.h>

#define _XTAL_FREQ 20000000 // Define oscillator frequency (20MHz)

// I2C Master Mode Definitions
#define I2C_START 0x08
#define I2C_REPEATED_START 0x10
#define I2C_WRITE 0x18
#define I2C_READ 0x40
#define I2C_ACK 0
#define I2C_NACK 1

void I2C_Init(void) {
SSPCON = 0x28; // Configure MSSP module for I2C master mode
SSPADD = 49; // Set I2C clock frequency to 100kHz (FOSC = 20MHz)
SSPSTAT = 0; // Clear status register
}

void I2C_Start(void) {
SEN = 1; // Initiate start condition
while (SEN); // Wait for start condition to complete
}

void I2C_Stop(void) {
PEN = 1; // Initiate stop condition
while (PEN); // Wait for stop condition to complete
}

void I2C_Write(uint8_t data) {
SSPBUF = data; // Load data into SSPBUF
while (!BF); // Wait until buffer is full
while (SSPCON2 & 0x1F); // Wait until I2C bus is idle
}

uint8_t I2C_Read(uint8_t ack) {
RCEN = 1; // Enable receive mode
while (!BF); // Wait for data to be received
if (ack) {
ACKDT = 0; // Send ACK
} else {
ACKDT = 1; // Send NACK
}
ACKEN = 1; // Send ACK/NACK
return SSPBUF; // Return received data
}

void I2C_Scan(void) {
uint8_t address;
printf("I2C Scanner\n");
for (address = 0; address < 128; address++) {
I2C_Start();
I2C_Write(address << 1); // Write address with R/W bit as 0
if (SSPSTAT & 0x18) { // Check for ACK
printf("Device found at address: 0x%02X\n", address);
}
I2C_Stop();
}
}

void main(void) {
I2C_Init();
// Configure USART for serial communication
// (Assuming USART is set up elsewhere in the code)

while (1) {
I2C_Scan(); // Call the I2C scanning function
__delay_ms(1000); // Delay for 1 second before scanning again
}
}


Explanation of the Code

  • I2C Initialization: The I2C_Init function sets up the PIC16F877A for I2C master mode, configuring the clock frequency.

  • I2C Start and Stop Conditions: The I2C_Start and I2C_Stop functions handle starting and stopping the I2C communication.

  • I2C Write and Read Functions: These functions manage data transmission over the I2C bus.

  • I2C Scan Function: The I2C_Scan function iterates through possible I2C addresses (0x00 to 0x7F), attempting to communicate with each device. If an acknowledgment (ACK) is received, it prints the address of the detected device.

Conclusion

With this simple I2C scanner using the PIC16F877A, you can easily detect I2C devices connected to your microcontroller. This is a great starting point for integrating various I2C peripherals into your projects. Be sure to check the documentation for your specific I2C devices to understand their addresses and how to communicate with them.

Further Reading:

Post a Comment

Previous Post Next Post