PIC16F724 communication with PCA9622 using I2C

Thread Starter

nic6911

Joined Jun 22, 2012
24
Hi again.
The PCB has a fault. So i got another PCB and it works! With the code i posted.

But now i wan't to get my inputs working. I have programmed a pic similar to this without i2c. There i got my inputs and outputs to work fine. But here i can't get it to react on my input. Is it because the i2c bus uses the PIC constantly?
 
Good going! Is there a clrf ANSELD? might as well clrf ANSELE while you are at it. Didn't see any analog (i.e. ANX) on PORTD, must have to do with capsense. Too bad no PWM on the leds, that's where the chip shines.
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
clrf ANSELD? clrf ANSELE??

Yeah, but i really don't need any PWM. It has to be simple. It has too meet som regulations here in DK and they don't like when you make something fancy... :)
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
from the pic16 data sheet "Setting a TRISD bit (= 1) will make the
corresponding PORTD pin an input"
This is how i do on all the other ports also, and they work. I can see that they can be configured as analog in.
But it also says "CLRF ANSELD ;Make PORTD digital" i will try this when i get the PCB back from repair. That could be the problem, just thought that it was defined as digital as default, but that doesn't seem to be the case!

Thanks again for the help!!
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
but "CLRF ANSELD ;Make PORTD digital" is in assembly.
I will see if port D works when i get the PCB back, or else i will look in the hitech manual :)

But for now i am just pleased it works with the led's! The inputs i will figure out eventually.

And again i will thank you for your help!
 
Glad to help.......Assembly shouldn't be a bad word, knowing a little bit never hurts :) Looking at the assembly can be instructional and can be an important debugging tool. Sometimes what you think you are telling the micro in a hll doesn't always translate to the low level assembler.
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
Hi again. I have now programmed a couple of these circuitboards but have never used more than 5 led's.
Now i have to use all the LED's (15) and i can't get it to work.
If i set input x high led x will be on. And this works fine for the first 8 led's (the last 8 outputs on PCA). But for the last 7 led's the led stays on even if the input gets low again. (the designer connected the led's from the bottom and up, so output 16 on the pca is the first led.)
So it doesn't set the output low on the PCA9622... But only on half of the led's. If i use the same integer to turn on the first and the last led they both go on and off as they should.

I just can't figure this one out... I really hope it is my poor code that is the problem!

(code in next post)
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
Rich (BB code):
#include	<htc.h>

#define _XTAL_FREQ 16000000
#include 	"i2c.h"
int led4; 
int led8; 
int led12;
int led15;

/*
 *	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){
TRISA = 0xFF;
ANSELD =0x00;
TRISD = 0xFF;
TRISE = 0x01; 
TRISB = 0x00; 
PORTB = 0x00; 


if(RA7==1){led4|=1<<6;}//sæt int led4 plads 0 til 1 - indgang 2 til diode 1
if(RA7==0){led4|=0<<6;}//sæt int led4 plads 0 til 0 
if(RC0==1){led4|=1<<4;}//sæt int led4 plads 2 til 1 - indgang 4 til diode 3
if(RC0==0){led4|=0<<4;}//sæt int led4 plads 2 til 0
if(RC1==1){led4|=1<<2;}//sæt int led4 plads 4 til 1 - indgang 3 til diode 2
if(RC1==0){led4|=0<<2;}//sæt int led4 plads 4 til 0
if(RC2==1){led4|=1<<0;}//sæt int led4 plads 6 til 1 - indgang 5 til diode 4
if(RC2==0){led4|=0<<0;}//sæt int led4 plads 6 til 0

if(RC5==1){led8|=1<<6;}//sæt int led8 plads 0 til 1 - indgang 6 til diode 5
if(RC5==0){led8|=0<<6;}//sæt int led8 plads 0 til 0 
if(RC6==1){led8|=1<<4;}//sæt int led8 plads 2 til 1 - indgang 7 til diode 6
if(RC6==0){led8|=0<<4;}//sæt int led8 plads 2 til 0
if(RC7==1){led8|=1<<2;}//sæt int led8 plads 4 til 1 - indgang 8 til diode 7
if(RC7==0){led8|=0<<2;}//sæt int led8 plads 4 til 0
if(RD0==1){led8|=1<<0;}//sæt int led8 plads 6 til 1 - indgang 9 til diode 8
if(RD0==0){led8|=0<<0;}//sæt int led8 plads 6 til 0

if(RD1==1){led12|=1<<6;}//sæt int led12 plads 0 til 1 - indgang 6 til diode 5
if(RD1==0){led12|=0<<6;}//sæt int led12 plads 0 til 0 
if(RD2==1){led12|=1<<4;}//sæt int led12 plads 2 til 1 - indgang 7 til diode 6
if(RD2==0){led12|=0<<4;}//sæt int led12 plads 2 til 0
if(RD3==1){led12|=1<<2;}//sæt int led12 plads 4 til 1 - indgang 8 til diode 7
if(RD3==0){led12|=0<<2;}//sæt int led12 plads 4 til 0
if(RD4==1){led12|=1<<0;}//sæt int led12 plads 6 til 1 - indgang 9 til diode 8
if(RD4==0){led12|=0<<0;}//sæt int led12 plads 6 til 0

if(RD5==1){led15|=1<<6;}//sæt int led15 plads 0 til 1 - indgang 6 til diode 5
if(RD5==0){led15|=0<<6;}//sæt int led15 plads 0 til 0 
if(RD6==1){led15|=1<<4;}//sæt int led15 plads 2 til 1 - indgang 7 til diode 6
if(RD6==0){led15|=0<<4;}//sæt int led15 plads 2 til 0
if(RD7==1){led15|=1<<2;}//sæt int led15 plads 4 til 1 - indgang 8 til diode 7
if(RD7==0){led15|=0<<2;}//sæt int led15 plads 4 til 0

//output til b-alarm output 1
if(led4|=0){RE1=1;}
if(led8|=0){RE1=1;}
if(led12|=0){RE1=1;}
if(led15|=0){RE1=1;}
if(led4==0&&led8==0&&led12==0&&led15==0){RE1=0;}

//Start af i2c moduler

i2c_WriteTo(0x28); //starter i2c på adresse 28(grøn)
i2c_PutByte(0x00); //mode 1
i2c_PutByte(0x00); //sender 0 til mode 1
i2c_Stop();
i2c_WriteTo(0x2A); //gul adresse
i2c_PutByte(0x00);
i2c_PutByte(0x00);
i2c_Stop();

//første 4 dioder gul

i2c_WriteTo(0x2A);
i2c_PutByte(0x17);
i2c_PutByte(led4);
i2c_Stop();

//næste 4 dioder gul

i2c_WriteTo(0x2A);
i2c_PutByte(0x16);
i2c_PutByte(led8);
i2c_Stop();

//næste 4 dioder gul

i2c_WriteTo(0x2A);
i2c_PutByte(0x15);
i2c_PutByte(led12);
i2c_Stop();

//næste 3 dioder gul

i2c_WriteTo(0x2A);
i2c_PutByte(0x14);
i2c_PutByte(led15);
i2c_Stop();

// lampetest
if(RA6==1){
i2c_WriteTo(0x2A);
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(0x17);
i2c_PutByte(0x55);
i2c_Stop(); 
}
if(RA6==0){
i2c_WriteTo(0x2A);
i2c_PutByte(0x14);
i2c_PutByte(0x00);
i2c_Stop(); 
i2c_WriteTo(0x2A);
i2c_PutByte(0x15);
i2c_PutByte(0x00);
i2c_Stop();   
i2c_WriteTo(0x2A);
i2c_PutByte(0x16);
i2c_PutByte(0x00);
i2c_Stop(); 
i2c_WriteTo(0x2A);
i2c_PutByte(0x17);
i2c_PutByte(0x00);
i2c_Stop();
}
}
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
Oh yes, and the last thing in the code is to test the function of all the led's, and this works fine! All the led's go on when RA6 is high and off when RA6 is low again....
 
The good thing is that the writes to the PCA9622 are working correctly. The inputs/Ports are still not initialized correctly in Main. It looks like PortD inputs are working correctly?, but PortC are not for the reasons already discussed.
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
All the inputs are working.
Rich (BB code):
if(RA7==1){led4|=1<<6;}//sæt int led4 plads 0 til 1 - indgang 2 til diode 1
if(RA7==0){led4|=0<<6;}//sæt int led4 plads 0 til 0 
if(RC0==1){led4|=1<<4;}//sæt int led4 plads 2 til 1 - indgang 4 til diode 3
if(RC0==0){led4|=0<<4;}//sæt int led4 plads 2 til 0
if(RC1==1){led4|=1<<2;}//sæt int led4 plads 4 til 1 - indgang 3 til diode 2
if(RC1==0){led4|=0<<2;}//sæt int led4 plads 4 til 0
if(RC2==1){led4|=1<<0;}//sæt int led4 plads 6 til 1 - indgang 5 til diode 4
if(RC2==0){led4|=0<<0;}//sæt int led4 plads 6 til 0


if(RC5==1){led8|=1<<6;}//sæt int led8 plads 0 til 1 - indgang 6 til diode 5
if(RC5==0){led8|=0<<6;}//sæt int led8 plads 0 til 0 
if(RC6==1){led8|=1<<4;}//sæt int led8 plads 2 til 1 - indgang 7 til diode 6
if(RC6==0){led8|=0<<4;}//sæt int led8 plads 2 til 0
if(RC7==1){led8|=1<<2;}//sæt int led8 plads 4 til 1 - indgang 8 til diode 7
if(RC7==0){led8|=0<<2;}//sæt int led8 plads 4 til 0
if(RD0==1){led8|=1<<0;}//sæt int led8 plads 6 til 1 - indgang 9 til diode 8
if(RD0==0){led8|=0<<0;}//sæt int led8 plads 6 til 0
Works fine, and i can change the inputs to either of the remaining inputs and get response.
I can also get the last 7 led's to turn on, but they remain on even if the input is low.
Rich (BB code):
if(RD0==1){led15|=1<<0;}
if(RD0==0){led15|=0<<0;}
It does not do the second if on led12 and led15.

Rich (BB code):
i2c_WriteTo(0x2A);
i2c_PutByte(0x17);
i2c_PutByte(led4);
i2c_Stop();

//næste 4 dioder gul

i2c_WriteTo(0x2A);
i2c_PutByte(0x16);
i2c_PutByte(led8);
i2c_Stop();

//næste 4 dioder gul

i2c_WriteTo(0x2A);
i2c_PutByte(0x15);
i2c_PutByte(led12);
i2c_Stop();

//næste 3 dioder gul

i2c_WriteTo(0x2A);
i2c_PutByte(0x14);
i2c_PutByte(led15);
i2c_Stop();
If i replace led12 and 15 with led4 and led8 i turn two led's on and off at a time, and that works fine...

I just don't get it...
 

Thread Starter

nic6911

Joined Jun 22, 2012
24
Hmm.. It is because led4, led8, led12 and led15 was declared as integers. It seemes like it was to much to handle for the pic. I corrected it to char's instead and it works fine now.

I have one more quick question though.
If i wan't to have a delay on a input how do i do that right?

my own suggestion
Rich (BB code):
int count//to store the counted value in

if(RA7==1&&count<5000){//if my input is high and the counter is less than 5000 then delay and count
__delay_ms(10);
count++;
}

if (count==5000){led4|=1<<6;}//if my countvalue is 5000 the the led should go on

if (RE0==1){count=0;}//resetbutton to reset the timer
Could that work?
As i see it i will only get a delay of 10ms each time the code runs, so it isn't caught in a loop for 50000ms where it can't do anything else.

like this
Rich (BB code):
if(RA7==1&&count<5000){//if my input is high and the counter is less than 5000 then delay and count
__delay_ms(10);
count++;
}
if(RC0==1){led4|=1<<4;}//it will move on to the rest of the code after the 10ms delay. and therefore i will only have 10ms delay in the program
I can't figure out how to run a timer in any other way. And if the delay is only 10ms i can live with it.
 
Top