[51] i2c : PCF8575 interface with P89C51RD2HBA

Status
Not open for further replies.

chiart

Newbie level 5
Joined
Jul 26, 2011
Messages
9
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Visit site
Activity points
1,362
Hi All,

I tried to use IO expansion chip that can controls up to 16 output by just using 2 wires (SDA and SCL). I'm using PCF8575 and interface with 8051 microcontroller (P89C51RD2HBA). I've connected 16 LED at the output side to see the result for the testing purpose. However, I'm stuck in the writing to the slave process, where i need to send 3 bytes of data to the slave.

Based on my findings :

1. We need to send 3 bytes of data : First is to determine slave address. In this case (0x40) as slave address based on PCF8575 datasheets.
2. Second byte is the data P0-P7 . (0xAA)
3. Third byte is the data P10-P17 . (0xF0)
4. The LED should turn ON at P0-P7 (10101010) and at P10-P17 (11110000)

But, the LED did not turn ON at all. The voltage at the output pin was around (1.1-1.3) which were not sufficient to turn on the LED.

Below, i attached the sourcecode, and appreciate any help to see which part i go wrong.

Code:
#include <REG51F.H>
#include <stdio.h>
#include <INPUT_OUTPUT.h>
#include <delay1.h>

// Function declarations
void initRS(); 												
void initPort();											
void I2C_Init();
void I2C_Start();
void I2C_Restart();
void I2C_Stop();
void I2C_SendAck();
void I2C_SendNack();
unsigned char I2C_Write(unsigned char Data);
unsigned char I2C_Read();


#define SDA p1_0
#define SCL p1_1

//Main function
void main()
{
	initRS();
	initPort();
	I2C_Init();
	
	//unsigned char RxByte = 0;

	I2C_Start();
	I2C_Write(0x40);
	I2C_Write(0xAA);
	I2C_Write(0xF0);
	I2C_Read();
	I2C_SendAck();
	I2C_Stop();

}


//Function : I2C Write Byte	transfer 3 bytes

unsigned char I2C_Write(unsigned char Data)
	{
	unsigned char i;		// Variable to be used in for loop
	
	for(i=0;i<8;i++)		// Repeat for every bit
	{
		SCL = 0;		// Make SCL pin low
		delay1();		  // Data pin should change it's value,
									// when it is confirm that SCL is low

		if ((Data & 0x40) == 0)			  //
			SDA = 1;
		else
			SDA = 0;
			delay1();
		SCL = 1;
		Data<<=1;
	 }

	//Get ACK from slave
	 SCL = 0;
	 SDA = 1;
	 delay1();
	 SCL = 1;
	 SCL = 0;
	 return SDA;

	//

	for(i=0;i<8;i++)		// Repeat for every bit
	{
		SCL = 0;		// Make SCL pin low
		delay1();		  // Data pin should change it's value,
									// when it is confirm that SCL is low

		if ((Data & 0xAA) == 0)			  //10101010
			SDA = 1;
		else
			SDA = 0;
			delay1();
		SCL = 1;
		Data<<=1;
	 }

	//Get ACK from slave
	 SCL = 0;
	 SDA = 1;
	 delay1();
	 SCL = 1;
	 SCL = 0;
	 return SDA;

	 //

	 for(i=0;i<8;i++)		// Repeat for every bit
	{
		SCL = 0;		// Make SCL pin low
		delay1();		  // Data pin should change it's value,
									// when it is confirm that SCL is low

		if ((Data & 0xF0) == 0)			  //11110000
			SDA = 1;
		else
			SDA = 0;
			delay1();
		SCL = 1;
		Data<<=1;
	 }

	//Get ACK from slave
	 SCL = 0;
	 SDA = 1;
	 delay1();
	 SCL = 1;
	 SCL = 0;
	 return SDA	;
	}  
		
		

//	Function : I2C Read Byte
	unsigned char I2C_Read()
	{
	unsigned char i, Data=0;
	for(i=0;i<8;i++){
		SCL = 0;
		SCL = 1;
		delay1();
		if(SDA)
			Data |=1;
		if(i<7)
			Data<<=1;
	}
	SCL = 0;
	SDA = 1;
	return Data;
	}
		


// Function : To set initial values of SDA and SCL
void I2C_Init()
{
	SDA = 1;				// Set SDA pin HIGH
	SCL = 1;			    // Set SCL pin LOW
}

// Function : Master sending START condition, HIGH to LOW transition on SDA while SCL keeping high
void I2C_Start()
{
	SCL = 1;
	SDA = 1;
	delay1();
	SDA = 0;
	SCL =1;
	delay1();
}

void I2C_Restart()
{
	SDA = 1;
	SCL = 1;
	SDA = 0;
}

void I2C_Stop()
{
	SDA = 0;
	SCL = 1;
	SDA = 1;
}

void I2C_Ack()
{
	SDA = 0;
	SCL = 1;
	SCL = 0;
}

void I2C_Nack()
{
	SDA = 1;
	SCL = 1;
	SCL = 0;
}

// Initialize serial port 
void initRS ()
{
    SCON  = 0x50;		        // SCON: mode 1, 8-bit UART, enable rcvr      
    TMOD  = 0x20;               // TMOD: timer 1, mode 2, 8-bit reload        
    TH1   = 253;                // TH1:  reload value for 9600 baud @ 11.0592MHz   FDH
    TR1   = 1;                  // TR1:  timer 1 run                          
    TI    = 1;                 	// TI:   set TI to send first char of UART    
}

//Initialize port
void initPort()
{
	P1 = 0xFF;                 
	P2 = 0x00;
	P0 = 0x00;
}



Any help highly appreciated.
Thank you.
 
Last edited by a moderator:

Address of the PCF8575 can have eight values depending upon A0, A1, A2. 0x40 is invalid address. Connect A0, A1, A2 to ground and the address of the device will be 0x00. Send 0x00 as the address.


Edit: I checked the datasheet. 0x40 is right for address when A0, A1, A2 are 0's.
 
Last edited:

Hi Jayanth,

Thank you for your feedback.
0x40 is the slave address when A0,A1 and A2 connected to ground.
But I may do wrong in coding in sending the 3 bytes of address and data?

Thanks
 

I tested the project by writing code for PIC micro and tested in Proteus. Only the first time it is sending the right data and it is getting all the ACKs and the last NACK but from second transmission it is sending wrong data. Actually I am shifting data 1 bit every time but the shifting is not working. I don't know why. Post your 89C51RD2 version .hex file compiled for 11.0592 MHz. I will test in Proteus.
 

Hi Jayanth,

I edited the code a bit and below is the code and hex file.

Thanks.

Regards,

Code:
#include <REG51F.H>
#include <stdio.h>
#include <INPUT_OUTPUT.h>
#include <delay1.h>

// Function declarations
void initRS(); 												
void initPort();											
void I2C_Init();
void I2C_Start();
void I2C_Restart();
void I2C_Stop();
void I2C_SendAck();
void I2C_SendNack();
bit I2C_Write(unsigned char Data);
unsigned char I2C_Read();
unsigned char I2C_GetAck();

#define SDA p1_0
#define SCL p1_1

//Main function
void main()
{
	initRS();
	initPort();
	I2C_Init();
	
	//unsigned char RxByte = 0;

	I2C_Start();
	I2C_Write(0x40);
	I2C_Write(0xAA);
	I2C_Write(0xF0);
	//I2C_Read();
	//I2C_SendAck();
	I2C_Stop();

	while(1)
	{
	}

}


//Function : I2C Write Byte	transfer 1 bytes

bit I2C_Write(unsigned char Data)
	{
	unsigned char i;		// Variable to be used in for loop
	
	for(i=0;i<8;i++)		// Repeat for every bit
	{
		SCL = 0;			// Make SCL pin low
		delay1();		    // Data pin should change it's value,
									      // when it is confirm that SCL is low

		if ((Data & 0x80) == 0)			  // Decimal = 128 
			SDA = 0;
		else
			SDA = 1;
			delay1();
		SCL = 1;
		Data<<=1;
		delay1();
		SCL = 0;			// All routines must exit with clock LOW or bus clear
	}
	
// Get ACK from slave

     //unsigned char i;	    // Variables to be used in for loop
	 SCL = 0;
	 delay1();
	 SDA = 1;
	 delay1();
	 SCL = 1;
	 delay1();
	 SCL = 0;
	 return SDA;
	}
	
		
		

/*//	Function : I2C Read Byte
	unsigned char I2C_Read()
	{
	unsigned char i, Data=0;
	for(i=0;i<8;i++)
	{
		SCL = 0;
		SCL = 1;
		delay1();  */
		/*if(SDA)
			Data |=1;
		if(i<7)
			Data<<=1;*/

		/*Data<<=1;
		if(SDA) data|=1;
	}
	SCL = 0;
	SDA = 1;
	return Data;
	}  */
		


// Function : To set initial values of SDA and SCL
void I2C_Init()
{
	SDA = 1;				// Set SDA pin HIGH
	SCL = 1;			    // Set SCL pin LOW
}

// Function : Master sending START condition, HIGH to LOW transition on SDA while SCL keeping high
void I2C_Start()
{
	SCL = 1;
	SDA = 1;
	delay1();
	SDA = 0;
	delay1();
	SCL =0;
	delay1();
}

void I2C_Restart()
{
	SDA = 1;
	delay1();
	SCL = 1;
	delay1();
	SDA = 0;
	delay1();
	SDA = 0; 		//Always exit with clock LOW
	delay1();
}

void I2C_Stop()
{
	SDA = 0;
	delay1();
	SCL = 1;
	delay1();
	SDA = 1 ;
	delay1();

}

void I2C_Ack()
{
	SDA = 0;
	SCL = 1;
	SCL = 0;
}

void I2C_Nack()
{
	SDA = 1;
	SCL = 1;
	SCL = 0;
}

// Initialize serial port 
void initRS ()
{
    SCON  = 0x50;		        // SCON: mode 1, 8-bit UART, enable rcvr      
    TMOD  = 0x20;               // TMOD: timer 1, mode 2, 8-bit reload        
    TH1   = 253;                // TH1:  reload value for 9600 baud @ 11.0592MHz   FDH
    TR1   = 1;                  // TR1:  timer 1 run                          
    TI    = 1;                 	// TI:   set TI to send first char of UART    
}

//Initialize port
void initPort()
{
	P1 = 0xFF;                 
	P2 = 0x00;
	P0 = 0x00;
}

Code:
:030000000200A556
:0C00A500787FE4F6D8FD75810702005951
:07003500D29012003CD291B1
:10003C00E4FFFEE4FDFC0DBD00010CED64324C70E0
:0C004C00F50FBF00010EBE03EABFE8E79D
:010058002285
:1000590012008A1200BB1200D21200797F401200EE
:10006900037FAA1200037FF01200031200B180FE81
:02000300AB0749
:10000500E4FAC29112003CEB20E704C2908002D2D0
:100015009012003CD291EB25E0FB12003CC2910A04
:0F002500BA08DFC29112003C120035C291A290BE
:0100340022A9
:0500D200D290D2912242
:10007900D291D29012003CC29012003CC29102006F
:010089003C3A
:0D009800120035C29012003CC29002003CE4
:0A00B100C290120037D29002003C0A
:0700C400C290D291C291220B
:0700CB00D290D291C29122F4
:0E008A00759850758920758DFDD28ED2992201
:0900BB007590FFE4F5A0F5802228
:00000001FF
 

P1 has to be made output port. I guess P1.0 (SDA) has to be made output while writing data to slave and then made input to receive ACK from slave. I tested your code, it is not working.

Edit: There is a 8051 software I2C example project at saeedsolutions.blogspot.com Try using that i2C code and see if that works for you.

Try i2c codes here.

https://www.8051projects.net/i2c-twi-tutorial/index.php

https://saeedsolutions.blogspot.in/2012/11/8051-i2c-bit-banging-code-proteus.html

https://saeedsolutions.blogspot.in/2012/11/interfacing-of-8051-with-i2c-based.html
 
Last edited:

Thank you for your advise.

I already tested the code based on the reference given, but still didn't works fine for me.
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…