Author Topic: Need help interfacing i2c PCF8575 with 8051 microcontroller  (Read 1624 times)

0 Members and 1 Guest are viewing this topic.

Offline chiart_nor

  • Newbie
  • Posts: 3
Need help interfacing i2c PCF8575 with 8051 microcontroller
« on: November 25, 2013, 03:42:32 pm »
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.

#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.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Need help interfacing i2c PCF8575 with 8051 microcontroller
« Reply #1 on: November 25, 2013, 04:19:23 pm »
The first thing to do in those cases is to make sure that your low level routines work.
================================
https://dannyelectronics.wordpress.com/
 

Offline free_electron

  • Super Contributor
  • ***
  • Posts: 7447
  • Country: us
    • SiliconValleyGarage
Re: Need help interfacing i2c PCF8575 with 8051 microcontroller
« Reply #2 on: November 25, 2013, 04:25:00 pm »
Wow. There is a ton of mistakes in that one...
 

//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(); <<< not needed
I2C_SendAck(); <<< not needed
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 // the start condition should have exited low !
       delay1(); // Data pin should change it's value,
       if ((Data & 0x80) == 0) // <<<<
         SDA = 0;
       else
         SDA = 001;
       delay1();
       SCL = 1;
       Data<<=1;
       delay1();
       Scl=0; // all routines must exit with clock low, or bus clear !
   }
}

unsigned char I2C_GetAck()//Get ACK from slave
    unsigned char i; // Variable to be used in for loop
      SDA = 1;
     delay1();
     SCL = 1;
<< delay here ! And sample the bloody sda, it should be low, if not -exit !
     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 ;


<<< what the hell was that ?!?
}



// 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();  // <<< added
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;
}

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.
Do you have any programming experience ? There are so many fundamental mistakes, not only against the protocol but also against basic programming.
« Last Edit: November 25, 2013, 07:56:42 pm by free_electron »
Professional Electron Wrangler.
Any comments, or points of view expressed, are my own and not endorsed , induced or compensated by my employer(s).
 

Offline chiart_nor

  • Newbie
  • Posts: 3
Re: Need help interfacing i2c PCF8575 with 8051 microcontroller
« Reply #3 on: November 26, 2013, 01:49:50 am »
Hi,

Thank you for the feedback and correcting my mistakes.
Based on the codes below :

I2C_Start();
I2C_Write(0x40);
I2C_Write(0xAA);
I2C_Write(0xF0);

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 // the start condition should have exited low !
       delay1(); // Data pin should change it's value,
      if ((Data & 0x80) == 0) // <<<<
         SDA = 0;
       else
         SDA = 001;
       delay1();
       SCL = 1;
       Data<<=1;
       delay1();
       Scl=0; // all routines must exit with clock low, or bus clear !
   }

From the highlighted code,
 if ((Data & 0x80) == 0) // Decimal = 128

In the previous code, the address is if ((Data & 0x40) == 0), This is where i go wrong.
I should define it as 0x80= 128 (8 bits) and to write the address to the slave, called the function I2C_Write.
Correct me if I'm wrong.

Thank you.

Regards,

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf