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 support@ccsinfo.com

sensor networks
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Olufola



Joined: 19 May 2009
Posts: 21

View user's profile Send private message

PostPosted: Tue Jun 16, 2009 4:02 pm     Reply with quote

I will go ahead with your advice. I think those codes are okay. I will do an extensive hardware troubleshooting now that the likelyhood of software errors is now largely ruled out. I will keep you informed about any progresses as soon as they are made. Thanks a lot. I may one day take on your role on this forum (That was a joke since experience does not come by boasting)
Olufola



Joined: 19 May 2009
Posts: 21

View user's profile Send private message

PostPosted: Sat Jun 20, 2009 1:56 am     Reply with quote

Very Happy

The impossible has become a possibility at last. I have a perfectly working sensor network implemented with I2C using the CCS C. All previous project managers could not do it. I will need to refer to PCM programmer when I am presenting the project but that is no name.

Thanks a thousand, a million ... infinitely to Mr PCM programmer but I cannot refer to you with that name when presenting the project.

The code that finally worked follows for any other person that might need it:

MASTER CODE
Code:

#include <18f4520.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
   
#define SLAVE1_WRT_ADDR   0x14
#define SLAVE1_READ_ADDR  0x15

#define SLAVE2_WRT_ADDR   0x28
#define SLAVE2_READ_ADDR  0x29

#define SLAVE3_WRT_ADDR   0x42
#define SLAVE3_READ_ADDR  0x43

//====================================
void main()
{
int8 data1,data2,data3;

while(1)
  {
  output_high(pin_d4);
   delay_ms(60);
   output_low(pin_d4);
   i2c_start();
   i2c_write(SLAVE1_READ_ADDR);
   data1 = i2c_read(0);
   i2c_stop();
   delay_ms(10);
   i2c_start();
   i2c_write(SLAVE2_READ_ADDR);
   data2 = i2c_read(0);
   i2c_stop();
   delay_ms(10);
   i2c_start();
   i2c_write(SLAVE3_READ_ADDR);
   data3 = i2c_read(0);
   i2c_stop();
   printf(" [ %3U %3U %3U ] \r\n", data1,data2,data3);
   output_high(pin_d6);
   delay_ms(60);
   output_low(pin_d6);
  }

}


SLAVE1 CODE
Code:

#include <18F4520.h>
#device adc=8
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x14)

int8 adc_result;


#INT_SSP
void ssp_interrupt()
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state < 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state >= 0x80)   // Master is requesting data from slave
  {
   i2c_write(14);
  }

}


//======================================
void main ()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
delay_us(20);
adc_result = read_adc();

enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
   
while(1)
  {
   adc_result = read_adc();
   delay_ms(500);
  }

}


SLAVE2 CODE
Code:

#include <18F4520.h>
#device adc=8
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x28)

int8 adc_result;


#INT_SSP
void ssp_interrupt()
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state < 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state >= 0x80)   // Master is requesting data from slave
  {
   i2c_write(28);
  }

}


//======================================
void main ()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
delay_us(20);
adc_result = read_adc();

enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
   
while(1)
  {
   adc_result = read_adc();
   delay_ms(500);
  }

}


SLAVE3 CODE
Code:

#include <18F4520.h>
#device adc=8
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x42)

int8 adc_result;


#INT_SSP
void ssp_interrupt()
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state < 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state >= 0x80)   // Master is requesting data from slave
  {
   i2c_write(42);
  }

}


//======================================
void main ()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
delay_us(20);
adc_result = read_adc();

enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
   
while(1)
  {
   adc_result = read_adc();
   delay_ms(500);
  }

}

If you are using this code, then it will be okay if "PCM Programmer" which is no name but just an identifier be acknowledged.
thedemri



Joined: 22 Sep 2007
Posts: 3

View user's profile Send private message

PostPosted: Sat Aug 21, 2010 2:55 pm     Reply with quote

Olufola hi
I know it was long time ago but do you remember what was the problem with the 3 slaves?
because the code with and without the problems are pretty similar.
Thanks Amnon
Shocked
JH1987



Joined: 22 Jan 2011
Posts: 11

View user's profile Send private message

Small Change to Your Example
PostPosted: Tue Jan 25, 2011 2:10 pm     Reply with quote

PCM programmer wrote:
Here is a simple i2c slave demo. The slave PIC reads the ADC value
every 500 ms and saves it in a global variable. This emulates a sensor.
The master PIC reads the ADC value from the slave. The master does
not send an internal address byte to the slave. It only sends the i2c
slave device address, and then it reads the data byte.

Also, notice that the master is not using FORCE_HW mode in the
#use i2c() statement. In some PICs, this can cause problems. It's best
to start by using a software i2c Master. When you get that working
reliably, then add the FORCE_HW to the master and try it.

I'm using the equivalent of 2.2K pullups on SDA and SCL. This was
tested on two PicDem2-Plus boards, with vs. 4.093 of the compiler.

Here is the output of the master PIC, as I slowly turn a trimpot that is
connected to the AN0 analog input pin. I turned the pot all the way to
the right, and then back to 0 again.
Quote:

read 00
read 30
read 8C
read F3
read FF
read FF
read D8
read 88
read 15
read 00


i2c Master:
Code:
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
   
#define SLAVE1_WRT_ADDR   0x12
#define SLAVE1_READ_ADDR  0x13

//====================================
void main()
{
int8 data;

while(1)
  {
   i2c_start();
   i2c_write(SLAVE1_READ_ADDR);
   data = i2c_read(0);
   i2c_stop();

   printf("read %X \n\r", data);

   delay_ms(1000);
  }

}


i2c slave:
Code:
#include <16F877.h>
#device adc=8
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x12)

int8 adc_result;


#INT_SSP
void ssp_interrupt()
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state < 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state >= 0x80)   // Master is requesting data from slave
  {
   i2c_write(adc_result);
  }

}


//======================================
void main ()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
delay_us(20);
adc_result = read_adc();

enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
   
while(1)
  {
   adc_result = read_adc();
   delay_ms(500);
  }

}



---------
Edit #1: Fixed a typo
Edit #2: Changed the PROTECT fuse to NOPROTECT. There is no need
for code protection in a test program.


Your example is good, as always, but its probably a good idea to do a read in the master that expects ACK, and to do a read in the slave isr for address 0x80, which will send the ACK. This seems more in line with actual I2C use, where its almost always true that the master expects to get an ACK after it sends the slave adr & Wr/Rd byte.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 26, 2011 4:07 pm     Reply with quote

Quote:
and to do a read in the slave isr for address 0x80

No address of 0x80 is sent. The 0x80 (and other values) comes
from the CCS function i2c_isr_state(). It is described in the CCS manual:
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
JH1987



Joined: 22 Jan 2011
Posts: 11

View user's profile Send private message

Sorry for miscommunication
PostPosted: Wed Jan 26, 2011 10:12 pm     Reply with quote

PCM programmer wrote:
Quote:
and to do a read in the slave isr for address 0x80

No address of 0x80 is sent. The 0x80 (and other values) comes
from the CCS function i2c_isr_state(). It is described in the CCS manual:
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf


I know. I apologize for mistyping. I meant state 0x80, which corresponds to the master sending the slave a byte with the correct slave address & the R/W bit set.

What I meant was that doing an I2C read() when the state is 0x80 would cause the slave to send back an ACK to the master. I didn't realize that the slave PIC did this anyway, regardless of the argument you give I2C read(). In other words it seemed like the ISR was called when the PIC received an 8-bit data byte but before it returned ACK. In light of that it seems totally pointless for the CCS manual to do a read in their example ISR when the state is 0x80, because the ISR would not have been called without the correct slave address. That's why I assumed you had to do the read to load the ACK in the shift register. But then the slave PIC would have to do clock stretching automatically to buy time to load the register. Oh well, at least from these posts the details of the PIC I2C are very clear now. The manual was vague and unhelpful. Thanks for the info.

Here's the CCS example as an FYI to anybody reading this

Code:

#INT_SSP
void i2c_isr() {
state = i2c_isr_state();
if((state== 0 ) || (state== 0x80))
i@c_read();
if(state >= 0x80)
i2c_write(send_buffer[state - 0x80]);
else if(state > 0)
rcv_buffer[state - 1] = i2c_read();
}
khienpzo



Joined: 26 Nov 2012
Posts: 3

View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger ICQ Number

PostPosted: Wed Nov 28, 2012 4:18 am     Reply with quote

Hi. I have a questions for you
Code:

if(state >= 0x80)   
  {
   i2c_write(42);
  }

before your code:
Code:

if(state >= 0x80)   
        {
            i2c_write(adc_result);
        }

the difference here ?
Can you explain?
thanks for answer the questions ..
tienchuan



Joined: 25 Aug 2009
Posts: 175

View user's profile Send private message Yahoo Messenger

PostPosted: Mon Mar 11, 2013 9:37 pm     Reply with quote

PCM programmer wrote:
Here is a simple i2c slave demo. The slave PIC reads the ADC value
every 500 ms and saves it in a global variable. This emulates a sensor.
The master PIC reads the ADC value from the slave. The master does
not send an internal address byte to the slave. It only sends the i2c
slave device address, and then it reads the data byte.

Also, notice that the master is not using FORCE_HW mode in the
#use i2c() statement. In some PICs, this can cause problems. It's best
to start by using a software i2c Master. When you get that working
reliably, then add the FORCE_HW to the master and try it.

I'm using the equivalent of 2.2K pullups on SDA and SCL. This was
tested on two PicDem2-Plus boards, with vs. 4.093 of the compiler.

Here is the output of the master PIC, as I slowly turn a trimpot that is
connected to the AN0 analog input pin. I turned the pot all the way to
the right, and then back to 0 again.
Quote:

read 00
read 30
read 8C
read F3
read FF
read FF
read D8
read 88
read 15
read 00


i2c Master:
Code:
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
   
#define SLAVE1_WRT_ADDR   0x12
#define SLAVE1_READ_ADDR  0x13

//====================================
void main()
{
int8 data;

while(1)
  {
   i2c_start();
   i2c_write(SLAVE1_READ_ADDR);
   data = i2c_read(0);
   i2c_stop();

   printf("read %X \n\r", data);

   delay_ms(1000);
  }

}


i2c slave:
Code:
#include <16F877.h>
#device adc=8
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x12)

int8 adc_result;


#INT_SSP
void ssp_interrupt()
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state < 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state >= 0x80)   // Master is requesting data from slave
  {
   i2c_write(adc_result);
  }

}


//======================================
void main ()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
delay_us(20);
adc_result = read_adc();

enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
   
while(1)
  {
   adc_result = read_adc();
   delay_ms(500);
  }

}




---------
Edit #1: Fixed a typo
Edit #2: Changed the PROTECT fuse to NOPROTECT. There is no need
for code protection in a test program.


Hi PCM programer
I try with your code in CCS C and Proteus to simulate, but it don't work as well as you tell. I saw master received one byte adc value from slave and it stop until restart.
Can you show me problems?
My PCH and PCM have a version 4.104.
thanks u so much.
_________________
Begin Begin Begin !!!
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Mon Mar 11, 2013 9:49 pm     Reply with quote

Try having slave #1 send 1, 4, 7, 10 etc.
Slave #2 send 2, 5, 8, 11 etc.
Slave #3 send 3, 6, 9, 12 etc.

Then you will know who is sending and when they sent it.
_________________
The search for better is endless. Instead simply find very good and get the job done.
tienchuan



Joined: 25 Aug 2009
Posts: 175

View user's profile Send private message Yahoo Messenger

PostPosted: Mon Mar 11, 2013 10:15 pm     Reply with quote

SherpaDoug wrote:
Try having slave #1 send 1, 4, 7, 10 etc.
Slave #2 send 2, 5, 8, 11 etc.
Slave #3 send 3, 6, 9, 12 etc.

Then you will know who is sending and when they sent it.


Thanks SherpaDoug
I tested with your show but it's still error.
I'm still get only the first data, the next data is 0xFF?
Pls help me.
Thanks


++++++++++++++++++++++++++
tienchuan,

Proteus is buggy for i2c slave. Read this:

PIC101 - No more Proteus questions
http://www.ccsinfo.com/forum/viewtopic.php?t=47549

- Forum Moderator
++++++++++++++++++++++++++

_________________
Begin Begin Begin !!!
tienchuan



Joined: 25 Aug 2009
Posts: 175

View user's profile Send private message Yahoo Messenger

PostPosted: Tue Mar 12, 2013 12:48 am     Reply with quote

Thanks Mod
I'll test again on board.
Thanks.
_________________
Begin Begin Begin !!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19257

View user's profile Send private message

PostPosted: Tue Mar 12, 2013 1:42 am     Reply with quote

On _some_ PIC's, it is required to do the read in the 0x80 state.
On these the buffer full bit, does not reset unless this is done, and then the I2C will hang, because on the next received byte, the interrupt doesn't trigger.
This is one where lots of people run with a PIC where this doesn't happen, and other have chips where this is needed, and code that works happily on the former, won't work on the latter. It is also one where the Proteus emulation differs from real chips.....

Best Wishes
mcr1981



Joined: 27 Oct 2010
Posts: 28

View user's profile Send private message

Thanks for this code.
PostPosted: Mon Oct 12, 2015 7:06 am     Reply with quote

I was able to communicate a master with a slave.

Could not use hardware I²C on a 18F45K22 but did it with software routines (#use I2C).

Will post the address snapshot. It's something strange:
The protocol (if I've read correctly) will shift to the left the address one bit and does not looks like it.

The address is 0x10 for the slave and we are supposed to see 0x20 but the 0x10 is what I see.


The compiler version is 5.038.


Thanks for this code Mr PCM programmer.
Very Happy
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Oct 12, 2015 8:44 am     Reply with quote

CCS uses 8-bit format for the i2c slave address, in which the 7-bit address
is shifted left by 1 and combined with the R/W bit in the D0 position.
So a 7-bit address of 0x10 in the Philips (NXP) format, becomes 0x20 in
byte format. For more information, see this comment by Ttelmah:
http://www.ccsinfo.com/forum/viewtopic.php?t=45628&start=4
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
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