|
|
View previous topic :: View next topic |
Author |
Message |
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
I2C Communication problems between 2 PIC's |
Posted: Thu Mar 08, 2007 8:29 am |
|
|
I am currently trying to get two Pic 18F452's to send data back and forth between each other through an I2C connection. I have wired then together, pulling the SDA and SCL wires up to +5V through 1K resistors. I have both Pic's connected through serial connections to the computer, and the master displays "Outputting: 66" and the slave displays "Running." If anybody has had experience with this task, please let me know. I have tried the code pointed to in another forum with the EX_SLAVE.c program unsuccessfully. Here is the code I am using:
Master
Code: | #include <protoalone_1.h>
#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3, SLOW)
main()
{
int8 i2c_command = 66;
while (true)
{
delay_ms(1000);
printf("Outputting: %d\n\r", i2c_command);
/* Master */
i2c_start(); // Start condition
i2c_write(0xa0); // Device address
i2c_write(i2c_command); // Write Command
i2c_stop(); // Stop condition
}
} |
Slave
Code: | #include <protoalone_1.h>
/* Setup I2C */
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0, SLOW, FORCE_HW)
#INT_SSP
void ssp_interupt ()
{
byte incoming;
incoming = i2c_read();
printf("\n\rRead byte 1: %d\n\r", incoming);
incoming = i2c_read();
printf("Read byte 2: %x\n\r\n\r", incoming);
}
main()
{
delay_ms(250);
printf("Running\n\r");
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while (true)
{
}
}
|
and the protoalone_1.h code:
Code: | #include <18f452.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOOSCSEN //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV20 //Brownout reset at 2.0V
#FUSES NOPUT //No Power Up Timer
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOCPD //No EE protection
#FUSES NOCPB //No Boot Block code protection
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#use delay (clock=20000000)
#define GREEN_LED PIN_A5
#define YELLOW_LED PIN_B4
#define RED_LED PIN_B5
#define PUSH_BUTTON PIN_A4
#define delay_seconds(x) delay_ms(x*1000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8) |
Thank you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 08, 2007 12:11 pm |
|
|
Put the Ex_Slave.c program into your slave PIC.
Use the code in this post for your Master PIC:
http://www.ccsinfo.com/forum/viewtopic.php?t=28097&start=9
This will provide a test environment that should work.
Also make sure you have a ground connection between the
the two PIC boards.
If you can't make the setup above work, then post your compiler version. |
|
|
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
Still Having Problems |
Posted: Mon Mar 12, 2007 6:28 am |
|
|
I have tried both the programs I have posted here and the programs you suggested, and I cannot seem to get the PIC's to communicate. I tried using different pins just in case it was a pin problem, but I still am not able to get the PIC's to talk. I am using compiler version 3.223, but am actually using DIP chips of the PIC now instead of the prototype boards. I have established communication between both PIC's and the DS1631 I2C temperature sensor that came with the PIC prototype board. I am using the MPLAB IDE program to program the PIC's, but the PIC C Compiler does sucessfully compile the programs I am using also. If you have any suggestions, I would appreciate any guidance you can provide. Thank you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Mar 12, 2007 9:14 am |
|
|
Quote: | I tried using different pins just in case it was a pin problem, |
Ex_Slave must use the hardware i2c pins. |
|
|
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
Success, new problem |
Posted: Tue Mar 13, 2007 12:03 pm |
|
|
I actually managed to figure out the I2C communications between 2 pics. I then expanded that to 3 PICs and got one to send characters. I am trying to transmit a float variable over the I2C, but have not been successful. I will post the master code, and for the slave, I am just using the EX_SLAVE.c program. This program does not correctly transmit the float, but does transmit the character to the other slave PIC. I am probably just missing something simple. If you have a moment, please look over this code and let me know what I am doing wrong. Thank you.
Code: | #include <18F452.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, SDA=PIN_C4, SCL=PIN_C3)
//====================================
void main()
{
int8 data; //int8
int32 data_float;
float data_1, i;
char j;
i=1;
j='Z';
while(1){
// Write to the slave 1 board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write(i);
i2c_stop();
delay_ms(200);
//Write to the slave 2 board.
i2c_start();
i2c_write(0xB0);
i2c_write(0x00);
i2c_write(j);
i2c_stop();
delay_ms(200);
// Read from the slave 1 board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
data_float = i2c_read(0);
i2c_stop();
data_1=data_float;
printf("read from 1: %u \n\r", data_1); //also tried %c and %f
delay_ms (200);
//Read from the slave 2 board and display the data.
i2c_start();
i2c_write(0xB0);
i2c_write(0x00);
i2c_start();
i2c_write(0xB1);
data = i2c_read(0);
i2c_stop();
printf("read from 2: %c \n\r\n\r", data);
delay_ms (200);
i=i+1;
j--;
}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 13, 2007 12:10 pm |
|
|
Look at this article in the CCS FAQ:
Quote: | Compiler Behavior
What is the format of floating point numbers? |
http://www.ccsinfo.com/faq.php |
|
|
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
|
Posted: Tue Mar 13, 2007 12:21 pm |
|
|
I understand that a floating point variable uses a 4 byte size, I just don't know how to send 4 bytes over the I2C as one number. I am assuming the error in the code is in the writing and reading of the variable over I2C, but I don't know how to go about sending it as a group of 4 related bytes. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue Mar 13, 2007 12:36 pm |
|
|
You can only send one byte at a time. You'll have to split it up and send four i2c_write() commands and then re-assemble the bytes at the receiving end.
Ronald |
|
|
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
|
Posted: Tue Mar 13, 2007 12:37 pm |
|
|
how do you go about splitting it and re-assembling it? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 13, 2007 1:02 pm |
|
|
There are several threads on this. Here's one of them:
http://www.ccsinfo.com/forum/viewtopic.php?t=24074&highlight=float+union
This CCS FAQ article has some code to split a float.
http://www.ccsinfo.com/faq.php?page=write_eeprom_not_byte
Unfortunately, it's no longer functional after vs. 4.021, where
they made this change:
Quote: | 4.021 The & unary operator by default no longer returns a generic (int8 *) |
To fix it, you have to cast the address of the floating point data
to a byte pointer, as shown in bold below.
Quote: |
WRITE_FLOAT_EXT_EEPROM(long int n, float data) {
int i;
for (i = 0; i < 4; i++)
write_ext_eeprom(i + n, *((int8*)&data + i) ) ;
}
float READ_FLOAT_EXT_EEPROM(long int n) {
int i;
float data;
for (i = 0; i < 4; i++)
*((int8*)&data + i) = read_ext_eeprom(i + n);
return(data);
} |
|
|
|
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
|
Posted: Thu Mar 15, 2007 7:05 am |
|
|
OK, so I attempted to apply that to what I am doing with the I2C communications between the PICs. I am just trying to see if it works by sending a 1 and seeing what it sends back. I recieve a -.000000 and don't know why. I assume it has something to do with how I am pointing to the memory locations to send them and then reading them. I will post the code I have now, but be advised, I have sections commented out that are about converting 32 bit ints to 8 bit and sending them, but this does not work with floats. If someone with more expertise in the pointer field could give me a hand, I would appreciate it. And by the way, thank you PCM Programmer for your help so far.
Code: | #include <18F452.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, SDA=PIN_C4, SCL=PIN_C3)
//====================================
/*
I2C_WRITE_FLOAT(long int n, float data) {
int i;
i = 0;
i2c_start(); // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x00);// Low byte of command
i2c_write((int8*)&data + i)); // High byte of command
i2c_stop(); // Stop condition
i = 1;
i2c_start(); // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(*((int8*)&data + i) )); // High byte of command
i2c_stop(); // Stop condition
i=2;
i2c_start(); // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x02);// Low byte of command
i2c_write(*((int8*)&data + i) )); // High byte of command
i2c_stop(); // Stop condition
i=3;
i2c_start(); // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x03);// Low byte of command
i2c_write(*((int8*)&data + i) )); // High byte of command
i2c_stop(); // Stop condition
}
//-------------------------------------
float READ_FLOAT_EXT_EEPROM(long int n) {
int i;
float data;
for (i = 0; i < 4; i++)
*((int8*)&data + i) = read_ext_eeprom(i + n);
return(data);
}
*/
//=====================================
void main()
{
//int8 f0, f1, f2, f3, g0, g1, g2, g3; //int8 for int32 conversion
int8 data_1;
float i, data, data_read;
char j;
data=1;
j='Z';
while(1){
/*//Convert 32 bit int to 1 byte ints.
f3 = MAKE8(i,3);
f2 = make8(i,2);
f1 = make8(i,1);
f0 = make8(i,0);
*/
// Write float to the slave 1 board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write(*(&data+0));
i2c_write(0x01);
i2c_write(*(&data+1));
i2c_write(0x02);
i2c_write(*(&data+2));
i2c_write(0x03);
i2c_write(*(&data+3));
i2c_stop();
delay_ms(200);
//Write to the slave 2 board.
i2c_start();
i2c_write(0xB0);
i2c_write(0x00);
i2c_write(j);
i2c_stop();
delay_ms(200);
// Read float bytes from the slave 1 board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
*(&data_read+0) = i2c_read(0);
*(&data_read+1) = i2c_read(1);
*(&data_read+2) = i2c_read(2);
*(&data_read+3) = i2c_read(3);
i2c_stop();
//data_1=make32(g0, g1, g2, g3); For reassembling int32
printf("read from 1: %f \n\r", data_read); //also tried %c and %f
delay_ms (200);
//Read from the slave 2 board and display the data.
i2c_start();
i2c_write(0xB0);
i2c_write(0x00);
i2c_start();
i2c_write(0xB1);
data_1 = i2c_read(0);
i2c_stop();
printf("read from 2: %c \n\r\n\r", data_1);
delay_ms (200);
//i=i+1;
j--;
}
}
|
Thank you |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 15, 2007 11:37 am |
|
|
Quote: | i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
*(&data_read+0) = i2c_read(0);
*(&data_read+1) = i2c_read(1);
*(&data_read+2) = i2c_read(2);
*(&data_read+3) = i2c_read(3);
i2c_stop(); |
This is not the correct way to read sequential bytes. The i2c_read()
function doesn't take an address. The parameter can be either a
0 or a 1.
1 -- means to do an "ACK". (acknowledge)
0 -- means to do a "NAK" (no acknowledge)
In the i2c protocol, the last read operation must do a NAK.
The read operations prior to the last one must do ACKs.
Also, to do an ACK, you don't have to supply the 1. It's understood
to be a 1 if you don't put in a parameter.
So delete all the parameters in that group of four i2c_read() statements,
except for the last one, and give it a parameter of 0. |
|
|
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
|
Posted: Thu Mar 15, 2007 12:26 pm |
|
|
OK, so here is the story. I tried to take the numbers out and put only a zero in the last i2c_read, but now the program just freezes and does not output anything. I did research this a bit, and tried to use the i2c_poll function with no success. Here is the modified section of code I tried with no luck:
Code: | // Read float bytes from the slave 1 board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
*(&data_read+0) = i2c_read();
*(&data_read+1) = i2c_read();
*(&data_read+2) = i2c_read();
*(&data_read+3) = i2c_read(0);
i2c_stop();
printf("read from 1: %f \n\r", data_read); //also tried %c and %f
delay_ms (200); |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 15, 2007 12:36 pm |
|
|
What I would do is:
1. Forget trying to send and receive floats (for now).
Get it working with just sending, receiving, and displaying
four sequential bytes (such as 0x01, 0x02, 0x03, 0x04).
Don't even involve floats in any way in the testing.
2. Don't add tests to talk to a 2nd Slave PIC when the primary
problem hasn't been solved yet. Remove all code that talks
to the 2nd slave and remove the hardware for the 2nd slave.
Strip everything down to essentials and solve the main problem. |
|
|
bestbuylvr
Joined: 31 Jan 2007 Posts: 27 Location: Pittsburgh, PA
|
|
Posted: Thu Mar 15, 2007 12:48 pm |
|
|
Is the method I'm using to write the data correct? |
|
|
|
|
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
|