|
|
View previous topic :: View next topic |
Author |
Message |
hamid9543
Joined: 31 Jan 2013 Posts: 63
|
|
Posted: Sun Jan 20, 2019 9:31 am |
|
|
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: 9113 Location: Greensville,Ontario
|
|
Posted: Sun Jan 20, 2019 1:27 pm |
|
|
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
|
|
Posted: Sun Feb 09, 2020 3:25 pm |
|
|
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: 19225
|
|
Posted: Mon Feb 10, 2020 2:32 am |
|
|
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: 9113 Location: Greensville,Ontario
|
|
Posted: Mon Feb 10, 2020 6:23 am |
|
|
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
|
|
Posted: Tue Feb 11, 2020 1:11 am |
|
|
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: 19225
|
|
Posted: Tue Feb 11, 2020 2:20 am |
|
|
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. |
|
|
|
|
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
|