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

Complete the task of slave[SOLVED]
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
hamid9543



Joined: 31 Jan 2013
Posts: 63

View user's profile Send private message

PostPosted: Sun Jan 20, 2019 9:31 am     Reply with quote

temtronic wrote:
Do you HAVE to use I2C ? As pointed out it's not the best for 'communications'. To get the feedback of 'task done', you need more pins, more interconnections.
RS-485 only needs 2,so actually saves I/O line in the 'comm bus'. It's been used for 'device 2 device communications for decades. The alarm industry adopted it a long time go. CCS in their FAQ section shows how to use a single wire to have several PICS talk to each other. I'veused a variation of that for 3 decades.
I2C is generally only good for very short distances (on same PCB).
Without knowing the details of the project, perhaps you can use one powerful PIC instead of several smaller ones ? Give us more details and we may have other options for you.

Jay

WOW amazing suggestion!
My project includes 36 LDR, 4 ultrasonic, 4 DC motors, 16 sensors TSOP 1138 and MPU6050 gyroscope.
>> all ldr sensor are read by 4 pic16f1937 inform of Analog(each 9 sensors are connected to a 16f1937)
>>pic16f1829 read all ultrasonic sensors and also measure the distance
>> gyroscope is connected to pic18f1829 which calculate Euler Angles
>> TSOP data is collected by 8 pic12f1822 (each 2 sensors are connected to a 12f1822)
All microcontrollers mentioned are connected by i2c to pic18f66k80(main chip).
main chip control dc motors by pwm method After processing the data
temtronic



Joined: 01 Jul 2010
Posts: 9093
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Jan 20, 2019 1:27 pm     Reply with quote

I counted 14 slave PICS connected to the Master PIC.
One potential problem is the actual I2C bus, depending on distance. Also 'motors' will need to be shielded to not generate any noise that the I2C bus might pickup as a signal.

I'd still prefer RS485, less chance of the bus 'hanging', better EMI protection, easy to be interrupt driven.

Jay
hamid9543



Joined: 31 Jan 2013
Posts: 63

View user's profile Send private message

PostPosted: Sun Feb 09, 2020 3:25 pm     Reply with quote

Hi
PCM PROGRAMER WROTE

Quote:

Suppose you have 3 i2c slave chips. Each slave could have an output
i/o pin that sends out a logic '1' when it's doing the task, and a logic '0'
when it's doing nothing (or has finished the task).

connect PIN_A0 slave to PIN_D0 master. When slave doing the task, state PIN_A0 is low and master don't read slave, but master always print "busy".

Master:
Code:

#include <18F452.h>
#use delay(xtal=20Mhz)
#use i2c(Master,sda=PIN_C4,scl=PIN_C3,fast,FORCE_HW)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

int8 data;

 void main()
 {   
 
    while(TRUE)
    {
    if(input(pin_d0)==1)
    {
          i2c_start();
          i2c_write(0x15);                // 0x14 ::
          int8 msb = i2c_read();      // Read MSB byte first.
          int8 lsb = i2c_read(0);     // Do a NACK on the last read
          i2c_stop();     
          printf("msb=%u , lsb=%u \r\n", msb , lsb);
    }
    else printf("Busy \r\n");
   }
}

and slave:
Code:

#include <12F1822.h>
#FUSES NOMCLR,NOWDT,NOPUT
#use delay(internal=32000000)
#use i2c(Slave,sda=PIN_A2,scl=PIN_A1,address=0x14)

#define busy    output_low(PIN_A0)
#define done    output_high(PIN_A0)
#define PULSE0   input(PIN_A5)
#define PULSE1   input(PIN_A3)

int   PULSEWITH[2],data[2],st[2];


#INT_SSP
void ssp_interrupt()
{
   int state = i2c_isr_state();
   
   if(state < 0x80)     // Master is sending data
   {
      i2c_read();
   }

   if(state >= 0x80)    // Master is requesting data from slave
   {
      i2c_write(data[state-0x80]);
   if(state==0x81) {busy;}
   }

}

void main()

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64|RTCC_8_bit);  // 1.024 ms
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);               //8.1 ms overflow
   delay_ms(5);
   setup_comparator(NC_NC);
   Setup_ccp1(CCP_OFF);
 
   enable_interrupts(INT_SSP);
   enable_interrupts(int_timer0);
   enable_interrupts(global);
   
   delay_ms(50);
   
   while(true)
   {
         st[0]=0;
         st[1]=0;
         
         set_timer0(0);

         while( (st[0]<3 || st[1]<3))   
         {
           
            if(PULSE0==1 && st[0]==0)  st[0]=1;
            else if(PULSE0==0 && st[0]==1) {set_timer0(0); st[0]=2;}
            else if(PULSE0==1 && st[0]==2) {PULSEWITH[0]=get_timer0(); st[0]=3;}
           
            if(PULSE1==1 && st[1]==0)  st[1]=1;
            else if(PULSE1==0 && st[1]==1) {set_timer1(0); st[1]=2;}
            else if(PULSE1==1 && st[1]==2) {PULSEWITH[1]=get_timer1()/32; st[1]=3;}
         }
         
         
         data[0]=PULSEWITH[0];
         data[1]=PULSEWITH[1]; 
         done;   
   }
}

Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Mon Feb 10, 2020 2:32 am     Reply with quote

You don't want to be using output_high & output_low for this.

At the start of the slave code, use:

output_low(PIN_A0);
output_float(PIN_A0);

Then have a pull up resistor on the line.
When you are 'busy', use 'output_drive(PIN_A0);' which will then pull the
pin low. When you are not busy, use 'output_float(PIN_A0);' which will
release it.

As written, as soon as it sees the slave is 'not busy', it sends a new
command making it busy again immediately. Is this what you actually want?.
temtronic



Joined: 01 Jul 2010
Posts: 9093
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Feb 10, 2020 6:23 am     Reply with quote

just a comment..

I'd have a 1 second delay in the master program BEFORE main() is executed to allow all the slaves time to powerup,setup and run their main() codes.
After that I might also have the master broadcast a 'run now' code to all the slaves.
You should have some type of code that allows for an orderly, known setup of the system.
hamid9543



Joined: 31 Jan 2013
Posts: 63

View user's profile Send private message

PostPosted: Tue Feb 11, 2020 1:11 am     Reply with quote

Ttelmah wrote:
You don't want to be using output_high & output_low for this.

At the start of the slave code, use:

output_low(PIN_A0);
output_float(PIN_A0);

Then have a pull up resistor on the line.
When you are 'busy', use 'output_drive(PIN_A0);' which will then pull the
pin low. When you are not busy, use 'output_float(PIN_A0);' which will
release it.

As written, as soon as it sees the slave is 'not busy', it sends a new
command making it busy again immediately. Is this what you actually want?.


I changed slave code as written below. and it works correctly. Thx.
Do you mean this? I want to know if there is any better solution ?

Code:

#include <12F1822.h>
#FUSES NOMCLR,NOWDT,NOPUT
#use delay(internal=32000000)
#use i2c(Slave,sda=PIN_A2,scl=PIN_A1,address=0x14)//0x12-0x14-0x16-0x18-0x1a-0x1c-0x1e-0x20

#define TSOP_OUT0   input(PIN_A5)
#define TSOP_OUT1   input(PIN_A3)

int1  OverFlow=0;
int   TSOP_time[2],data[4],st[2];


#INT_TIMER0
void t0_interr()
{
   OverFlow=1;
}

#INT_SSP
void ssp_interrupt()
{
   int state = i2c_isr_state();
   
   if(state < 0x80)     // Master is sending data
   {
      i2c_read();
   }

   if(state >= 0x80)    // Master is requesting data from slave
   {
      i2c_write(data[state-0x80]);
      if(state==0x81) {output_drive(PIN_A0);output_low(PIN_A0);delay_us(10);}
   }
}

void main()

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32|RTCC_8_bit);  // 1.024 ms
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);               //8.1 ms overflow
   delay_ms(5);
   setup_comparator(NC_NC);
   Setup_ccp1(CCP_OFF);
 
   enable_interrupts(INT_SSP);
   enable_interrupts(int_timer0);
   enable_interrupts(global); 
   delay_ms(50);
   
   while(true)
   {

         st[0]=0;
         st[1]=0;
         
         set_timer0(0);
         OverFlow=0;
         while( (st[0]<3 || st[1]<3) && OverFlow==0)   
         {
            if(TSOP_OUT0==1 && st[0]==0)  st[0]=1;
            else if(TSOP_OUT0==0 && st[0]==1) {set_timer0(0); st[0]=2;}
            else if(TSOP_OUT0==1 && st[0]==2) {TSOP_time[0]=get_timer0(); st[0]=3;}
           
            if(TSOP_OUT1==1 && st[1]==0)  st[1]=1;
            else if(TSOP_OUT1==0 && st[1]==1) {set_timer1(0); st[1]=2;}
            else if(TSOP_OUT1==1 && st[1]==2) {TSOP_time[1]=get_timer1()/32; st[1]=3;}
         }
         
         if(st[0]<3) TSOP_time[0]=254;
         if(st[1]<3) TSOP_time[1]=254;
         
         data[0]=TSOP_time[0];
         data[1]=TSOP_time[1];         
         output_float(PIN_A0);   
   }
}

Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Tue Feb 11, 2020 2:20 am     Reply with quote

Modified inline:
Code:

#include <12F1822.h>
#FUSES NOMCLR,NOWDT,NOPUT
#use delay(internal=32000000)
#use i2c(Slave,sda=PIN_A2,scl=PIN_A1,address=0x14)//0x12-0x14-0x16-0x18-0x1a-0x1c-0x1e-0x20

#define TSOP_OUT0   input(PIN_A5)
#define TSOP_OUT1   input(PIN_A3)

int1  OverFlow=0;
int   TSOP_time[2],data[4],st[2];


#INT_TIMER0
void t0_interr()
{
   OverFlow=1;
}

#INT_SSP
void ssp_interrupt()
{
   int state = i2c_isr_state();
   
   if(state < 0x80)     // Master is sending data
   {
      i2c_read();
   }

   if(state >= 0x80)    // Master is requesting data from slave
   {
      if(state==0x81) {output_drive(PIN_A0);}
      //Your shouldn't need the delay. All you need to do is turn on the
      //actual 'drive', since the latch is already programmed 'low'.
      i2c_write(data[state-0x80]);
   }
}

void main()
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32|RTCC_8_bit);  // 1.024 ms
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);               //8.1 ms overflow
   output_low(PIN_A0);
   output_float(PIN_A0); //This now programs the A0 output 'latch' low
   //but leaves the pin floating.

   delay_ms(5);
   setup_comparator(NC_NC);
   Setup_ccp1(CCP_OFF);
 
   enable_interrupts(INT_SSP);
   enable_interrupts(int_timer0);
   enable_interrupts(global);
   delay_ms(50);
   
   while(true)
   {

         st[0]=0;
         st[1]=0;
         
         set_timer0(0);
         OverFlow=0;
         while( (st[0]<3 || st[1]<3) && OverFlow==0)   
         {
            if(TSOP_OUT0==1 && st[0]==0)  st[0]=1;
            else if(TSOP_OUT0==0 && st[0]==1) {set_timer0(0); st[0]=2;}
            else if(TSOP_OUT0==1 && st[0]==2) {TSOP_time[0]=get_timer0(); st[0]=3;}
           
            if(TSOP_OUT1==1 && st[1]==0)  st[1]=1;
            else if(TSOP_OUT1==0 && st[1]==1) {set_timer1(0); st[1]=2;}
            else if(TSOP_OUT1==1 && st[1]==2) {TSOP_time[1]=get_timer1()/32; st[1]=3;}
         }
         
         if(st[0]<3) TSOP_time[0]=254;
         if(st[1]<3) TSOP_time[1]=254;
         
         data[0]=TSOP_time[0];
         data[1]=TSOP_time[1];         
         output_float(PIN_A0);   
   }
}


The key is you 'preload' the output latch with a '0'. Then turn off the
TRIS so the pin floats. When you want to signal that you are busy,
just re-enable the TRIS.
Did you find you needed the delay to allow the master to detect before
proceeding?. Look at where I do it instead. I set the bit 'back' to signal
the master _before_ I complete the I2C transaction. This should remove
the need for any delay.
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