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 interrupts

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







problems with interrupts
PostPosted: Wed Dec 13, 2006 12:50 am     Reply with quote

Hi everyone

I hope every one is doing ok

I am try to use both 'INT_RDA' (serial interrupt) and 'INT_EXT' (external interrupt) in the same code and i seem to be having some problems. I have tried 'INT_RDA' and 'INT_EXT' separately(i.e in separate codes) and they both work fine. This rules out any hardware problem. In the code posted below, a stepper motor should move until an interrupt comes but when i include the line 'enable_interrupts(INT_RDA);' even the motor does not move. I was wondering if there is a bug in the compiler or something. The
compiler version is 3.249. here is the code (i have not included all the defined variable):

Code:

#include <16F877A.h>
#device *=16
#include <stdlib.h>
#include <string.h>
#include <24512.c> //for the atmel eeprom
#include <math.h>
#USE DELAY (CLOCK=20000000)
#fuses  HS,NOWDT,NOLVP
#use rs232(baud=19200,xmit=pin_c4,rcv=pin_c5,parity=N,stream=pc)
#use rs232(baud=19200,xmit=pin_c2,rcv=pin_c3,parity=N,stream=con2)
#use rs232(baud=19200,xmit=pin_d6,rcv=pin_d7,parity=N,stream=sensor)// i have changed this
#use rs232(baud=19200,xmit=PIN_C6,rcv=PIN_C7,ERRORS,stream=special)  //this will be used for serial interrupt


//----------------------------------------

int cpos = 30;  //this is the initialized value
int apos = 20;  //this is the initialized value


void decidecw();
void decideacw();
void movecw();
void moveacw();


#INT_RDA
void serial_isr()
{
   command[0] = fgetc(special);

   command[1] = fgetc(special);

   command[2] = fgetc(special);

   command[3] = fgetc(special);

   command[4] = '\0';

   if(command[0] == 'S' && command[3] == 'P')  //means that 'STOP' received
   {
      decideacw();

      factor = 2;
   }

}


#INT_EXT   // External interrupt
void ext_isr()
{
   factor = 3;  //so that after one step of CW the no other step is taken

   decidecw();

   movecw(); //after this is done means that the lrf is at 0 degrees

   fprintf(con2,"RESET\r");  //instruction to UC2 to reset

   reset_cpu();

   disable_interrupts(global);

}



void decidecw()
{
     if(apos != 20) //means that acw has already been entered
     {
         if(apos == 0)
         {
            cpos = 1;
         }
         else if(apos == 1)
         {
            cpos = 0;
         }
         else if(apos == 2)
         {
            cpos = 3;
         }
         else if(apos == 3)
         {
            cpos = 2;
         }
      }
      else  //so apos == 20
      {
         cpos = 0;
      }

}


void decideacw()
{
     if(cpos != 30) //means that acw has already been entered
     {
         if(cpos == 0)
         {
            apos = 1;
         }
         else if(cpos == 1)
         {
            apos = 0;
         }
         else if(cpos == 2)
         {
            apos = 3;
         }
         else if(cpos == 3)
         {
            apos = 2;
         }
      }
      else  //so cpos == 30
      {
         apos = 0;
      }

}

void moveacw()
{

         if(apos == 0)
         {
           output_high(PIN_A3);
           delay_ms(150);
           output_low(PIN_A3);
           apos++;
         }
         else if(apos == 1)
         {
           output_high(PIN_A2);
           delay_ms(150);
           output_low(PIN_A2);
           apos++;
         }
         else if(apos == 2)
         {
           output_high(PIN_A1);
           delay_ms(150);
           output_low(PIN_A1);
           apos++;
         }
         else if(apos == 3)
         {
           output_high(PIN_A0);
           delay_ms(150);
           output_low(PIN_A0);
           apos = 0;
         }

}

void movecw()
{

          if(cpos == 0)
          {
              output_high(PIN_A0);
              delay_ms(150);
              output_low(PIN_A0);
              cpos++;
           }
          else if(cpos == 1)
          {
              output_high(PIN_A1);
              delay_ms(150);
              output_low(PIN_A1);
              cpos++;
           }
          else if(cpos == 2)
          {
              output_high(PIN_A2);
              delay_ms(150);
              output_low(PIN_A2);
              cpos++;
          }
          else if(cpos == 3)
          {
              output_high(PIN_A3);
              delay_ms(150);
              output_low(PIN_A3);
              cpos = 0;
          }

}




void main()
{

   setup_adc( ADC_OFF );

   SET_TRIS_A( 0x00 );

   OUTPUT_A(0x00);

   delay_ms(1000);  //this is to cater for the initial jitters in the motor.

   decidecw();  //as initially it will be moving in the CW direction

   enable_interrupts(INT_RDA);

   enable_interrupts(INT_EXT);

   ext_int_edge( L_TO_H );   // Sets up EXT
   
   enable_interrupts(global);

   while(1)
   {
      if(factor == 2)
      {
         moveacw();
      }
      else if(factor == 1)
      {
         movecw();
      }

   }

}


Best Regards
Martin Berriman



Joined: 08 Dec 2005
Posts: 66
Location: UK

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 1:43 am     Reply with quote

Just a very quick look so not sure if this will help but are you definitely sending 4 characters to it. If not you may have problems - if your code receives less than 4 chars then it will get stuck on one of the fgetc waiting for more characters to arrive. If you are sending more than 4 chars then the 5th char will still be in the receive buffer since you are not removing it. You might want to use kbhit to check for available chars.
Ttelmah
Guest







PostPosted: Wed Dec 13, 2006 3:56 am     Reply with quote

There are a number of problems.
The key rule is 'keep interrupt handlers short'.
Now 'short' here, means _time_. You can have a 100 line interrupt handler, which is only using one instruction per line, and is fine, but have a one line interrupt handler, that delays for something internally, and will cause problems.
Now your 'RDA' interrupt, takes potentially a long time. It will arrive with one character waiting in the hardware buffer, but then have to sit and wait for three more to arrive. At 19200bps, this is about 1.5mSec, which is an 'age' in computer terms. Use this style instead:
Code:

#INT_RDA
void serial_isr() {
   static int8 state=0;
   command[state++] = fgetc(special);
   if (state==4) {
      command[state]='\0';
      if(command[0] == 'S' && command[3] == 'P')  {
         //means that 'STOP' received
        decideacw();
        factor = 2;
        state=0;
      }
   }
}

This receives just a single character on the interrupt, and when four have arrived, then performs the test, rather than waiting n the interrupt. You may well need to tidy things to get the behaviour as you want, but it shows how to approach this type of problem.
As a comment at this point, you do not show the declaration of 'command'. Is it large enough?.
Now the external interrupt is 'messy'. The 'disable_interrupt' line, will never be reached. Global interrupts are already disabled in the handler, and you reset the CPU the line before. You reset the CPU, which forces a jump to address 0, but at this point, the interrupt flag is still set, so the code will loop forever, from the point where the interrupt is enabled in the main. This is probably what is killing the code.
Don't use 'reset_cpu'. This should be treated as _only_ to be used, in some major error recovery code, and using it routinely, should be considered a 'no-no'. Instead set a flag, and then have an outer loop in the main, if this flag is set, send the message, and then restart the main loop.
As a separate comment, don't change the interrupt edge, after enabling the interrupt. Read the data sheet on this. It can result in the interrupt being triggered, which given the 'fatal' nature of this interrupt is another source of problems.

Best Wishes
ckielstra



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

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 5:31 am     Reply with quote

Besides all the above:
I don't see the declaration line for 'factor'. Make sure it is initialized to 1 or your code will do very little.

Ttelmah's interrupt handler is a good starting point. One important missing feature is a way of synchronizing the input, i.e. you need a mechanism to handle situations where the user enters a command of more or less than 4 characters. Most common solution is to have the user terminate the command with the enter key.

Code:
#include <string.h>

#define MAX_CMD_LEN   10
char command[MAX_CMD_LEN + 1];

void execute_command()
{
  char tmp[MAX_CMD_LEN + 1];

  strcpy(tmp, "STOP");
  if (strcmp(command, tmp) == 0)
  {
    decideacw();
    factor = 2;
  }
}

#int_rda
void serial_isr()
{
  static int8 len=0;
  char c;
 
  c = fgetc(special);
  if ((c >= ' ') && (c <= '~'))   // Check for valid input
  {
    if (len < MAX_CMD_LEN)
    {
      command[len++] = c;
    }
  }
  else if (c == '\n')       // Received newline character?
  {
    command[len] = '\0';    // Terminate command string
    execute_command();
    len = 0;
  }
}
someone
Guest







PostPosted: Wed Dec 13, 2006 6:45 am     Reply with quote

Thankyou all for your replies.

But i think that there is some other problem. let me explain what i am acutally trying to do.

my second microcontroller '18f452' will serially interrupt my first microcontroller '16f877a' through 'INT_RDA'. Now '18f452' will transmit on pin 17 (pin C2) and this pin will directly be connected with pin c7 (pin 26)(hardware Uart) of '16f877a' and hence will trigger the serial interrupt. but the problem is that pin 17 on '18f452' goes high initially(even when i am not sending any serial data through the pin) and due to this reason the serial interrupt is generated constantly on '16f877a'. Due to this the 16f877a always remains in the interrupt handling routine and hence does nothing else. Now to cater this problem i thought perhaps i should use a max232 ic in between. so what i did was that connected pin17 of 18f452 to max232 pin 11. I shorted pin 14 and 13 of max232 (sort of a loop back) and then took the TTL output through pin 12. Now this pin12 of max232 was connected to pin 26 (c7) of first controller '16f877a'. but with this new configuration the same problem exists, the pin 26 of 16f877a is still constantly high and the pic is still in the interrupt subroutine constantly.

Please tell me if this is a proper way to generate interrupt and capture data from other PIC or should i try some other scheme. Please do reply

Many thanks
someone
Guest







PostPosted: Wed Dec 13, 2006 9:27 am     Reply with quote

Also i would like to say that i am using a bootloader for both the PIC's (i.e 18f452 and 16f877a). could this be causing the problem.

Can any one suggest a better way of interrupt based communication between the two controllers named above

Many thanks

Best Regards
someone
Guest







PostPosted: Wed Dec 13, 2006 9:36 am     Reply with quote

I was wondering, is there any need for a pull up or a pull down on the hardware uart for using the 'int_rda' properly

Best REgards
ckielstra



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

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 10:25 am     Reply with quote

Quote:
but the problem is that pin 17 on '18f452' goes high initially(even when i am not sending any serial data through the pin) and due to this reason the serial interrupt is generated constantly on '16f877a'.
For RS232 it is normal behaviour for the Rx pin on the PIC to be high. Idle situation is high level, the start and data bits are low level.

As pointed out by two different people your serial interrupt handler routine is flawed. Fix this first, then come back and report the results.
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