Friday, March 27, 2015

Interfacing PIC Microcontroller With External EEPROM

Interfacing PIC16F877A with 24C08A EEPROM

The EEPROM is used in most of the electronic equipments like televisions, computers, digital clocks ....It is used to store data. 
The 24C eeprom series is one of the mostly used today, this type of memory uses the I2C protocol to communicate with the master device.
The 24C08A eeprom has 8 Kbit of memory (1KByte) its pin assignment as shown below:
24c08 eeprom pin out

A0, A1, A2: used for device addressing according to the following table:
24c08 circuit
For example in general when A0, A1, A2 connected to ground the device address becomes:
(for 24C08A A0 & A1 can be disconnected).
Write data to EEPROM:
Start I2C protocol,
Send EEPROM write mode address,
Send byte address,
Send data,
Stop the I2C protocol.
The 24C08A has 1024 bytes of memory organized as 4 blocks of 256 bytes. 
Assume A2 connected to ground, the addressing of our eeprom bcomes as shown on the following table:
24c08 write data

P1 and P0 are called the page address which used to to select one of the four pages of 24C08A EEPROM.
So, the complete process of writing byte is shown below:
eeprom write data

MikroC PRO For PIC code:
(0xA0 means that we are at page0)

 void write_data(char address, char data_){
  I2C1_Start();       // start I2C signal
  I2C1_Wr(0xA0);      // Send EEPROM and page address
  I2C1_Wr(address);   // Send byte address
  I2C1_Wr(data_);     // Write data
  I2C1_Stop();        // Stop I2C protocol
 }

Read data from EEPROM:
Start I2C protocol,
Send EEPROM write mode address,
Send byte address,
I2C repeated start,
Send EEPROM read mode address,
Read data from EEPROM,
Stop the I2C protocol.
eeprom read data

MikroC PRO For PIC code:

 void read_data(char address){
  I2C1_Start();     // start I2C signal
  I2C1_Wr(0xA0);   // Send EEPROM and page address at write mode
  I2C1_Wr(address);   // Send byte address
  I2C1_Repeated_Start();
  I2C1_Wr(0xA1);   // Send EEPROM and page address at read mode
  a = I2C1_Rd(0);
  I2C1_Stop();     // Stop I2C protocol
 }

Example:
Interfacing PIC16F877A with 24C08A EEPROM
Circuit schematic:

interface external eeprom 24c08 with pic16f877a mikroc


On this application I am going to write 4 different values at different addresses then read these values and display it on 1602 LCD display.
The values are: (decimal)
7 at address 10, 141 at address 320, 255 at address 680 and 224 at address 1010.
The LCD displays as shown on the previous picture.
Interfacing PIC16F877A with 24C08A EEPROM mikroC code:

// LCD module connections
 sbit LCD_RS at RB0_bit;
 sbit LCD_EN at RB1_bit;
 sbit LCD_D4 at RB2_bit;
 sbit LCD_D5 at RB3_bit;
 sbit LCD_D6 at RB4_bit;
 sbit LCD_D7 at RB5_bit;
 sbit LCD_RS_Direction at TRISB0_bit;
 sbit LCD_EN_Direction at TRISB1_bit;
 sbit LCD_D4_Direction at TRISB2_bit;
 sbit LCD_D5_Direction at TRISB3_bit;
 sbit LCD_D6_Direction at TRISB4_bit;
 sbit LCD_D7_Direction at TRISB5_bit;
 // End LCD module connections

 char a ;
 void write_data(unsigned address, char data_){
 char device_address;
 device_address = 0xA0;
 if(address > 767) {address -= 768;
 device_address = 0xA6;
 goto write;}
 if(address > 511) {address -= 512;
 device_address = 0xA4;
 goto write;}
 if(address > 255) {address -= 256;
 device_address = 0xA2;
 goto write;}
 write:
  I2C1_Start();
  I2C1_Wr(device_address);
  I2C1_Wr(address);
  I2C1_Wr(data_);
  I2C1_Stop();
  }
 void read_data(unsigned address){
 char device_address;
 device_address = 0xA0;
 if(address > 767) {address -= 768;
 device_address = 0xA6;
 goto read;}
 if(address > 511) {address -= 512;
 device_address = 0xA4;
 goto read;}
 if(address > 255) {address -= 256;
 device_address = 0xA2;
 goto read;}
 read:
 I2C1_Start();      // start I2C signal
 I2C1_Wr(device_address);
 I2C1_Wr(address);
 I2C1_Repeated_Start();
 I2C1_Wr(device_address + 1);
 a = I2C1_Rd(0);
 I2C1_Stop();
 }
void main(){
 Lcd_Init();
 Lcd_Cmd(_LCD_CURSOR_OFF);        // cursor off
 Lcd_Cmd(_LCD_CLEAR);             // clear LCD
 I2C1_Init(100000); // initialize I2C protocol at 100KHz
 delay_ms(20);
 write_data(10, 0x07);
 delay_ms(20);
 write_data(320, 0x8D);
 delay_ms(20);
 write_data(680, 0xFF); 
 delay_ms(20);
 write_data(1010, 0xE0);
 delay_ms(20);
 read_data(10);
 Lcd_Chr(1, 2, (a/100) + 48);
 Lcd_Chr(1, 3, ((a/10)%10) + 48);
 Lcd_Chr(1, 4, (a % 10) + 48);
 read_data(320);
 Lcd_Chr(1, 8, (a/100) + 48);
 Lcd_Chr(1, 9, ((a/10)%10) + 48);
 Lcd_Chr(1, 10, (a % 10) + 48);
 read_data(680);
 Lcd_Chr(2, 2, (a/100) + 48);
 Lcd_Chr(2, 3, ((a/10)%10) + 48);
 Lcd_Chr(2, 4, (a % 10) + 48);
 read_data(1010);
 Lcd_Chr(2, 8, (a/100) + 48);
 Lcd_Chr(2, 9, ((a/10)%10) + 48);
 Lcd_Chr(2, 10, (a % 10) + 48);

 while(1);  // Endless loop
}