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

I2C with 16f1503 slave received string problem (SOLVED)

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jartur32



Joined: 24 Feb 2014
Posts: 10

View user's profile Send private message

I2C with 16f1503 slave received string problem (SOLVED)
PostPosted: Mon Feb 24, 2014 12:26 am     Reply with quote

Hi all Very Happy
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: 19238

View user's profile Send private message

PostPosted: Mon Feb 24, 2014 2:56 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Feb 24, 2014 8:22 am     Reply with quote

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: 19238

View user's profile Send private message

PostPosted: Mon Feb 24, 2014 8:56 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Feb 24, 2014 9:50 am     Reply with quote

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: 19238

View user's profile Send private message

PostPosted: Mon Feb 24, 2014 2:40 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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