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

INT_TIMER0 interrupt causing weird output??

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



Joined: 08 Jul 2005
Posts: 91

View user's profile Send private message

INT_TIMER0 interrupt causing weird output??
PostPosted: Mon Apr 17, 2006 10:15 pm     Reply with quote

Hi all,

The code below works perfectly fine without the INT_TIMER0 interrupt...that is, I see values for "wp1" and "wp2" correctly printed to hyperterminal. However, when including the TIMER0 interrupt, I see "wp1" and "wp2" printed to the screen every once in a while and then in between I see ASCII junk. For example:


wp1: 323
wp��H�


H�wp1: 323
wp��

I attached the code in this post. What I'm guessing is happening is the TIMER0 interrupt is occurring during the RS232 interrupt and thus not allowing it to fill the char arrays? I tried to avoid this with the reset2 variable, but it still didn't work. Any help would be much appreciated.

Thanks in advance,
weg

Code:

#include <16F877.H>
#include <stdlib.h>
#include <math.h>

#define LED PIN_C0

#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=4800, xmit=PIN_C6, rcv=PIN_C7, stream=GPS)
#use rs232(baud=4800, xmit=PIN_D1, rcv=PIN_D0, stream=PC)

// global variables
int rud_pwm=128, reset=0, reset2=0;
long pulseLength=0;
int i=0, j=0, k=0, commas=0, commas2=0;
char wp1[6], LAT[10], LONGI[11];
char c;

// Timer interrupt to generate PWM signals
#INT_TIMER0
void pwm_signal()
{
   if(reset2==1) reset2=reset2;
   else
   {
      reset=1;

      //One of the parameters used to cause the interrupt to occur every 22.5 msec
      set_timer0(37); // 61 for 20 msec

      // RUDDER
      output_high(PIN_B5); // generates initial high time ie 1 msec
      delay_us(1000);
      i=0;
      for(i=0;i<rud_pwm;i++) // generates remaining high time, varied by variable "pwm"
      {
         //use this to tune duty cycle
         delay_us(1);
      }
      output_low(PIN_B5);
   }
}

// hardware interrupt to detect manual override
#int_ccp1
void isr()
{
   reset=0;
   set_timer1(0);
   while(input(PIN_C2));

   // if SW interrupt triggers during HW interrupt, prevent bogus pulseLength value
   if(reset==0) pulseLength = get_timer1();
   else
   {
      pulseLength = pulseLength;
      reset=0;
   }
}

#int_rda
void rda_isr(void)
{
   reset2=1;

   c = fgetc(GPS);
   c = (char)c;

   if(c=='$') {j=1; commas=0; commas2=0;}
   if(c=='G' && j==1) j=2;
   if(c=='P' && j==2) j=3;
   if(c=='R' && j==3) j=4;
   if(c=='M' && j==4) j=5;
   if(c=='C' && j==5) j=6;
   if(c=='B' && j==5) j=7;
   
   if(c==',' && j==6) commas++;
   if(c==',' && j==7) commas2++;

   if(commas==3) // get latitude data (3)
   {
      if(c==',') k=0;
        else {LAT[k]=c; k++;}
   }

   if(commas==5) // get longtitude data (5)
   {
      if(c==',') k=0;
        else {LONGI[k]=c; k++;}
   }

   if(commas2==11) // get waypoint heading (11)
   {
      if(c==',') k=0;
      else {wp1[k]=c; k++;}
   }

   reset2=0;
}

void main()
{
   char afterDecimal[4];
   float diff_Lat=0.0, diff_Long=0.0;
   float currentLat=0.0, currentLong=0.0;
   float currentWayptLat=0.0, currentWayptLong=0.0;
   float waypointHeading=0.0;
   long wpHeading=0;


   // current waypoint (drexel parking lot)
    currentWayptLat = 39.9540667*Pi/180.0;
    currentWayptLong = 75.184833*Pi/180.0;

   output_high(LED); delay_ms(1500);
   output_low(LED); delay_ms(1500);
   fprintf(PC, "Hello World\r\n");
   
   // setup interrupts
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256); // other param causing interrupt to occur every 20 msec
   setup_ccp1(CCP_CAPTURE_RE); // on rising edge
    setup_timer_1(T1_INTERNAL);

   // enable interrupts
   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_CCP1);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   while(1)
   {
      if(pulseLength>3750)
      {
         output_low(LED); // LED off under manual control
      }


      else
      {
         output_high(LED);

         // latitude
         afterDecimal[0] = LAT[5];
         afterDecimal[1] = LAT[6];
         afterDecimal[2] = LAT[7];
         afterDecimal[3] = LAT[8];

         currentLat = (float)(atol(LAT)/100) + ((float)(atol(LAT)%100) + atof(afterDecimal)/10000.0)/60.0;
         currentLat = currentLat*Pi/180.0;

         // longitude
         afterDecimal[0] = LONGI[6];
         afterDecimal[1] = LONGI[7];
         afterDecimal[2] = LONGI[8];
         afterDecimal[3] = LONGI[9];

         currentLong = (float)(atol(LONGI)/100) + ((float)(atol(LONGI)%100) + atof(afterDecimal)/10000.0)/60.0;
         currentLong = currentLong*Pi/180.0;

         // calculate heading to waypoint
         diff_Lat = currentWayptLat - currentLat;
         diff_Long = currentWayptLong - currentLong;
         waypointHeading = atan2(diff_Long,diff_Lat);
         if(sin(currentWayptLong - currentLong)>0.0)
            waypointHeading = 360.0 - waypointHeading*180.0/Pi;
         else
            waypointHeading = -waypointHeading*180.0/Pi;

         wpHeading = atol(wp1); // in degrees
         fprintf(PC, "wp1: %ld\r\n", wpHeading);
         fprintf(PC, "wp2: %f\r\n\n", waypointHeading);
   
      }
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Apr 17, 2006 10:45 pm     Reply with quote

RS-232 depends upon the proper bit timing being maintained.
In a software UART, the bit periods are generated by toggling
the Tx pin high and low, with a software delay loop between the
transitions. If you permit an interrupt to occur while a byte
is being transmitted by a soft UART, the bit timing will be
stretched out much longer than it should be. It takes many
microseconds just for the overhead to get in and out of an isr.
In addition to that, you have a huge 1000 usec delay in your isr.
arunb



Joined: 08 Sep 2003
Posts: 492
Location: India

View user's profile Send private message Send e-mail

RE:
PostPosted: Tue Apr 18, 2006 1:36 am     Reply with quote

Hi,

A general scheme would be to avoid receiving an interrupt while another one is being serviced, for this you must see which of the interrupts should take priority over the others.

Just ensure that you have only one interrupt enabled at all times..

thanks
arunb
weg22



Joined: 08 Jul 2005
Posts: 91

View user's profile Send private message

PostPosted: Tue Apr 18, 2006 6:47 am     Reply with quote

So you're saying I should have something like below in my RDA interrupt loop?

Code:

#int_rda
void rda_isr(void)
{

   disable_interrupts(INT_TIMER0);

   // rest of code...

   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
}
Ttelmah
Guest







PostPosted: Tue Apr 18, 2006 7:50 am     Reply with quote

What you post, would be _lethal_. You _must never have a global interrupt enable in an interrupt handler_. This is a 'sure' way of making the code die.
Now the comment about only enabling one interrupt, is 'silly'. It is not needed, and has no advantages at all. The whole 'point' of the hardware flags triggered by interrupt events, is so that they can be remembered if they happen while other events are being dealt wth. The _big_ problem with your code, is having the long delay in the interrupt handler. The 'Golden rule' of interrupts, is _keep the handlers short_ (in 'time' terms).
If you need a long 'time' delay, triggered by an interrupt, then program one of the hardware timers to do this, start/enable this in the interrupt handler, and return, then when this triggers perform the 'delayed' function. Delays in interrupt handler of more than a very few uSecs, are a 'sure way' to generate problems.
Now assuming that you have a reasonably recent compiler, add the keyword 'DISABLE_INTS', to the use rs232 line for the 'software' UART, This will disable the interrupts, during the actual transmission/reception of characters on this stream. It won't help, if you are already inside a hugely long interrupt handler, but will stop the interrupt from 'interfering' with the data I/O.

Best Wishes
weg22



Joined: 08 Jul 2005
Posts: 91

View user's profile Send private message

PostPosted: Tue Apr 18, 2006 8:29 am     Reply with quote

Alternatively, if I used the CCP2 pin to generate a PWM and eliminate the INT_TIMER0 loop...this should solve my problems, right?

Thanks for all the help,
weg
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