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

[SOLVED]Problems to handle RS232 interrupts in CCS

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



Joined: 19 Jan 2013
Posts: 9

View user's profile Send private message

[SOLVED]Problems to handle RS232 interrupts in CCS
PostPosted: Sat Jan 19, 2013 9:51 pm     Reply with quote

Hiho, folks, is everybody ok?

I'm making a Track System using a GSM and GPS module, both controlled by a PIC18F4680. At the moment, I'm facing a big problem to handle the data that come through USART using the interrupt approach. I don't know why, but after enabling the RS232 receive data available (#INT_RDA) interrupt, the LCD stops working (lcd_putc or printf through LCD don't work) and the microcontroller seems to stuck in some part.

My code is below. If someone can help me with these problems, feel free for making changes in my code.

Thanks in advance,

Pedro Rosa.

P.S: The compiler used was CCS 4.130

main.c
Code:

#include <18f4680.H>
#include <defines.h>
#include <global.c>

#use delay(clock=16610000)
#fuses HS,NOWDT,NOPROTECT,NOLVP

#use rs232 ( baud=9600, xmit=PIN_C6, rcv=PIN_C7, stream=SIM900D, bits=8, ERRORS )
#use rs232 ( baud=9600, xmit=PIN_C5, stream=PK2, bits=8, ERRORS )

#include <flex_lcd.c>
#include <functions.c>

void main(){

   setup_timer_0(RTCC_OFF);               // Configuração do Timer0
   setup_timer_1(T1_DISABLED);               // Configuração do Timer1
   setup_timer_2(T2_DISABLED,0,1);           // Configuração do Timer2
   setup_ccp1(CCP_OFF);                      // Configuração do CCP1
   setup_comparator(NC_NC_NC_NC);            // Configuração dos Comparadores
   setup_vref(FALSE);                        // Configuração da Tensão de referência

lcd_init();

delay_ms(500);
fputs("ABCD",PK2);

enable_interrupts(GLOBAL);

inicializaPIC();

while(1){
   output_toggle(LED_VERMELHO);
   delay_ms(500);
}
}

defines.h
Code:

/*
Header destinado a DEFINES
*/

//#define LED_USART_GSM PIN_D2
//#define LED_BUTTON PIN_D1

/*LEDs para diagnóstico*/
#define LED_VERMELHO PIN_D0
#define LED_VERDE PIN_D2
#define LED_AMARELO PIN_D1

/*SIM900D*/
#define PPWR_SIM900D PIN_D3
#define PRX_SIM900D PIN_C7
#define PTX_SIM900D PIN_C6
#define SIM900_OK 1

/*UP501*/
#define PRX_UP501 PIN_C4 //Software USART

/*Celular*/
#define tamNumCelular 13 //Comprimento máximo do número do celular
#define posStatusCadastro 0 //Posi;áo que indica se há ou náo celular cadastrado
#define posInicialCelular 1 //Posição inicial para armazenar o celular
#define posFinalCelular (posInicialCelular + tamNumCelular - 1) //Posição final para armazenar o celular

/*EEPROM*/
#define OFFSET 0x0000

function.c
Code:

void inicializaPIC(){
   
   /*Alterna Leds para indicar inicialização*/
   output_high(LED_VERMELHO);
   delay_ms(1000);
   output_high(LED_VERDE);
   delay_ms(1000);
   output_high(LED_AMARELO);
   delay_ms(1000);   
   output_low(LED_AMARELO);
   delay_ms(1000);      
   output_low(LED_VERDE);
   delay_ms(1000);   
   output_low(LED_VERMELHO);   
   
   /*Carregar variáveis globais*/   
   temCelularCadastrado = getTemCelCadastrado();
   if(temCelularCadastrado == 'S'){
      numCel = getCelCadastrado();
   }
   else{
      output_high(LED_AMARELO);      
      /*Checar se a inicialização foi bem sucedida*/
      if(inicializaGSM() != SIM900_OK ){
         int16 stuckTime = 0;
         for(;;){
            /*LEDs piscando a cada 1s */
            output_toggle(LED_VERMELHO);
            output_toggle(LED_VERDE);
            output_toggle(LED_AMARELO);
            delay_ms(500);
            stuckTime++;
            /*Resetar o PIC após 60s*/
            if(stuckTime == 120){
               /*Desligar o SIM900D através do pino*/
               output_high(PPWR_SIM900D);
               delay_ms(2000);
               output_low(PPWR_SIM900D);
               reset_cpu();
            }
         }         
      }//Ao receber o SMS
      //+CMTI: "SM",2
      //posSMSRecebido = chegouSMS();               
   }   
}

int8 inicializaGSM(){
   int8 status = 0;
   output_high(LED_VERMELHO);
   delay_ms(2000);
   
   /*Ligar o SIM900D através do pino*/
   output_high(PPWR_SIM900D);
   delay_ms(2000);
   output_low(PPWR_SIM900D);
   /*--------------------------------*/
   
   /*Delay de 25s para sincronismo com a rede GSM*/
   delay_ms(25000);
   
   /*Checar se o SIM900D está conectado a rede*/
   status = isGSMOk();
   output_low(LED_VERMELHO);
   
   return status;      
}

int8 isGSMOk(){
   
   int8 USARTCarCounter=0;//Contador de caracteres recebidos na USART
   int8 msgCounter=0;//Contador de caracteres da mensagem de interesse
   char msg[9];//Tamanho máximo da mensagem de status (1\r\n\r\nOK\r\n)
   
   msg = "";//Garantir que não há lixo na variável
   output_high   (LED_VERMELHO);
   
   /*Desabilitar o Echo Mode: ATE0*/
   fputs("ATE0\r\n", SIM900D);
   delay_ms(1000);
   output_low(LED_VERMELHO);
   
   enable_interrupts(INT_RDA);
   
   /*AT+CCALR?: 0 = NOT READY; 1 = READY*/
   fputs("AT+CCALR?\r\n", SIM900D);
   
   delay_ms(500);
   
   for(;;){   
      if(interrupt == 1){
         if(USARTCarCounter > 9){
            msg[msgCounter] = caracterRecebido;
            msgCounter++;
            if(caracterRecebido == '\r'){
               disable_interrupts(INT_RDA);
               output_high(LED_AMARELO);
               return msg;   
            }
         }
         else if(caracterRecebido == headerStatusGSMVec[USARTCarCounter]){
            USARTCarCounter++;
            putc(USARTCarCounter, PK2);
           }
           interrupt=0;
           caracterRecebido = ' ';
      }
   }   
}

#INT_RDA
void RDA_isr(void){
   caracterRecebido = getc(SIM900D);
   interrupt=1;
   //putc(caracterRecebido, PK2);
}

P.S: The compiler used was CCS 4.130


Last edited by plateau on Wed Jan 23, 2013 5:02 pm; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19467

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 12:21 am     Reply with quote

The command to get a character from a stream, is fgetc, not getc.
getc defaults to getting from the last RS232 defined. So your interrupt hangs waiting for a character on the second stream.....

Best Wishes
plateau



Joined: 19 Jan 2013
Posts: 9

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 5:39 am     Reply with quote

Ttelmah wrote:
The command to get a character from a stream, is fgetc, not getc.
getc defaults to getting from the last RS232 defined. So your interrupt hangs waiting for a character on the second stream.....

Best Wishes


Thank you so much for having answered me, Ttelmah.

I've change the interrupt routine to:
Code:
#INT_RDA
void RDA_ISR(){
   caracterRecebido = fgetc(SIM900D);
   interrupt=1;
   //fputc(caracterRecebido,PK2);
   count++;
}

But it's still not working. A friend tells me to pay attention with the many delays at my main function. Do you agree with him?

One more time, thanks in advance.

Regards,

Pedro Rosa.

P.S: I don't know why, but if I get rid of the interrupt routine and use a loop with KBHIT, the code works. I think the problem is really the many delays across my code... but I don't know how to solve this.
Mike Walne



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

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 7:51 am     Reply with quote

What is not working?

Can you tell where it's stuck?

Try removing most of the functions, deal with the most important ones first. I.e. simplify what you're doing.

Mike
plateau



Joined: 19 Jan 2013
Posts: 9

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 8:10 am     Reply with quote

Mike Walne wrote:
What is not working?

Can you tell where it's stuck?

Try removing most of the functions, deal with the most important ones first. I.e. simplify what you're doing.

Mike


Hello, Mike.

After the second AT command (fputs("AT+CCALR?\r\n", SIM900D);), I don't know what happens but I never get correctly the message sent by SIM900D.

I've found some tricks at Google about implement a Circular Buffer but I don't know how to handle the break condition in the loop. Look at my code below.

Main.c

Code:
void main(){

   setup_timer_0(RTCC_OFF);               // Configuração do Timer0
   setup_timer_1(T1_DISABLED);               // Configuração do Timer1
   setup_timer_2(T2_DISABLED,0,1);           // Configuração do Timer2
   setup_ccp1(CCP_OFF);                      // Configuração do CCP1
   setup_comparator(NC_NC_NC_NC);            // Configuração dos Comparadores
   setup_vref(FALSE);                        // Configuração da Tensão de referência

//lcd_init();

delay_ms(500);
fputs("ABCD",PK2);

clear_interrupt(INT_RDA);

char var;

var = teste();

fputc(var,PK2);
}


Function.c
Code:
char* teste(){
   
   int8 USARTCarCounter=0;
   int8 msgCounter=0;
   char* msg;
   int control = 0, i=0;
   
   msg = "";//Garantir que não há lixo na variável
   
   /*Desabilitar o Echo Mode: ATE0*/
   fputs("ATE0\r\n", SIM900D);
   delay_us(1000);
   
   clear_interrupt(INT_RDA);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   
   /*AT+CCALR?: 0 = NOT READY; 1 = READY*/
   fputs("AT+CCALR?\r\n", SIM900D);
   set_timer0(0);
   do{
      interrupt = '0';
      delay_us(1000);
      output_toggle(LED_VERDE);      
   }while(count != 0 || get_timer0() < 2000);
   
   clear_interrupt(INT_RDA);
   disable_interrupts(INT_RDA);
   
//   for(i=0;i<control;i++)
//      fputc(msg[i], PK2);

   fprintf(PK2, "%d",count);
   return buffer[2];      
}


#INT_RDA
void SerialInt(){
   buffer[count]=fgetc(SIM900D);
   count++;
   if(count==BUFFER_SIZE)
      count=0;
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19467

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 8:13 am     Reply with quote

Look at ex_sisr.c
The delays don't particularly matter, provided you remember that as written, you only have 2mSec of buffering on this UART. Most GPS's once they are started, keep sending their data every second, so you will be missing huge amounts.
Is 'getTemCelCadastrado()' ever going to return 'S'?. Where is this reading from?. You haven't got an input pin defined on the second software UART (and remember this _will_ miss data unless it is sitting waiting for it.
I'd suspect this is your problem, rather than INT_RDA.

if(USARTCarCounter > 9){

Remember a 9 element array, has entries 0 to 8....

'msg', is a pointer to an array of characters, yet you return it as an int8.

Best Wishes
plateau



Joined: 19 Jan 2013
Posts: 9

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 8:27 am     Reply with quote

Ttelmah wrote:
Look at ex_sisr.c
The delays don't particularly matter, provided you remember that as written, you only have 2mSec of buffering on this UART. Most GPS's once they are started, keep sending their data every second, so you will be missing huge amounts.
Is 'getTemCelCadastrado()' ever going to return 'S'?. Where is this reading from?. You haven't got an input pin defined on the second software UART (and remember this _will_ miss data unless it is sitting waiting for it.
I'd suspect this is your problem, rather than INT_RDA.

if(USARTCarCounter > 9){

Remember a 9 element array, has entries 0 to 8....

'msg', is a pointer to an array of characters, yet you return it as an int8.

Best Wishes


HiHo, Ttelmah.

In the right moment I'm not using the GPS module (Fastrax UP501) because I still not got success with the GSM module (SIM900D). The function (getTemCelCadastrado()) checks if there is a mobile phone number stored on EEPROM. If so, the return is 'S', otherwise is 'N'. However, I get rid of these methods because I'm trying to implement a circular buffer to receive the message sent by SIM900D. Do you think it's possible?

Regards.
Mike Walne



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

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 10:19 am     Reply with quote

Do you know how much data you have to handle?

Like Ttelmah says EX_SISR.C shows how to implement a serial input buffer.

When I get stuck with comms I get a PC to play at being one end of the system. That way I've got more control over what's happening, and get the PC to act a diagnostic tool.

Not tried it, but see no reason why PC can't play at being two remote devices.

Mike
plateau



Joined: 19 Jan 2013
Posts: 9

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 10:47 am     Reply with quote

Mike Walne wrote:
Do you know how much data you have to handle?

Like Ttelmah says EX_SISR.C shows how to implement a serial input buffer.

When I get stuck with comms I get a PC to play at being one end of the system. That way I've got more control over what's happening, and get the PC to act a diagnostic tool.

Not tried it, but see no reason why PC can't play a being two remote devices.

Mike


HiHo, Mike!!!

I think the max length will be 200 characters for GSM strings.

In the moment, I'm getting rid of the interrupt approach and coming back to the KBHIT way until I see what I've done wrong. Now, my code is this below. It's not so brilliant but it works.

Code:

char* teste(){
   
   int8 USARTCarCounter=0;
   int8 msgCounter=0;
   char* msg;
   int control = 0, i=0;
   
   msg = "";//Garantir que não há lixo na variável
   
   /*Desabilitar o Echo Mode: ATE0*/
   fputs("ATE0\r\n", SIM900D);
   delay_ms(2000);
   
   /*AT+CCALR?: 0 = NOT READY; 1 = READY*/
   fputs("AT+CCALR?\r\n", SIM900D);
   while(1){
      output_toggle(LED_VERMELHO);
      if(kbhit()){
         caracterRecebido = fgetc(SIM900D);
         fputc(caracterRecebido, PK2);
         if(USARTCarCounter > 9){
            msg[msgCounter] = caracterRecebido;
            msgCounter++;
            if(caracterRecebido == '\r' || caracterRecebido == '\n'){
               output_high(LED_VERDE);
               return msg[0];
            }
         }
         else if(caracterRecebido == headerStatusGSMVec[USARTCarCounter]){
            USARTCarCounter++;
         }
      }
   }      
}

What I would wish to do is send the AT command (fputs("AT+CCALR?\r\n", SIM900D);) and then receive the answer using the interrupts. With the code above, I can do it without interrupts.

How can I modify EX_SISR.C for using in my case?

So sorry for many questions.

Regards,

Pedro Rosa.
Ttelmah



Joined: 11 Mar 2010
Posts: 19467

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 11:04 am     Reply with quote

kbhit -> bkbhit
getc -> bgetc

Modify the sisr code to use fgetc, where it uses getc

Best Wishes
plateau



Joined: 19 Jan 2013
Posts: 9

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 11:15 am     Reply with quote

Ttelmah wrote:
kbhit -> bkbhit
getc -> bgetc

Modify the sisr code to use fgetc, where it uses getc

Best Wishes


Ok dok, Sir! I'm going to lunch and I'll make these change later.

In my case, how can I break this loop in the end of the transmission?
Code:

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

Best regards,

Pedro Rosa!
Ttelmah



Joined: 11 Mar 2010
Posts: 19467

View user's profile Send private message

PostPosted: Sun Jan 20, 2013 11:24 am     Reply with quote

1) Get rid of the delays. Why do you need/want them at all....
2) bkbhit()
3) Commonest is that 'messages' will have some character that marks start/end. Look for this.
4) Alternatively, run a 'tick' in a timer interrupt, and limit how long you wait.

Best Wishes
plateau



Joined: 19 Jan 2013
Posts: 9

View user's profile Send private message

PostPosted: Wed Jan 23, 2013 4:58 pm     Reply with quote

HiHo, friends, are you all fine?

After so much problems in handling the interrupts, I've decided to use the KBHIT approach. Now, everything is ok but I have a doubt about dynamic memory use.

In my code, I have a pair of routines to write and read data from EEPROM. Both are based on native CCS EEPROM routines.

The read routine is:
Code:

char* leStringEEPROM(int8 low, int8 high){
   //char* texto = calloc((high-low),sizeof(char));
   char texto[12];
   int8 i,y=0;   
   
   for(i=low;i<high;i++){
      texto[y] = (char)read_int16_eeprom(i);
      y++;
   }
   return texto;
}

I don't know why, but this routine only works well when I declare the variable 'TEXTO' as a static length array. When I use the dynamic array associated with calloc, the array TEXTO always returns with wrong length (per example, if the right length would be 10, it returns 12).

Can anybody help me to solve this issue?

Regards,

Pedro Rosa.
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