Thread: PIC16F724 communication with PCA9622 using I2C

  1. #1
    Registered User
    Join Date
    May 2012
    Posts
    11

    PIC16F724 communication with PCA9622 using I2C

    Hi all.
    I have recieved a circuitboard that i have to program to do some simple stuff. The only problem is that i have very little experience in C. I am used to programming PLC's in ladder.

    The board has 30 led's that are connected with two PCA9622 chips controlled by the PIC. There are 17 inputs and two outputs on the board. The first 15 led's are green and the last 15 are yellow.
    LED1 and LED16 are combined in one, LED2 and 17 are combined and so on..

    The function should be this:
    If input 1 gets high led1 or led16 goes on, if in2 gets high led2 or led17 goes on and so on. So i should be able to chose if it is the green or the yellow led that is lit whenever input x is high.
    If input 16 goes high all yellow led's should be lit to see if they work.

    The two outputs should be set high if certain led's are on. I should be able to write which led's would set one of the outputs high.

    That is basically it.

    I have read through the datasheet of the PCA9622 and also the PIC. I have programmed this type of PIC before to drive som ledīs, but not through i2c.

    I am very confused on how to deal with this.
    I have some code, but i am not sure how to do this. The first thing is to be able to turn on the led's individually.

    So far i have understood this is how it goes:
    Start
    1. adress of slave (PCA9622)
    2. go to mode 1 register (don't know why, but that is what i get from the datasheet)
    3. ReStart
    4. adress of slave again
    5. and know i am lost?!? :S


    Code:
    #include	<htc.h>
    
    #define _XTAL_FREQ 16000000
    
    
    #define SCL     RC3 // I2C bus
    #define SDA     RC4 //
    
    
    #define green 0x14;
    #define red 0x15;
    
    
    void i2c_dly(void)
    {
    }
    
    
    void i2c_start(void)
    {
      SDA = 1;             // i2c start bit sequence
      i2c_dly();
      SCL = 1;
      i2c_dly();
      SDA = 0;
      i2c_dly();
      SCL = 0;
      i2c_dly();
    }
    
    
    void i2c_stop(void)
    {
      SDA = 0;             // i2c stop bit sequence
      i2c_dly();
      SCL = 1;
      i2c_dly();
      SDA = 1;
      i2c_dly();
    }
    
    
    
    
    main(void){
    i2c_start();              // send start sequence
    SDA = green;			//adress for the green led driver
    SDA = 0x00;				//Mode 1 register
    _delay_us(600);
    i2c_start(); 			//restart
    SDA = green;			//adress for the green led driver
    SDA = 0x14;
    
    
    i2c_stop();               // send stop sequence
    
    
    }
    I have a schematic for the board, but the pdf is to large for upload to the forum, so i will get it resized later.

    But the datasheet for PCA9622 is here http://www.nxp.com/documents/data_sheet/PCA9622.pdf

    Any help for the part with the i2c and PCA9622 would be much appreciated!

    Regards Nic

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    FYI: The chip PIC16F724 has hardware support for I2C; there is no need for bit-banging the outputs.

    Read section 17.2 of the PIC manual.

    Example code for PIC
    Microchip PIC micros and C - source and sample code

    Note: I have not used any of the I2C example code.

    FYI: You are likely to get better help on micro-controllers here All About Circuits Forum - Powered by vBulletin

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  3. #3
    Registered User
    Join Date
    May 2012
    Posts
    11
    Thank you for the reply.
    As i mentioned, i have no experience in this, so i did not know what bit banging was before you mentioned it.
    But again. I have struggled whit this a couple of nights know, reading on the internet and in a couple of manuals as well. But i am still no getting much further in this.
    I have looked at the sample code in the link, but it is not quite what i am looking for i guess.

    To make it simple i just want to get the PCA9622 to light up a LED - i don't want to dim the light or blink in any way. Just on and off.
    I thought that there would be a library for this kind of stuff, to make it more easy to program. I have worked a little with arduino, and there is almost a library for everything there...

    Please bear with me, I am REALLY a newbie...

    Here is a link to the circuit i am working with.All About Circuits Forum

  4. #4
    Registered User
    Join Date
    May 2012
    Posts
    11
    Hi. I have mounted pull-ups on the lines now (they were missing).
    But i still have problems.
    I use a example from hitechC compiler.
    It worked fine at first. I have light in the led's. But it seems like it stays in some infinite loop somewhere. It stays locked in this position. Sometimes when i transfer a edited program it doesn't work - then i unplug the power and wait for 10 seconds and plug it back in, then i get light! But if i plug it in after lets say 3 seconds, then i don't get light!?

    It seems like i am stuck in a loop?

    Code:
    #include <htc.h>
    #define _XTAL_FREQ 16000000
    #include  "i2c.h"
    /*
     * I2C functions for HI-TECH PIC C - master mode only
     */
    /*
     *  TIMING - see Philips document: THE I2C-BUS SPECIFICATION
     */
    
    /*
     *  Send stop condition
     *    - data low-high while clock high
     */
    void
    i2c_Stop(void)
    {
     /* don't assume SCL is high on entry */
     SCL_LOW();
     SDA_LOW();     /* ensure data is low first */
     
     __delay_us(I2C_TM_DATA_SU);
     SCL_DIR = I2C_INPUT;  /* float clock high */
     __delay_us(I2C_TM_STOP_SU);
     SDA_HIGH();     /* the low->high data transistion */
     __delay_us(I2C_TM_BUS_FREE); /* bus free time before next start */
     SDA_DIR = I2C_INPUT;  /* float data high */
     return;
    }
    /*
     *  Send (re)start condition
     *    - ensure data is high then issue a start condition
     *    - see also i2c_Start() macro
     */
    void
    i2c_Restart(void)
    {
     SCL_LOW();     /* ensure clock is low */
     SDA_HIGH();     /* ensure data is high */
     __delay_us(I2C_TM_DATA_SU);
     SCL_DIR = I2C_INPUT;  /* clock pulse high */
     __delay_us(I2C_TM_SCL_HIGH);
     SDA_LOW();     /* the high->low transition */
     __delay_us(I2C_TM_START_HD);
     return;
    }
    /*
     *  Send a byte to the slave
     *    - returns true on error
     */
    unsigned char
    i2c_SendByte(unsigned char byte)
    {
     signed char i;
     for(i=7; i>=0; i--)
     {
      SCL_LOW();     /* drive clock low */
      
      /* data hold time = 0, send data now */
            SDA_DIR = ((byte>>i)&0x01);
            if ((byte>>i)&0x01) {  /* bit to send */
       SDA_HIGH();
            }else {
       SDA_LOW();
            }
      __delay_us(I2C_TM_DATA_SU);
      SCL_DIR = I2C_INPUT;  /* float clock high */
      if(i2c_WaitForSCL())  /* wait for clock release */
       return TRUE;   /* bus error */
      __delay_us(I2C_TM_SCL_HIGH); /* clock high time */
     }
     
     return FALSE;
    }
    /*
     *  send an address and data direction to the slave
     *    - 7-bit address (lsb ignored)
     *    - direction (FALSE = write )
     */
    unsigned char
    i2c_SendAddress(unsigned char address, unsigned char rw)
    {
     return i2c_SendByte(address | (rw?1:0));
    }
    /*
     *  Check for an acknowledge
     *    - returns ack or ~ack, or ERROR if a bus error
     */
    signed char
    i2c_ReadAcknowledge(void)
    {
     unsigned char ack;
     SCL_LOW();      /* make clock is low */
     SDA_DIR = I2C_INPUT;   /* disable data line - listen for ack */
     __delay_us(I2C_TM_SCL_TO_DATA); /* SCL low to data out valid */
     SCL_DIR = I2C_INPUT;   /* float clock high */
     __delay_us(I2C_TM_DATA_SU);
     ack = SDA;      /* read the acknowledge */
     /* wait for slave to release clock line after processing byte */
     if(i2c_WaitForSCL())
      return I2C_ERROR;
     return ack;
    }
    /*
     *  Read a byte from the slave
     *    - returns the byte, or I2C_ERROR if a bus error
     */
    int
    i2c_ReadByte(void)
    {
     unsigned char i;
     unsigned char byte = 0;
     for(i=0; i<8; i++)
     {
      SCL_LOW();     /* drive clock low */
      __delay_us(I2C_TM_SCL_LOW); /* min clock low  period */
      SDA_DIR = I2C_INPUT;  /* release data line */
      SCL_DIR = I2C_INPUT;  /* float clock high */
      if(i2c_WaitForSCL())
       return I2C_ERROR;
      __delay_us(I2C_TM_SCL_HIGH);
      byte = byte << 1;  /* read the next bit */
      byte |= SDA;
     }
     return (int)byte;
    }
    /*
     *  Send an (~)acknowledge to the slave
     *    - status of I2C_LAST implies this is the last byte to be sent
     */
    void
    i2c_SendAcknowledge(unsigned char status)
    {
     SCL_LOW();
     if ( status & 0x01) {
      SDA_LOW();    /* drive line low -> more to come */
     }else { 
      SDA_HIGH();
     }
     __delay_us(I2C_TM_DATA_SU);
     SCL_DIR = I2C_INPUT;  /* float clock high */
     __delay_us(I2C_TM_SCL_HIGH);
     return;
    }
    /*
     *  Send a byte to the slave and acknowledges the transfer
     *    - returns I2C_ERROR, ack or ~ack
     */
    signed char
    i2c_PutByte(unsigned char data)
    {
     if(i2c_SendByte(data))
      return I2C_ERROR;
     return i2c_ReadAcknowledge(); /* returns ack, ~ack */
    }
    /*
     *  Get a byte from the slave and acknowledges the transfer
     *    - returns true on I2C_ERROR or byte
     */
    int
    i2c_GetByte(unsigned char more)
    {
     int byte;
     if((byte = i2c_ReadByte()) == I2C_ERROR)
      return I2C_ERROR;
     i2c_SendAcknowledge(more);
     return byte;
    }
    /*
     *  Send an array of bytes to the slave and acknowledges the transfer
     *    - returns number of bytes not successfully transmitted
     */
    int
    i2c_PutString(const unsigned char *str, unsigned char length)
    {
     signed char error;
     while(length)
     {
      if((error = i2c_PutByte(*str)) == I2C_ERROR)
       return -(int)length;     /* bus error */
      else
       if(error)
        return (int)length;     /* non acknowledge */
      str++;
      length--;
     }
     return FALSE;         /* everything OK */
    }
    /*
     *  Reads number bytes from the slave, stores them at str and acknowledges the transfer
     *    - returns number of bytes not successfully read in
     */
    unsigned char
    i2c_GetString(unsigned char *str, unsigned char number)
    {
     int byte;
     while(number)
     {
      if((byte = i2c_GetByte(number-1)) == I2C_ERROR)
       return number;        /* bus error */
      else
       *str = (unsigned char)byte;
      str++;
      number--;
     }
     return FALSE;          /* everything OK */
    }
    /*
     *  Opens communication with a device at address. mode
     *  indicates I2C_READ or I2C_WRITE.
     *    - returns TRUE if address is not acknowledged
     */
    unsigned char
    i2c_Open(unsigned char address, unsigned char mode)
    {
     i2c_Start();
     i2c_SendAddress(address, mode);
     if(i2c_ReadAcknowledge()) 
      return TRUE;
     return FALSE;
    }
    /*
     *  wait for the clock line to be released by slow slaves
     *    - returns TRUE if SCL was not released after the
     *      time out period.
     *    - returns FALSE if and when SCL released
     */
    unsigned char
    i2c_WaitForSCL(void)
    {
     /* SCL_DIR should be input here */
     if(!SCL)
     {
      __delay_us(I2C_TM_SCL_TMO);
      /* if the clock is still low -> bus error */
      if(!SCL)
       return TRUE;
     }
     return FALSE;
    }
    void
    i2c_Free()
    {
     unsigned char ucI;
     SDA_DIR=I2C_INPUT;
     for(ucI=0;ucI!=9;ucI++)
     {
      SCL_HIGH();
      __delay_us(5);
      SCL_LOW();
      __delay_us(5);
     }
    }
    unsigned char i2c_read(unsigned char ucAdr)
    {
     unsigned char ucDat;
     if (i2c_ReadFrom(ucAdr)==0)
     {
      ucDat=i2c_GetByte(I2C_MORE);
      i2c_Stop();
     }
     return(ucDat);
    }
    
    main(void){
    TRISB = 0;
    PORTB = 0x00;   //OE pin LOW 
    i2c_WriteTo(0x28);
    i2c_PutByte(0x00);
    i2c_PutByte(0x00);
    i2c_Stop(); 
    i2c_WriteTo(0x28);
    i2c_PutByte(0x14);
    i2c_PutByte(0x55);
    i2c_Stop();  
    i2c_WriteTo(0x2A);
    i2c_PutByte(0x15);
    i2c_PutByte(0x55);
    i2c_Stop();   
    i2c_WriteTo(0x2A);
    i2c_PutByte(0x16);
    i2c_PutByte(0x55);
    i2c_Stop(); 
    i2c_WriteTo(0x2A);
    i2c_PutByte(0x00);
    i2c_PutByte(0x00);
    i2c_Stop();
    i2c_WriteTo(0x2A);
    i2c_PutByte(0x17);
    i2c_PutByte(0x55);
    i2c_Stop(); 
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Communication between C++ DLL and a C# GUI
    By JeremyCAFE in forum C++ Programming
    Replies: 5
    Last Post: 11-29-2007, 11:09 AM
  2. Communication with cmd.exe
    By Livijn in forum C++ Programming
    Replies: 16
    Last Post: 03-31-2007, 09:14 AM
  3. USB Communication
    By Queatrix in forum Windows Programming
    Replies: 4
    Last Post: 08-07-2006, 10:22 AM
  4. Looking for communication lib
    By BrownB in forum C Programming
    Replies: 3
    Last Post: 04-27-2005, 10:01 AM
  5. C++ and PHP communication
    By Korhedron in forum Game Programming
    Replies: 4
    Last Post: 01-12-2004, 06:37 AM