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

BIG problem with Serial interrupt

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



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

BIG problem with Serial interrupt
PostPosted: Mon May 05, 2014 4:29 pm     Reply with quote

Hi everyone! I have a big problem with serial interrupt (#INT_RDA) because my program enter in this interrupt the first time but don't enter the second time.

I don't know if the problem is the version of CCS (v4.140) or the MPLAB (v8.87). I use the CCS compiler with the MPLAB.

In the simulation the program seems ok but in the practice is strange.

I use an Arduino Due that sends to the PIC a data like this ("$ADQ,P01,CH1\r") and the PIC that I use is the 16F88 that responds to Arduino. The power supply of the 16f88 is 3,3 because Arduino due works 3.3V.

This is my code. If there are something bad responds me please I need a lot of help with this :(

Is not necessary check all code, only the serial interrupt part and the fuses.

THANKS!!

Code:
#include <16f88.h>
#device ADC=10

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT, INTRC_IO
#use delay (internal=8MHz)
#use RS232(UART1)         


//**VARIABLES PARA GESTIONAR LA TRAMA RECIBIDA Y LA TRAMA A ENVIAR POR PUERTO SERIE**//

long valor_adc=0; //Variable para lectura ADC

int P_W=0; //puntero escritura
int P_R=0; //puntero lectura

int i=0; //puntero bucle for
int j=0;

int inicio=0;
int final=0;

char string_valor_adc[]="0000";//Cadena de caracteres para guardar valor ADC en Carcteres
char trama_entrada[91]={0}; //String para guardar el dato de entrada por UART

char direccion_pic[]="P01";
char tipo_dato[]="$ADQ";
char canal[]="CH0";
char dato[]="$ADQ,P01,CH0\r";
char datomio[]="$ADQ,P01,CH1,3333\r";

char miretorno[]="\r";
char misimbolo[]="$";

short flag_final=0;
short flag_permiso=0;
short flag_tst=0;
short flag_envio=0;


void lectura(){

 for(P_R=0; P_R<91; P_R++){

  if(trama_entrada[P_R]==misimbolo[0]){

  inicio=P_R;
 
  for(P_R=inicio; P_R<91; P_R++){
 
   if(trama_entrada[P_R]==miretorno[0]){

   P_W=0;
   final=P_R;
   flag_permiso=1;
   break;

    }
 
   }
   break;
  }

 }

}


void escritura(){

for(i=inicio; i<=final; i++){
dato[j]=trama_entrada[i];
j++;
}
i=0;
j=0;

for(i=0;i<91;i++){
trama_entrada[i]='\0';
}


return;
}


void procesamiento(){

for(i=0; i<3; i++){
direccion_pic[i]=dato[i+5];
}


direccion_pic[3]='\0';


if(strcmp(direccion_pic, (char*)"P01")==0){

for(i=0;i<3;i++){
direccion_pic[i]='\0';
}


for(i=0; i<4; i++){
tipo_dato[i]=dato[i];
}

tipo_dato[4]='\0';


if(strcmp(tipo_dato, (char*)"$ADQ")==0){
for(i=0;i<4;i++){
tipo_dato[i]='\0';
}

flag_tst=0;

for(i=0; i<3; i++){
canal[i]=dato[i+9];
}

canal[3]='\0';


if(strcmp(canal,(char*)"CH0")==0){

 set_adc_channel(0); 
   }
 
 
   else if(strcmp(canal,(char*)"CH1")==0){
     
      set_adc_channel(1);
   }

 
delay_us(20);//retardo para leer ADC
valor_adc=read_adc();//lectura ADC

 }

else if(strcmp(tipo_dato,(char*)"TST")==0){

for(i=0;i<4;i++){
tipo_dato[i]='\0';
}

flag_tst=1;

}
flag_envio=1;
}
return;
}


void enviar(){

switch(flag_tst){

case 0:

   sprintf(string_valor_adc,"%04ld",valor_adc);

   output_high(PIN_B0);
   printf("$ADQ,P01,%s,%s\r", canal,string_valor_adc);
   output_low(PIN_B0);
   
     

   for(i=0;i<4;i++){
   string_valor_adc[i]='\0';
   }
   for(i=0;i<3;i++){
   canal[i]='\0';
   }

    break;


case 1:

output_high(PIN_B0);
printf("$TST,P01\r");
output_low(PIN_B0);
flag_tst=0;



break;

}
return;
}



void main(){
output_low(PIN_B3);
output_low(PIN_B0);

disable_interrupts(INT_RDA);
enable_interrupts(GLOBAL); //HABIlLITO TODAS LAS INTERRUPCIONES GLOBALES
enable_interrupts(INT_RDA); //HABILITO LA INTERRUPCIÓN UART
setup_adc_ports(sAN0|sAN1|sAN2|sAN3|sAN4|sAN5); //INDICO EL PIN A0/A1/A2/A3/A4/A5 COMO ENTRADA ANALÓGICA
setup_adc(ADC_CLOCK_INTERNAL); //CLOCK INTERNO PARA CONVERSIÓN ADC

 while(1){

if(flag_final==1){
flag_final=0;
 lectura();

if(flag_permiso==1){
 flag_permiso=0;
 escritura();
 procesamiento();
if(flag_envio==1){
flag_envio=0;
enviar();
}
  }
 }
}

}


#INT_RDA

void INT_UART(void) {
trama_entrada[P_W]=getc();
if(trama_entrada[P_W]=='\r'){
P_W=0;
flag_final=1;
}

else{
P_W++;
}

}




Smile


Last edited by Salfer on Mon May 05, 2014 4:59 pm; edited 1 time in total
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon May 05, 2014 4:55 pm     Reply with quote

try removing this line from your handler

clear_interrupt(INT_RDA);

the CCS code does it FOR you at the end of the function

also you might try to test that the pointer in the handler does not let the fill pointer P_W go beyond say 89 decimal into trama_entrada[]

AND even consider filling the whole array with zeros - not just the first element
at INIT time.


Last edited by asmboy on Mon May 05, 2014 4:59 pm; edited 1 time in total
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Mon May 05, 2014 4:58 pm     Reply with quote

asmboy wrote:
try removing this line from your handler

clear_interrupt(INT_RDA);

the CCS code does it FOR you at the end of the function



OK but the program continue without work :( I'm very worried I have done all
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Mon May 05, 2014 5:06 pm     Reply with quote

asmboy wrote:
try removing this line from your handler

clear_interrupt(INT_RDA);

the CCS code does it FOR you at the end of the function

also you might try to test that the pointer in the handler does not let the fill pointer P_W go beyond say 89 decimal into trama_entrada[]

AND even consider filling the whole array with zeros - not just the first element
at INIT time.


Ok I will consider it. A lor of Thanks!! but the programs continue without enter in the INT_RDA I don't know what is the problem.
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Mon May 05, 2014 5:27 pm     Reply with quote

Hi,

At a minimum add 'errors' to your #use rs232 directive. This has been discussed a million ( or more!) times on the forum.....

John
Ttelmah



Joined: 11 Mar 2010
Posts: 19540

View user's profile Send private message

PostPosted: Tue May 06, 2014 12:43 am     Reply with quote

Several other comments though:

Code:

#include <16f88.h>
#device ADC=10
#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT, INTRC_IO
#use delay (internal=8MHz)
#use RS232(UART1, ERRORS)         

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

The fuse an clock defines must _always_ be in front of anything that uses them. This includes things like stdio....

ERRORS already mentioned.

I suspect you have one of the compiler versions that is disabling GIE when printf is used. Do a search here. This was a problem that appeared, was fixed, then appeared again, and was eventually fixed around 5.012ish. This would explain your problem.

As a general comment, avoid using names like 'long', and 'short'. These have different meanings on different chips. Be explicit. Include 'stdint.h', and use types like uint8_t, which say exactly what you are using, and will work whatever chip is involved. It's a problem 'waiting to happen'.

As a further comment, add size testing on your buffer variable. You may 'expect' that a carriage return will arrive before the buffer overflows, but in only needs to be missed once, for the code to destroy other variables, and crash.

Then read the data sheet. Is ADC_CLOCK_INTERNAL recommended at your clock rate....

I suspect the GIE problem is the 'killer' at present, but think about a bit of redefinition for the future.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue May 06, 2014 3:45 am     Reply with quote

Then a few comments on coding style:
- Please check the formatting of your code. It is now difficult to read because indentation for the lines is using different styles and sizes everywhere.
- Please use defines instead of hard coded values. For example you have the magic value '91' in many places where you mean the size of one of the arrays. Add something like
Code:
#define RECEIVE_ARRAY_SIZE   91
at the top of your program.
Same applies to the I/O pins. Compare these two:
Code:
output_low(PIN_B0);

#define LED    PIN_B0
output_low(LED);

- Use the standard C functions whenever possible to create more efficient and easier to read programs:
Code:
for(i=0;i<91;i++){
trama_entrada[i]='\0';
}
can be replaced by:
Code:
memset(trama_entrada, 0, sizeof(trama_entrada));
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Tue May 06, 2014 5:12 am     Reply with quote

Ttelmah wrote:
Several other comments though:

Code:

#include <16f88.h>
#device ADC=10
#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT, INTRC_IO
#use delay (internal=8MHz)
#use RS232(UART1, ERRORS)         

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

The fuse an clock defines must _always_ be in front of anything that uses them. This includes things like stdio....

ERRORS already mentioned.

I suspect you have one of the compiler versions that is disabling GIE when printf is used. Do a search here. This was a problem that appeared, was fixed, then appeared again, and was eventually fixed around 5.012ish. This would explain your problem.

As a general comment, avoid using names like 'long', and 'short'. These have different meanings on different chips. Be explicit. Include 'stdint.h', and use types like uint8_t, which say exactly what you are using, and will work whatever chip is involved. It's a problem 'waiting to happen'.

As a further comment, add size testing on your buffer variable. You may 'expect' that a carriage return will arrive before the buffer overflows, but in only needs to be missed once, for the code to destroy other variables, and crash.

Then read the data sheet. Is ADC_CLOCK_INTERNAL recommended at your clock rate....

I suspect the GIE problem is the 'killer' at present, but think about a bit of redefinition for the future.



Ttelmah YES. The problem is the PRINTF. When I use PRINTF for send the data by USART the program can enter ONLY one time. But when I use PUTC for send the data by USART the program CAN enter again in the INT_RDA, but now the program can enter ONLY four times in INT_RDA.

What is the problem? The PIC16F88 could be the problem?

And the last cuestion: If I have installed CCS v5.012 I shouldn't have problems with PRINTF no?

Thanks
Smile Smile
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Tue May 06, 2014 5:16 am     Reply with quote

ckielstra wrote:
Then a few comments on coding style:
- Please check the formatting of your code. It is now difficult to read because indentation for the lines is using different styles and sizes everywhere.
- Please use defines instead of hard coded values. For example you have the magic value '91' in many places where you mean the size of one of the arrays. Add something like
Code:
#define RECEIVE_ARRAY_SIZE   91
at the top of your program.
Same applies to the I/O pins. Compare these two:
Code:
output_low(PIN_B0);

#define LED    PIN_B0
output_low(LED);

- Use the standard C functions whenever possible to create more efficient and easier to read programs:
Code:
for(i=0;i<91;i++){
trama_entrada[i]='\0';
}
can be replaced by:
Code:
memset(trama_entrada, 0, sizeof(trama_entrada));


Thanks I will change it in my program later. I need improve my programing. But The big problem now is that I don' know why my program work bad.
Ttelmah



Joined: 11 Mar 2010
Posts: 19540

View user's profile Send private message

PostPosted: Tue May 06, 2014 6:45 am     Reply with quote

I suggest you 'revector' the print.

Code as:
Code:

void putc_gie(char chr)
{
   putc(chr);
   enable_interrupts(GLOBAL);
}


//then where you printf
   printf(putc_gie,"what you want to print");


As I said, if you search the forum, you will find this problem being discussed. I remember it as being an issue with 4.140, hence my guess as to what happens. Problem is that the compiler disables the GIE when doing a table access, but then forgets it needs to be 'on', if waiting to receive data while sending. Encapsulating the putc, ensures that the interrupt gets re-enabled between the characters.
drh



Joined: 12 Jul 2004
Posts: 192
Location: Hemet, California USA

View user's profile Send private message

PostPosted: Tue May 06, 2014 7:45 am     Reply with quote

Quote:

#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT, INTRC_IO
#use delay (internal=8MHz)
#use RS232(UART1)


Which are you using, a xtal or the internal osc.?
Specify one or the other, not both.
_________________
David
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Tue May 06, 2014 1:27 pm     Reply with quote

drh wrote:
Quote:

#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT, INTRC_IO
#use delay (internal=8MHz)
#use RS232(UART1)


Which are you using, a xtal or the internal osc.?
Specify one or the other, not both.


Now I will change it Smile Thanks. (I will use internal clock)
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Tue May 06, 2014 3:37 pm     Reply with quote

Ttelmah wrote:
I suggest you 'revector' the print.

Code as:
Code:

void putc_gie(char chr)
{
   putc(chr);
   enable_interrupts(GLOBAL);
}


//then where you printf
   printf(putc_gie,"what you want to print");


As I said, if you search the forum, you will find this problem being discussed. I remember it as being an issue with 4.140, hence my guess as to what happens. Problem is that the compiler disables the GIE when doing a table access, but then forgets it needs to be 'on', if waiting to receive data while sending. Encapsulating the putc, ensures that the interrupt gets re-enabled between the characters.



If I need send by serial port a data like this:

data[19]="$ADQ,P01,CH1,3333\r";


The part of the code that sends by serial port is it. It is correct?. It seems that this part works OK but ONLY follow print by serial port FOUR TIMES the data. What is the problem now? I am using an Arduino that reads this data.

(The INT_RDA works OK because the led that I programing show it)

Is the problem the model of the pic (16f88)? buffers USART full? I don't know

Quote:
for(i=0;i<19;i++){
putc(data[i]);
enable_interrupts(GLOBAL);
}



Other cuestion is... when my program print by serial port the data that I want see the value of ADC not change. Is the same in the four times that get see the data that I print by serial port. Is necessary clear the bit activation of the ADC when I read its value?

Thanks. Sad Sad
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Wed May 07, 2014 4:12 am     Reply with quote

The problem was the version. If I use CCS 5.015 code works OK. But the value of ADC not change. I need clear de adc before read adc?
Salfer



Joined: 20 Mar 2014
Posts: 15

View user's profile Send private message

PostPosted: Thu May 08, 2014 2:34 am     Reply with quote

The code now works OK. I installed a new version of CCS and redefined the variables and the code now works ok. Thanks everyone.
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