CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PCA9535PW I/O Expander with PIC16F883

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PCA9535PW I/O Expander with PIC16F883
PostPosted: Tue Jul 18, 2023 12:22 am     Reply with quote

Hello all,

I'm trying to use PCA9535PW with 16F883. First thing I need to do is set all P0 pins of PCA9535 to input and set all P1 pins to output. After this I need to check P0 pins and digital read and set low/high to P1 pins. I set PCA's address to 0x21(high to A0, low to A1,A2) I checked the i2c device with i2c scanner and it finds a device at 0x42 so there is no connection error.

Although I tried many things by looking at the datasheets, I could not set the pins. Unfortunately I don't have any serial port or a display so I can't debug and do any control from the serial port.

My code is as follows, I'm open to help.


Code:

#include <main.h>
#include <16f883.h>
#fuses NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT
#use delay(clock=8000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)

#define PCA9535_ADDRESS 0x42 // 21

void main()
{
   int8 outputData = 0x00; //
   
   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS); // PCA9535 address
   i2c_write(0x00); // P0 as input
   i2c_write(outputData); //
   i2c_stop(); //

   outputData = 0xFF; //
     
   i2c_start(); //
   i2c_write(PCA9535_ADDRESS); //
   i2c_write(0x03); // P1 as output
   i2c_write(outputData); // set pins high low
   i2c_stop(); //

   while(1)
   {


   }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 2:02 am     Reply with quote

First thing. Hurrah!...

You have covered so many things. You have understood the 7bit to 8bit
translation, have a 5v device. Great.
You have missed two things though. First you don't say what pull up's
you have on the bus?. However that it is working with the scanner code
suggests you have these OK.
Then key is understanding how the chip works. You have to send the chip
address, then a command, then data. Now, you don't have to 'Set P0 as
input'. It wakes up with both ports set as input. However you do have
to set P1 as output before you write to it, and you can't write to an input
port. Then on I2C you have to reverse the bus to read.
You have to start by writing to registers 6, and 7. These set the data
direction.
Code:

   //from here
   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x06); // P0 direction register
   i2c_write(0xFF); // set P0 as input (this is the default though)
   i2c_stop();
   //to here
   //These are not needed since default is P0 set as input.
   //Now P0 is set as input - so now read from it
   i2c_start();
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x00); //select read register
   i2c_start(); //This is a restart command
   i2c_write(PCA9535_ADDRESS+1); //This is now saying we want to _read_
   val=i2c_read(); //This now reads from input register 0 - so value of P0
   i2c_stop();

Now in the case of P0, you can actually start by assuming it is set to
read, so selecting the input is not 'needed'. However you still have to
issue a select for the read register and then read it.

Now to write P1:
Code:

   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x07); // P1 direction register
   i2c_write(0x0); // sets P1 as output
   i2c_stop();
   //Once this is done we can write to P1 output register

   //Now P1 is set as output, so write to it
   i2c_start();
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x03); //select write register P1
   i2c_write(val); //This now writes val to P1
   i2c_stop;


So you have to select the register, then direction, then perform the
I/O.
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 2:43 am     Reply with quote

Hello Ttelmah thanks for your reply, I am just learning communication protocols and your messages are very helpful to me.

[img] https://ibb.co/7KXXz2Q [/img]

this is my circuit, from r48 to r53 are optional I set them to make address 0x21, also I connect pull-ups to SDA/SCL.

I programmed the pic with your code but still there is no output on the P1 port. All are low. What could be the problem?
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 2:51 am     Reply with quote

Depends what you put in 'val'....
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 2:57 am     Reply with quote

First I tried 0x55 because I can understand which pin is low and high but no output, after I directly put the value that we equated to i2c_read above still no output.

What should be the format?
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 3:23 am     Reply with quote

First thing. Are you sure your chip is running?.
You don't show a clock configuration. You say clock=8000000,
but there are no fuses to select what oscillator is being used to create
this.
So, start be telling the chip to use it's internal oscillator:
Code:

#include <main.h>
#include <16f883.h>
#fuses NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT
#use delay(internal=8MHz)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)

Compiling your code as posted selects the RC oscillator, which requires
an external resistor/capacitor to work.

Sad
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 3:41 am     Reply with quote

I am sure that my chip works because I tried to set pins high low and it worked without any issue and delay functions were worked correct. Also I have a external oscillator, this is my circuit around the chip:

[img] https://ibb.co/PDVfFTc [/img]

This is my code with last updates:

Code:
 

#include <16F883.h>
#include <main.h>
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT
#use delay(clock=8M)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#use FIXED_IO(B_outputs=PIN_B5,PIN_B4,PIN_B3)

#define PCA9535_ADDRESS 0x42 // 42?

void main()
{

   int8 val;

   while(TRUE)
   {


   //from here
   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS | 0x01); // PCA9535 _write_ address
   i2c_write(0x06); // P0 direction register
   i2c_write(0xFF); // set P0 as input (this is the default though)
   i2c_stop();
   //to here
   //These are not needed since default is P0 set as input.
   //Now P0 is set as input - so now read from it
   i2c_start();
   i2c_write(PCA9535_ADDRESS | 0x01); // PCA9535 _write_ address
   i2c_write(0x00); //select read register
   i2c_start(); //This is a restart command
   i2c_write(PCA9535_ADDRESS); //This is now saying we want to _read_
   val=i2c_read(); //This now reads from input register 0 - so value of P0
   i2c_stop();

   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS | 0x01); // PCA9535 _write_ address
   i2c_write(0x07); // P1 direction register
   i2c_write(0x00); // sets P1 as output
   i2c_stop();
   //Once this is done we can write to P1 output register

   //Now P1 is set as output, so write to it
   i2c_start();
   i2c_write(PCA9535_ADDRESS | 0x01); // PCA9535 _write_ address
   i2c_write(0x03); //select write register P1
   i2c_write(val); //This now writes val to P1
   i2c_stop();

     
    if (val == 0xE3)
    {
    output_high(PIN_B5);
    output_low(PIN_B4);
    }
    else
    {
    output_high(PIN_B4);
    output_low(PIN_B5);
    }

     
   }
}



Do you see any mistake?
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 4:44 am     Reply with quote

You have not used what I posted. A _read_ address has | 1. The address
on it's own is a write address. You have the addresses reversed.
Code:

#include <16f883.h>
#fuses NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT
#use delay(Crystal=8MHz)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)

#define PCA9535_ADDRESS 0x42 // 21

void main()
{
   int8 count;
   int 8 outputData; //
   
   i2c_start(); // I2C iletisimini baslat
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x07); // P1 direction register
   i2c_write(0x0); // sets P1 as output
   i2c_stop();
   //Once this is done we can write to P1 output register

   while (TRUE)
   {
      output_data=1;
      for (count=0;count<8;count++)
      {
         //Now P1 is set as output, so write to it
         i2c_start();
         i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
         i2c_write(0x03); //select write register P1
         i2c_write(output_data; //This now writes val to P1
         i2c_stop;
         output_data*=2; //select next bit
         delay_ms(1000);
      }
   }
}   


This should turn on P1.0 for one second, then P1.1, and step through
all 8 pins and then go back to the start.
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 5:58 am     Reply with quote

Thanks to you sir, I am finally able to run the expander now. I didn't know I had to do bit by bit processing, I thought it could take a byte of data I gave in a single message packet, but I was wrong. May I ask where did you find this information in the datasheet?

Similarly, I tried to read the P0 port, again assuming that the value is bit by bit, I saved these values in an array and wrote a function to convert this to the integer, but I think I'm making a mistake somewhere again.

Is this process correct?

Code:

void main()
{
   int8 count;
   int8 outputData; //
   int8 inputData; //
   int16 val[8];
   int8 result;
 
   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x06); // P0 direction register
   i2c_write(0xFF); // set P0 as input (this is the default though)
   i2c_stop();

   while (TRUE)
   {   
      for (count=0;count<8;count++)
      {
         //These are not needed since default is P0 set as input.
         //Now P0 is set as input - so now read from it
         i2c_start();
         i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
         i2c_write(0x00); //select read register
         i2c_start(); //This is a restart command
         i2c_write(PCA9535_ADDRESS+1); //This is now saying we want to _read_
         val[count]=i2c_read(); //This now reads from input register 0 - so value of P0
         i2c_stop();
         delay_ms(500);
      }
     
      for (int i = 0; i < 8; i++)
    {
        result = (result << 1) | val[i];
    }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 6:00 am     Reply with quote

You don't.
I'm just showing you each bit in turn being set on. The routine is writing
a byte each time.
I just did it as a demo, showing how the I/O needs to be done. Point is
you only have to setup the direction register(s) once, and can then just
input or output bytes as wanted.

Your val array is getting 8 copies of the whole byte. You don't need to scan
it bit by bit.
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 9:08 am     Reply with quote

Ttelmah,
I updated the code as you said, I don't know why, but no matter how I set the input ports, the value 0x02 comes to the "val" variable.

Code:

void main()
{

   int8 val;
   int8 result;

   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x06); // P0 direction register
   i2c_write(0xFF); // set P0 as input (this is the default though)
   i2c_stop();

   while (TRUE)
   {   

         i2c_start();
         i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
         i2c_write(0x00); //select read register
         i2c_start(); //This is a restart command
         i2c_write(PCA9535_ADDRESS+1); //This is now saying we want to _read_
         val=i2c_read(); //This now reads from input register 0 - so value of P0
         i2c_stop();
         
      }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 9:43 am     Reply with quote

OK. One change needed:
Code:

void main()
{

   int8 val;
   int8 result;

   i2c_start(); // I2C iletişimini başlat
   i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
   i2c_write(0x06); // P0 direction register
   i2c_write(0xFF); // set P0 as input (this is the default though)
   i2c_stop();

   while (TRUE)
   {   

         i2c_start();
         i2c_write(PCA9535_ADDRESS); // PCA9535 _write_ address
         i2c_write(0x00); //select read register
         i2c_start(); //This is a restart command
         i2c_write(PCA9535_ADDRESS+1); //This is now saying we want to _read_
         val=i2c_read(0); //This now reads from input register 0 - so value of P0
         i2c_stop();
         
      }
}


Note the zero in the read. You have to NACK the last byte read. I'd
have expected the first byte to be right though.
This matches exactly what the data sheet shows in Fig 10.
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Tue Jul 18, 2023 11:54 pm     Reply with quote

Yes that is it.

Its working properly. Now I can create an algorithm to operate system.

Thank you very very much sir for your patience and support.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group