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

Problems with RS232. Strange behavior

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



Joined: 28 Oct 2010
Posts: 7

View user's profile Send private message

Problems with RS232. Strange behavior
PostPosted: Thu Oct 28, 2010 9:26 am     Reply with quote

Hi, I have a question.
I am working with the PIC16F876A (4 MHz). The pic reads data from various analog sources through adc_read function () and send to PC via RS-232. So far so good.
The program also allows the PC to send commands to the PIC, using interrupt #int_rda and its associated function. Here's the problem. The function I use is (The PC sends a string, for example "1345 \ n". The first digit is the command and the rest is the value of-mult-):

This function does not work, get blocked:

Code:
void MyFunction
{
  char inst;
  float mult;
  char s[20];
  inst = getc ();            // reads the first character is the command to execute (0-9)

    get_string (s, 10);   // read the string that indicates the value
    mult = atof (s)        // converts the string to float value corresponding

}



But this function operates normally:

Code:
void MyFunction
{
  char inst;
  float mult;
  char s[20];
  inst = getc ();             // reads the first character is the command to execute (0-9)
  if (inst> 10) {            //always TRUE in this case
    get_string (s, 10);   // read the string that indicates the value
    mult = atof (s)        // converts the string to float value corresponding
  }
}


It seems that by including the function get_string () inside a block-if-, or perhaps use the variable -inst- in that condition, makes it run the rest of the reading of the line. I do not know.


Although I have little time with microcontroller programming, I program (C, Java, VBasic, Pascal ..) for many years and this behavior does not respond to anything that I can understand


Please appreciate all the help you can provide, especially to understand the logic of the processes of this behavior. Maybe will be a compiler problem?

best regards
pmuldoon



Joined: 26 Sep 2003
Posts: 218
Location: Northern Indiana

View user's profile Send private message

PostPosted: Thu Oct 28, 2010 12:37 pm     Reply with quote

just a quick guess but I think you made the assumption that instr is always > 10.
Isn't /n actually two chars; 0x0d, 0x0a.
I don't know what get_string() is but CCS has a gets() which terminates on the RETURN (0x0d) character which would leave the 0x0a yet to be read.

Could that be the problem?
by saying
Code:

if (inst> 10)

you would discard the extra character.
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Thu Oct 28, 2010 12:44 pm     Reply with quote

Well it matters little which language since all have to have a way of knowing when a string ends. In C strings are null terminated. get string expects this to be true. If your string isn't null terminated then it is terminated some other way maybe CR or LF or both. It that is true then you alone using getc will have to assemble your string and when you get to your terminator you will replace it with a null so you are in compliance with what C expects.
Now since broken clocks show the right time twice per day so broken code will will occasionally work in special circumstances.
pmuldoon



Joined: 26 Sep 2003
Posts: 218
Location: Northern Indiana

View user's profile Send private message

PostPosted: Thu Oct 28, 2010 1:07 pm     Reply with quote

char s[20]; may be initialized to zero by the compiler, that would guarantee a zero terminator when you load a shorter string into the array.

if you send "1345 \n" the quotes will zero terminate the string being sent also.

I have a digital clock, and it's never right. Even when it's broken!
(but some of my broken code has worked surprisingly well...for a while.)
biomo



Joined: 28 Oct 2010
Posts: 7

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 1:53 am     Reply with quote

Thank you for your interest.
I do not think the problem is the character string. Function get_string () is a function that comes with the examples of CCS in the file input.c. This function runs a reading loop with getc () until you find the ascii value '13 'or until the maximum number of characters to read. The function gets() have the same behavior in this case.
The problem is that if the process of reading is within a conditional block (always true in this case and only to force the execution of the instructions) is executed correctly and if it is outside of the conditional block is not executed, which is out of structured programming logic.
Could be a bug in the conversion from C to ASM ? In my short time in PIC programming, this is not the only gap that meeting between what does and what it should do, but I could go around solving the situations. But if this is very often maybe I'll have to change compiler. The problem is not that work differently, the problem is I do not know how it works, and I can not predict their behavior (at the programming level, of course).
temtronic



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

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 5:13 am     Reply with quote

Perhaps the best thing to do is create the smallest program that has both functions in it,compile then dump the listing to see the assembler .
Now you can see ,line by line, what it's doing(or not),
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 5:21 am     Reply with quote

The compiler does not normally zero arrays or any vars for that matter.

gets and get_string will read input until a <cr> char(13) 0x0D is read, they will then discard the 0x0D and null terminate the string and return.
get_string should also only read upto the number of chars specified and then null terminate the string and return.

The problem possibly with this is when you are doing the check
if (inst > 10)
you are making sure that you have the start of your data before reading the string, when you are not doing the check any random char will be read and the program will move on to the get_string.

Taken from the help file
Code:

atof
"Converts the string passed to the function into a floating point representation. If the result cannot be represented, the behavior is undefined."

If you do get other data comming in and atof fails then this may be why it is hannging.

"1345\n" the char '\n' is normally a NewLine char 0x0A, NOT a <cr>
but it could expand to \r\n depending on what is doing the outputting.
try
"1345\r"
pmuldoon



Joined: 26 Sep 2003
Posts: 218
Location: Northern Indiana

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 6:10 am     Reply with quote

perhaps just add something to discard any potential garbage .

Code:

while((inst = getch())<'0');
biomo



Joined: 28 Oct 2010
Posts: 7

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 7:20 am     Reply with quote

Quote:
The problem possibly with this is when you are doing the check
if (inst > 10)
you are making sure that you have the start of your data before reading the string, when you are not doing the check any random char will be read and the program will move on to the get_string.


I also thought that, but does not work as I show later.

The discusion about the end of the string, I say that I send in all posibilities with Java and ended in "\n", with Visual Basic append chr(13) and/or chr(10), etc.. In deed, the program works in the initial condition. I aswell send via wire, via bluetooth. I don´t think that the problem is in the send process.


To focus, the complete program, that work good, is as follows:

Code:

#include <16F876A.h>
#include <ctype.h>
#include <stdlib.h>

#device adc=10  //propone una resolución de 10 bits (0-1023)

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES LP                       //Low power osc < 200 khz
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES WRT_50%                  //Lower half of Program Memory is Write Protected

#fuses NOPROTECT,NOCPD,NOLVP,NOWDT,XT

#use fast_io (A) //no rehace el puerto cada vez que envía
#use fast_io (C) //no rehace el puerto cada vez que envía
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

// FUNCTION GET_STRING OF INPUNT.C  ++++++++++++++++++++++++
void get_string(char* s, int max) {
   int len;
   char c;

   --max;
   len=0;
   do {
     c=getc();
     if(c==8) {  // Backspace
        if(len>0) {
          len--;
          }
     } else if ((c>=' ')&&(c<='~'))
       if(len<=max) {
         s[len++]=c;
       }
   } while(c!=13);
 
  s[len]=0;
}

// THE PROGRAM  ++++++++++++++++++++++++++++++++++++++++++++++
float mult=5;
char s[20];

#int_rda   //INTERUPTION OF UART
void MyIntFunction()
// THIS FUNCTION RUN. WITH THE STRING SEND VIA RS-232 BY THE PC, TAKE THE FIRST CARACTER AND PUT IT IN inst, THEN TAKE THE REST OF DE STRING AND PUT IT IN THE s VARIABLE.
{   
  char inst;
  int k;
  inst=0;
  for (k=0;k<20;k++){s[k]=0;}
  inst=getc(); //lee un caracter -> comando
  if (inst>10) {
    get_string(s,10);     // lee un string y con una longitud máxima de 10
    mult=atof(s);       //convierte la cadena en su valor float correspondiente
    delay_us(10);       //espera 10 usegundos, no es necesario.   
 }
}

int16 ReadADC(int Puerto){
      set_adc_channel (Puerto);        //Selección del canal 0 (RA0)
      delay_us (20);                   //Temporiza 0.01s
      read_adc(ADC_START_ONLY);        //Inicia la conversión
      delay_ms(1);                    //Se asegura que se ha terminado la conversión AD
      return read_adc (ADC_READ_ONLY); //Lee el resultado de la última conversión
}

int16 resultado0,resultado1;      //Variable para el resultado de la conversión AD
float resultmV0=0.00;
float resultmV1=0.00;


void main()
{
   set_tris_c (0b10111101);      //RC7 -> Rx IN, RC6 -> Tx OUT, RC1-> ANOTHER OUT PIN (NO PROBLEM)
   enable_interrupts(INT_RDA);   //Activa interrupción en la recepción
   enable_interrupts(global);    //Habilita interrupciones

   //setup_adc_ports
   setup_adc (ADC_CLOCK_DIV_32); //Define la frecuencia del muestreo analógico
   setup_adc_ports (ALL_ANALOG); //Todas entradas analógica
 
   WHILE (1)
   {
     
      resultado0=LeerADC(0);  //LEE EL PIN A0
      resultado1=LeerADC(1);  //LEE EL PIN A1
     
      //RECALCULA Y LO ENVIA AL PUERTO SERIE
      resultmV0 = ((float)resultado0) / 1023*mult;
      resultmV1 = ((float)resultado1) / 1023*5;
      printf ("s:%s A0: %04Lu, A1: %04Lu, A0(mV): %5.3f,A1(mV): %5.3f ,mult:%3.3f \n", s, resultado0, resultado1, resultmV0,resultmV1,mult);
   }
}



functions MyIntFunction() like following are wrong (seem to get blocked waiting, but what?):

Code:
void MyIntFunction()
{   
  char inst;
  int k;
  inst=0;
  for (k=0;k<20;k++){s[k]=0;}
  inst=getc();             //lee un caracter -> comando
  if (inst>10) {k=1;}  //TO INITIALIZE THE inst VARIABLE
    get_string(s,10);     // lee un string y con una longitud máxima de 10
    mult=atof(s);       //convierte la cadena en su valor float correspondiente
    delay_us(10);       //espera 10 usegundos, no es necesario.   
 }
}


Code:
void MyIntFunction()   //SIMPLEST
{   
     get_string(s,10);     // lee un string y con una longitud máxima de 10
 }
}
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Fri Oct 29, 2010 8:17 am     Reply with quote

Things to know
The rda interrupt is called every time for each and every character (byte) that is received.
An RS232 character inbound to your code can arrive at anytime in the middle of a calculation. middle of a line of code at anytime. The RDA routine must catch the character place it in memory and with as little extra code as is possible transfer control to the main routine so it is ready for the next character to arrive.
Things to never do
Never put delays in interrupt routines like #int rda
Never put floating point operations in an isr.
Never put printf in an isr.
Things to do
For a GPS interface always use a circular buffer. The GPS will send a sentence. Always parse the sentence in main
Ideas
Often only a specific sentence is needed so it is acceptable to select for the sentence as it comes in. Suppose its $abcde then set a start of sentence flag when the isr sees $ if the next char isn't 'a' then clear it
if still set and the next char isn't 'b' then clear it and so on. These are fast compares and even though there are many lines in the isr only a few are actually executed. If the sentence flag remains move the sentence into the circular buffer and set a sentence end flag. Main will see the end flag and start parsing while the circular buffer accepts the next sentence.
There are others way to do rs232 but few work as reliably as the circular buffer.
Many knowing an isr processes one byte at a time don't use get_string or any routine that will wait for more than one char.
Except for the simplest of situations RS232 needs the isr and the isr needs the circular buffer to be fully successful.
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 8:41 am     Reply with quote

Does the output from printf for mult mach what you are sending it ?

The only thing I can think of is that in the working code get_string is never called because inst is always <= 10.

This would mean the data you are sending is either wrong or corrupt.

If the printf matches then you know get_string is recieving the correct chars.

And what Douglas said stands about what you should not do in sir routines!
biomo



Joined: 28 Oct 2010
Posts: 7

View user's profile Send private message

PostPosted: Sat Oct 30, 2010 2:42 am     Reply with quote

Thank for all,

Douglas, I will probe your recommendations.

if I undertand well, this maybe a program

Code:
byte s[20];
int cont=0;

# Int_rda / / INTERRUPCIÓN DE UART
void MyIntFunction ()
{   
  byte c; 
  c=getc();
  if ((c=="$") || (s[0]=="$" ) {
    s[cont]=c;
    cont=cont+1;
  }
}

And in Main
Code:
  Comand=MyParseFunction(s);                     // My function that parse de string command
  if (Command=1) then {........; MyClear(s);} //execute the comand 1 and clear de string command
  if (Command=2) then {........; MyClear(s);} /execute the comand 2 and clear de string command
   
   ....

  if (Command=-1) then {MyClear(s);}        //The command don't exist and clear the string commad (MyClear(s) put all items of s to 0 and put the cont=0)



Or more simple alternate...

Code:
int1 Ismessage=0;

# Int_rda / / INTERRUPCIÓN DE UART
void MyIntFunction ()
{   
  Ismessage=1;
}

And In Main
Code:
If (Ismessage) {get_string(s,10);Ismessage=0}
Comand=MyParseFunction(s);
......
......
......




I'll probe this and I´ll say you the results
biomo



Joined: 28 Oct 2010
Posts: 7

View user's profile Send private message

PostPosted: Sat Oct 30, 2010 6:08 am     Reply with quote

I found the answer. It is similar to the proposed Douglas with a buffered reading and management in the Main. Forgetting of the functions get_string () and gets (), which, in the end, are the ones that block the reception.

The answer you can see at (in spanish, sorry):
http://www.todopic.com.ar/foros/index.php?PHPSESSID=ce6a0a91c9835a53397bb2ad634182bb&topic=4573.0

Thank you for all and best regards
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