|
|
View previous topic :: View next topic |
Author |
Message |
jartur32
Joined: 24 Feb 2014 Posts: 10
|
I2C with 16f1503 slave received string problem (SOLVED) |
Posted: Mon Feb 24, 2014 12:26 am |
|
|
Hi all
I'm having a problems when using I2C in one project.
In my project, I receive a data string[9] from i2c, but not how to get the string complete. only i get the first char
I used PIC18F2550 master and 16f1503 slave
Thank so much !
Master send code 18f2550
Code: |
void i2c_communication(unsigned int8 opc, byte stream,char string_i2c[9])
{
i2c_start(); // begin transmission
i2c_write(stream); // select address of device to communicate with
for (int8 j = 0; j < strlen(string_i2c); j++) // for
i2c_write(string_i2c[j]); // send actual data
i2c_stop(); // terminate communication
}
|
Slave received code 16f1503
Code: |
const int8 lenbuff_string_i2c = 9;
char string_i2c[lenbuff_string_i2c] = {'\0','\0','\0','\0','\0','\0','\0','\0','\0'};
#INT_SSP
void ssp_interrupt()
{
temp = i2c_isr_state();
if(temp<0x80)//Master send data
{
temp = i2c_read();//An array will be needed to store data if more than one byte is transferred
string_i2c[cont_i2c_data] = temp;
cont_i2c_data++;
}
else
if(temp==0x80)//Master requested data
{
//i2c_write (buffer[address]); //send requested data
}
}
|
Last edited by jartur32 on Mon Feb 24, 2014 9:51 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19511
|
|
Posted: Mon Feb 24, 2014 2:56 am |
|
|
Several things here:
First the master.
Now a function receiving a string, would not normally declare the length. The whole point is that the code adjusts to suit the length of the 'string' being passed. Remember that a string like "hellofred", is actually ten characters long, not nine characters. This could potentially be dangerous, given your buffer size at the receiver.
Now 'strlen', returns the number of characters in the string _excluding the terminating null_. Ideally you want to send the null as well (Otherwise there will be problems if a string is shorter than the last one sent). Currently if you send a 9 character string, you have no terminator left at the receiver.... How is the string being sent declared?.
Ideally write the transmission function to compare the strlen to one _less_ than the receive buffer size, and if it is above this value, just send this many characters, and flag an error. This is where careful programming comes in....
Now, then the slave. The buffer here should be large enough to include the terminating null. Then when the state==0, the count (cont_i2c_data), needs to be reset to zero, and the character thrown away. This is the address byte, not a character of the string....
Currently there is a problem since you potentially overwrite all the characters, if your transmitted 'string' is 9 characters long, there is then not a null terminator character in the array...
ideally make the array a one character larger, and send the null terminator from the master.
If you do start writing back, you need to remember that on state==0x80, the byte must be _read_ before you write back, while on states higher than 0x80, you can just write.
Have you verified your bus is actually working _first_. Use the example, as a receiver, and write a byte, and read it back. |
|
|
jartur32
Joined: 24 Feb 2014 Posts: 10
|
|
Posted: Mon Feb 24, 2014 8:22 am |
|
|
Hi Thank Ttelmah
Seven (7) is the maximum length of the string being passed and the master code sends all the string correctly, as seen at the image at the output with my logic analyzer.
http://galeon.com/tbz/analyzer.jpg
The problem is to get that string, I do not know how to get the string. in my code initiating counter to 0, only I get to receive the first character correctly but no more than that
At this moment i don't need start writing back to the master, later i see this problem
Thank |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19511
|
|
Posted: Mon Feb 24, 2014 8:56 am |
|
|
The point is that you are not sending the null, and this is needed. Otherwise as I said, if the string is shorter than the last one sent, things will go problematical, and when the isr_state=0, you need to throw the character received away, and reset the counter. So:
Code: |
void i2c_communication(unsigned int8 opc, byte stream,char * string_i2c)
{
i2c_start(); // begin transmission
i2c_write(stream); // select address of device to communicate with
for (int8 j = 0; j <= strlen(string_i2c); j++) // for
i2c_write(string_i2c[j]); // send actual data
i2c_stop(); // terminate communication
}
|
Code: |
#define I2C_BUFF_LEN 9; //This uses no storage
char string_i2c[lI2C_BUFF_LEN];
int1 have_string=FALSE;
#INT_SSP
void ssp_interrupt(void)
{
char state,temp;
state = i2c_isr_state();
if(state<0x80)//Master send data
{
temp = i2c_read();
if (state==0)
cont_i2c_data=0; //here need to read but not store
else
{
string_i2c[cont_i2c_data++] = temp;
if (temp==0)
have_string=TRUE;
}
}
else
{
if(temp==0x80);
temp=i2c_read(); //here character must be read
i2c_write (string_i2c[cont_i2c_data++]); //send requested data
}
}
//Then in the main, only read the string when 'have_string' goes TRUE,
//and immediately reset it to FALSE;
|
Note that the string is not available, till the 'have_string' flag goes TRUE. |
|
|
jartur32
Joined: 24 Feb 2014 Posts: 10
|
|
Posted: Mon Feb 24, 2014 9:50 am |
|
|
Thank Ttelmah
The problem is solved.
string sent image (logic analyzer)
http://galeon.com/tbz/Untitled.jpg
Final Master send code 18f2550 (Part of code)
Code: |
// I2C config//
#define SDA_PIN PIN_B0
#define SCL_PIN PIN_B1
#use I2C(MASTER, SDA=SDA_PIN, SCL=SCL_PIN, FORCE_HW, FAST)
//0x14 slave 1
//0xA0 slave 2
#define lenbuff_string_i2c_temp 10
char cadena_i2c_temp[lenbuff_string_i2c_temp];
// I2C comunicacion //
void i2c_communication(byte stream, char *string_i2c)
{
i2c_start(); // begin transmission
i2c_write(stream); // select address of device to communicate with
for (int8 j = 0; j <= strlen(string_i2c); j++) // for
i2c_write(string_i2c[j]); // send actual data
i2c_stop(); // terminate communication
}
// MAIN //
void main ()
{
Init();
delay_ms(300);
strcpy(string_i2c_temp,"V|20.0|%");
i2c_comunicacion(0XA0,string_i2c_temp);
do{
}while(TRUE); // while
}
|
Final Slave received code 16f1503 (Part of code)
Code: |
// I2C //
#define SCL_i2c PIN_C0
#define SDA_i2c PIN_C1
#USE I2C(SLAVE, sda=SDA_i2c, scl=SCL_i2c, ADDRESS=0xA0, FORCE_HW, FAST)
char state,temp;
unsigned int8 count_i2c_data = 0;
#define lenbuff_string_i2c 10
char string_i2c[lenbuff_string_i2c];
#INT_SSP
void ssp_interrupt()
{
state = i2c_isr_state();
if(state<0x80)//Master envia datos
{
temp = i2c_read();//An array will be needed to store data if more than one byte is transferred
if (state==0)
count_i2c_data=0; //here need to read but not store
else
{
string_i2c[count_i2c_data++] = temp;
if (temp==0)
FLAG_have_string=TRUE;
}
}
else
{
/*if(temp==0x80)//Master pide datos
temp=i2c_read(); //here character must be read
i2c_write (string_i2c[count_i2c_data++]); //send requested data */
}
}
|
thanks for everything |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19511
|
|
Posted: Mon Feb 24, 2014 2:40 pm |
|
|
As one little minor 'comment', you will notice I made the temp and state variables local. You have made them global. It is better practice to _only_ make variables global, when they have to be. This way variables used inside routines won't conflict with things used in other routines.
Worth changing your style a little.
Best Wishes |
|
|
|
|
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
|