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 CCS Technical Support

Send received data to array

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



Joined: 08 Mar 2012
Posts: 38
Location: Canada

View user's profile Send private message

Send received data to array
PostPosted: Thu Mar 29, 2012 7:52 pm     Reply with quote

Hey everyone,

I am using the example code provided by ccs EX_SISR.c

Code:

/////////////////////////////////////////////////////////////////////////
////                          EX_SISR.C                              ////
////                                                                 ////
- Deleted -

+++++++++++++++++++++++++++
Code removed.
Reason: see forum Rule #10:
http://www.ccsinfo.com/forum/viewtopic.php?t=26245
- Forum Moderator
+++++++++++++++++++++++++++


I am not sure how to :

1. Put received data into an array
2. Read data on array

Here is the code that I have written so far. It display's some data on the LCD screen but they are all "giberish" symbols.

What the code does is.
1. Initialises the lcd
2. Powers on the microconroller that is transmitting data
3. Receive and display data.

Code:

/***********************************************************/
/************************ Project 2 ************************/
/******************** OBDII Interpreter ********************/

/********** Included Files ***********/
#include <main.h>
#include "D:\Winter_2012\Project_2\Project2_LCD_Driver.c"

/********** Required Registers **********/
#byte TRISA = 0x85

/********** Required Bits **********/
#bit A5 = 0x5.5 // Used to power on ELM323

/********** Declared Variables **********/
char received;
int interrupt_flag;
int interrupt_flag2;
int i;
int j;

/********** Declared Array's **********/
int received_data[24]; //16F877A data Array

#int_rda
void serial_isr() {
   int t;

   buffer[next_in]=getc();
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)
     next_in=t;           // Buffer full !!
}

#define bkbhit (next_in!=next_out)

BYTE bgetc() {
   BYTE c;

   while(!bkbhit) ;
   c=buffer[next_out];
   next_out=(next_out+1) % BUFFER_SIZE;
   return(c);
}

void main()
{
   enable_interrupts(int_rda);
   #if defined(__PCD__)
   enable_interrupts(intr_global);
   #else
   enable_interrupts(global);
   #endif

interrupt_flag2 = 0;

While(interrupt_flag2 ==0)
   {
   LCD_init(); // Initialize LCD
   set_disp_add_first_line();//set display address first line
   interrupt_flag2 = 1;
   }
delay_ms(5000);
TRISA = 0x00; // Set Pot D as outputs
A5 = 1; // Turns on ELM323
i = 0;
j = 0;


while(bkbhit)
   { 
      For (i = 0; i<=24; i++)// increments i
      {
      received_data[i] = bgetc(); // saves received bytes to the array
      }
   }
      For (j = 0; j<=24; j++)// increments j
      {
      text_string(received_data[j]);// reads characters from array and sends to lcd.
      }   

}


Also, I set my buffer size to 8.
Code:

#define BUFFER_SIZE 8
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;

I am not sure how this has affected anything since its purpose is unclear to me. But I am guessing the buffer_size would be the size of the element in my array (in my case 8 bits)?

Also on this note, in my main code that I just posted, will this code be putting a single bit into the received_data array or will it be placing all the bits that are in the buffer in the array?
Code:

received_data[i] = bgetc();


Thanks!
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Fri Mar 30, 2012 1:51 am     Reply with quote

No.
Buffer size, is the number of _characters_ of buffer generated.

The key to SISR, is understanding a 'circular buffer'. The buffer _is_ an array 'BUFFER_SIZE' characters long. However instead of being used as a 'linear' array, where the first character is at address '0', then the second at address '1' etc.. it is treated like a circular running track.

Think of the array numbers, as referring to segments round the track. '0' being at the start line, then '1' is the first corner, '2' the second half of this bend, 3 & 4 are the two halves of the back straight, 5 & 6, the bend at the other end of the track, and '7' the main straight coming back to the start line.

The racing event is run like a 'hare & hounds' race, but with bits of paper left in each segment of the track, each with a character written on them. So when a character is received, then it's bit of paper goes into part '0' of the track, and the competitor advances to part '1'. Next character received goes into '1', and the competitor advances to '2'. Where the character is going to go, is the 'next_in' value. This is the 'hare'.

The second competitor (the hound), then starts 'chasing' the first, picking up the bits of paper as they go. So they pick up the piece of paper in section '0' of the track, and advance to section 1. This is the 'next_out' counter. If 'next_out' matches the value in 'next_in', then the hare has caught up, and no more characters are waiting to be read. Key difference to the linear array is the way the two addresses 'chase' each other round the circuit. If you get to the start line (end of sector '7'), then the next part of the circuit, is sector '0' again.

Now if the hound catches the hare, this is 'buffer empty', no more characters waiting. All the bits of paper have been picked up. If the hare catches the hound, this is 'buffer full'. All eight locations round the 'lap', have pieces of paper waiting to be picked up (there then has to be a decision what to do - common solution is to start throwing the oldest bits of paper away....).
So 'bkbhit', simply tests if the hare has caught the hound.

Now some slightly more technical comments:

CCS, handle the situation at the end of the lap - where the counters go from 7, potentially to '8' on our imaginary circuit, using '%'. The % operator, gives the _remainder_ from an integer division. So 8/8 has a remainder of '0', giving us correctly the '0' location back at the start of the lap. Problem with this is how it is calculated. The '%' operator, for a _binary multiple of 1_ (1,2,4,8,16,32,64 etc..), can be solved by a single mathematical '&' operation, so is efficient. So _provided the buffer size chosen is one of these sizes_, the code will work well. Just half a dozen machine instructions. Problem is if you choose a buffer size that is _not_ such a size. Solving (for example) 12%12, requires 113 machine instructions!. This also results in using code in the interrupt that may cause interrupts to be disabled in the main code. It is unfortunately, a case of the CCS example being 'badly written'...

The 'better' solution, is to simply use:

if (next_in==BUFFER_SIZE) next_in=0;

Which effectively says 'if runner has finished lap, start a new lap', and works whatever 'buffer size' is chosen.

Now, the data is already in an array. If you want to wait for 24 characters to arrive, then make your buffer array larger than this (say 32 characters), and test for how many characters are waiting. This is coded as:
Code:

int num_in_buff; //need to enlarge this if buffer>128 chars

num_in_buff = next_in-next_out;
if (num_in_buff>=BUFFER_SIZE) num_in_buff=BUFFER_SIZE+num_in_buff;


So you could just wait till 'num_in_buff' >=24, and then display this, or output this. Currently you are going to your routine when just one character has arrived, then waiting for the remaining 23, basically throwing away the 'point' of buffering the data.

Best Wishes
wordizlife



Joined: 08 Mar 2012
Posts: 38
Location: Canada

View user's profile Send private message

How to read received data
PostPosted: Fri Mar 30, 2012 9:08 am     Reply with quote

Perfect thank you for that explanation, cleared up a lot of things Smile

Once I have waited for all the expected characters to be received, how would I read the data that is in the array and for example send it to an LCD or to my pc serial port with the printf() function?
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

Reading array
PostPosted: Sun Apr 01, 2012 7:52 am     Reply with quote

Ttelmah has just explained it.

He's shown you how to get your data into the array, and how to keep track of data taken out.

The two indicees "next_in" and "next_out" are doing it for you.

CCS provides samples which show you how to write to LCD and PC.

Mike
wordizlife



Joined: 08 Mar 2012
Posts: 38
Location: Canada

View user's profile Send private message

reading array data
PostPosted: Sun Apr 01, 2012 12:49 pm     Reply with quote

Yea sorry about that I got confused for a while there.
So using the information that Ttelmah gave my main code now looks like this but does not display anything..
What could be the source of the problem?
Code:

/********** Included Files ***********/
#include <main.h>
#include "D:\Winter_2012\Project_2\Project2_LCD_Driver.c"

/********** Required Registers **********/
#byte TRISA = 0x85

/********** Required Bits **********/
#bit A5 = 0x5.5 // Used to power on ELM323

/********** Declared Variables **********/
char received;
int interrupt_flag;
int interrupt_flag2;
int i;
int j;
int lcd_data;
int num_in_buff;
BYTE c;
BYTE received_data;



#int_rda
void serial_isr() {
   int t;

   buffer[next_in]=getc();
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)
     next_in=t;           // Buffer full !!
}

#define bkbhit (next_in!=next_out)

BYTE bgetc() {

   while(!bkbhit) ;
   c=buffer[next_out];
   next_out=(next_out+1) % BUFFER_SIZE;
   return(c);
}

void main()
{
   enable_interrupts(int_rda);
   #if defined(__PCD__)
   enable_interrupts(intr_global);
   #else
   enable_interrupts(global);
   #endif

interrupt_flag2 = 0;

While(interrupt_flag2 ==0)
   {
   LCD_init(); // Initialize LCD
   set_disp_add_first_line();//set display address first line
   interrupt_flag2 = 1;
   }
delay_ms(5000);
TRISA = 0x00; // Set Pot D as outputs
A5 = 1; // Turns on ELM323
i = 0;
j = 0;

While(1)
{
   num_in_buff = next_in-next_out;
   if (next_in==BUFFER_SIZE) next_in=0;

   If (num_in_buff>=8)
   {
      For (i = 0; i <= 8; i++)
      {
      received_data = buffer[i];
      text_string(received_data); // sends received_data to lcd
      }
   }
}
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Sun Apr 01, 2012 1:00 pm     Reply with quote

You don't show your declaration for buffer. My comments about the size apply, if this is not a binary multiple.

Much better to get rid of the % throughout and use the test as already outlined.

Then your calculation won't work. The 'point' is that because of the circular nature of the buffer 'next_out', can be _less_ than 'next_in', when next_in has effectively passed the finishing line. This is why I showed how to calculate the 'num_in_buff'. I subtract the values, and then if the value has wrapped (a lap has taken place), offset the number to give the required result.

Best Wishes
wordizlife



Joined: 08 Mar 2012
Posts: 38
Location: Canada

View user's profile Send private message

PostPosted: Sun Apr 01, 2012 1:35 pm     Reply with quote

Here is my buffer declaration:
Code:

#if defined(__PCM__)
#include <16F877A.h>
#device adc=16


#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOPROTECT

#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,ERRORS)

#endif

#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;


Modified main code:
Code:


/********** Included Files ***********/
#include <main.h>
#include "D:\Winter_2012\Project_2\Project2_LCD_Driver.c"

/********** Required Registers **********/
#byte TRISA = 0x85

/********** Required Bits **********/
#bit A5 = 0x5.5 // Used to power on ELM323

/********** Declared Variables **********/
char received;
int interrupt_flag;
int interrupt_flag2;
int i;
int j;
int lcd_data;
int num_in_buff;
BYTE c;
BYTE received_data;



#int_rda
void serial_isr() {
   int t;

   buffer[next_in]=getc();
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)
     next_in=t;           // Buffer full !!
}

#define bkbhit (next_in!=next_out)

BYTE bgetc() {

   while(!bkbhit) ;
   c=buffer[next_out];
   next_out=(next_out+1) % BUFFER_SIZE;
   return(c);
}

void main()
{
   enable_interrupts(int_rda);
   #if defined(__PCD__)
   enable_interrupts(intr_global);
   #else
   enable_interrupts(global);
   #endif

interrupt_flag2 = 0;

While(interrupt_flag2 ==0)
   {
   LCD_init(); // Initialize LCD
   set_disp_add_first_line();//set display address first line
   interrupt_flag2 = 1;
   }
delay_ms(5000);
TRISA = 0x00; // Set Pot D as outputs
A5 = 1; // Turns on ELM323
i = 0;
j = 0;

While(bkbhit)
{
   num_in_buff = next_in-next_out;
   if (num_in_buff>=BUFFER_SIZE) num_in_buff=BUFFER_SIZE+num_in_buff;

   If (num_in_buff>=8)
   {
      For (i = 0; i <= 8; i++)
      {
      received_data = buffer[i];// reads data in array
      text_string(received_data); // display data from array
      }
   }
}
}

So If I understand correctly if the size is 32 I don't need any of this code?:
Code:

  num_in_buff = next_in-next_out;
   if (num_in_buff>=BUFFER_SIZE) num_in_buff=BUFFER_SIZE+num_in_buff;


I am not sure what size I should be setting my buffer too since the amount of data being received will vary so I just set it to a size 32 to be safe.
wordizlife



Joined: 08 Mar 2012
Posts: 38
Location: Canada

View user's profile Send private message

PostPosted: Mon Apr 02, 2012 1:17 pm     Reply with quote

Using the CCS Example file as reference to get the incoming data and display it to my lcd. Here is the example file:
Code:

   printf("\r\n\Running...\r\n");

               // The program will delay for 10 seconds and then display
               // any data that came in during the 10 second delay

   do {
      delay_ms(10000);
      printf("\r\nBuffered data => ");
      while(bkbhit)
        putc( bgetc() );
   } while (TRUE);

My question is when say:
Quote:

// The program will delay for 10 seconds and then display
// any data that came in during the 10 second delay

Does that mean that the program will display ALL of the data that was received or only one byte? I have modified this code to send data to my lcd screen without any success...
Code:

 do { 
    while(bkbhit)
    text_string( bgetc() );
    }while(TRUE);
temtronic



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

View user's profile Send private message

PostPosted: Mon Apr 02, 2012 2:59 pm     Reply with quote

...
while(bkbhit)
putc( bgetc() );


...

It displays everything.. that is sent in the 10 seconds.

While...

bkbhit is true( ie. next_in does not equal next_out)
get a buffered character(the function bgectc() and then put that character onto the local console using the function putc().


text_string( bgetc() );
I suspect you may have a problem in your coding of 'text_string' as the CCS example does work.


hth
wordizlife



Joined: 08 Mar 2012
Posts: 38
Location: Canada

View user's profile Send private message

PostPosted: Tue Apr 03, 2012 1:56 pm     Reply with quote

If I test my LCD code with this for example:

Code:

text_string("hello");


The header file works fine and displays hello on my LCD.

Here is my text_string function:
Code:

 void text_string(char string1)
      {
      LCD_RS = 1;
      send_nibbles(string1);
      }

void send_nibbles(int data_val)
         {
         set_lcd_pins(data_val&0xf0);
         delay_ms(10);
         set_lcd_pins((data_val&0x0f)<<4);
         delay_ms(10);
         }
void set_lcd_pins(int data_val)
         {
         
         if( data_val & 0x80) LCD_D7=1; else LCD_D7=0;
         if( data_val & 0x40) LCD_D6=1; else LCD_D6=0;
         if( data_val & 0x20) LCD_D5=1; else LCD_D5=0;
         if( data_val & 0x10) LCD_D4=1; else LCD_D4=0;
         pulse();
         }

Is there anything wrong with that for this code not to work?:
Code:

 do { 
    while(bkbhit)
    text_string( bgetc() );
    }while(1);
}
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