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

3 interruptions' conflicts

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
J.H.Sun



Joined: 27 Jun 2011
Posts: 4

View user's profile Send private message

3 interruptions' conflicts
PostPosted: Sun Jul 10, 2011 1:35 am     Reply with quote

Dear all

I use a pic18f458 to decode PWM signals from flight remote controller and tachometer. Also taking it to Receive the data from force gauge. That is I use " 3 " interruption simultaneously to decode the PWM, RPM and force. Now the execution of code is OK, but the accuracy is not well. When I just use CCP1 and CCP2 without using RDA,the RPM and PWM's accuracy is acceptable. While, if taking CCP1, CCP2 and RDA simultaneously to decode the signal, the error here will enlarge. The error here is likely that the true value is 2500, although the PIC can calculate 2500, but it will "jump" to 1500 very quick and back to 2500 repeatly. The frequency is not low. Therefore, I try to ask for help how to solve these kind of problems. I just think of tip if I could know the start time and end time of each interruption, maybe avoiding the conflict between 3 interruption is possible. But, how I could get the time ?? If different input signal, is it the same ??
Code:

#include  <18f458.h>
#include  <stdlib.h>
#fuses    HS,WDT1
#use      delay(clock = 20000000)
#use      rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#priority CCP1,CCP2,RDA
#define   bsize 128

int8  CCP1_flg = 0,CCP1A_flg=0,CCP2_flg =0,CCP2A_flg=0,n,out[13],i,buffer[bsize],len=0,RDA_flg=0,ii ;
int16 rate_ctrl=0;
int32 pwm_ttick = 0 ,rpm=0,rpm_ttick =0,force=0 ;
int32 pwm=0,period=0,rpm_ttick1=0;
char  data[4];

void rcv()
{
int8  buf[20], ii, jj ;
 
   for(ii = 0 ; ii < len ; ++ii)
   {
      for(jj = 0 ; jj < 15 ; jj++)
            buf[jj] = buf[jj+1]  ;
   
      buf[15] = buffer[ii] ;

      if(buf[1] == '4' && buf[2] == '1' &&
         buf[3] == '5' && buf[4] == '5' &&
         buf[6] == '2' && buf[7] == '0' &&
         buf[8] == '0' && buf[9] == '0' &&
         buf[10] == '0')
      {         
         data[0] = buf[11] ;
         data[1] = buf[12] ;
         data[2] = buf[13] ;
         data[3] = buf[14] ;
         
         if(buf[5] == '0')
            force = atof(data)  ;
         else if(buf[5] == '1')
            force = -atof(data) ;
         } 
   }
   for(ii = 0 ; ii < bsize ; ++ii )
       buffer[ii] = 0;

   len = 0;
}


#INT_CCP1
void CCP1_isr()
{
   if(CCP1_flg == 0)
   {   
      set_timer1(0) ;
      CCP1_flg = 1 ; 
      setup_ccp1(CCP_CAPTURE_FE) ;
   }
   else if(CCP1_flg == 1)
   {       
      pwm_ttick = get_timer1();                   
      CCP1_flg = 0 ;
      CCP1A_flg =1 ;
      setup_ccp1(CCP_CAPTURE_RE) ;
   }   
}


#INT_CCP2
void CCP2_isr()
{
   if(CCP2_flg ==0)
   {
    set_timer3(0) ;
    CCP2_flg =1 ;
   }
   else if(CCP2_flg ==1)
   {
    rpm_ttick = get_timer3();
    CCP2_flg =0;
    CCP2A_flg =1;
   }
}


#INT_RDA
void RDA_isr(void)
{
  buffer[len] = getc() ;
  ++len                ;
 
  if(len >= 16)
  rcv() ;
}


void main()
{
   for(n=0;n<13;n++)
   {
    out[n]=0;
   }
   setup_wdt(WDT_ON) ;
   setup_ccp1(CCP_CAPTURE_RE)              ;
   setup_ccp2(CCP_CAPTURE_RE)              ;
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_4)  ;
   setup_timer_3(T1_INTERNAL|T1_DIV_BY_4)  ;
   enable_interrupts(INT_CCP1)             ;
   enable_interrupts(INT_CCP2)             ;
   enable_interrupts(INT_RDA)              ;
   enable_interrupts(GLOBAL)               ;
       
   while(TRUE)
                {
                restart_wdt();
                if(CCP1A_flg ==1)
                {
                pwm = pwm_ttick *8;//0.1us
                CCP1A_flg =0;
                }
                else if(CCP2A_flg ==1)
                {
                rpm_ttick1=rpm_ttick*8;
                rpm   = 600000000/rpm_ttick1 ;
                CCP2A_flg =0 ;
                }
               
                out[0]=252;
                out[1]=253;
                out[2]=0;
                out[3]= pwm/65536;
                out[4]=(pwm%65536)/256;
                out[5]=(pwm%65536)%256;
                out[6]=rpm/256 ;
                out[7]=rpm%256 ;         
                out[8]=force/256;
                out[9]=force%256;
                out[10]=0;
                out[11]=254;
                out[12]=255;
                //printf("%ld,%ld,%ld\r\n",rpm_ttick,rpm,rpm_ttick1);
                  if(rate_ctrl ==5200)//20Hz(10750)
                    {
                     for(i=0;i<13;i++)
                    {
                       printf("%c",out[i]);
                    }
                     rate_ctrl = 0 ;
                     }
                     rate_ctrl++ ;
               

                }
}


Last edited by J.H.Sun on Sun Jul 10, 2011 5:17 pm; edited 2 times in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Sun Jul 10, 2011 2:07 am     Reply with quote

Critical thing is always 'keep interrupt handlers quick'.
Second thing is to understand that 'priority' does basically nothing. It sets the order in which interrupts are _polled_, but once you are inside an interrupt, unless you use hardware priority, the handler you are in, has to complete, _before_ another can occur. This is why it is always vital to get out of the handlers ASAP.

Now, your CCP1, and CCP2 handlers are quick. Your RDA handler is quick for 15 characters, but the 16'th, is appalling. You have loops inside loops (always slow), and at the centre, atof. I hate to think how long this routine will be, but, given that atof, tries to convert a value to 'float', and therefore can involve float maths. Uurgh!...
Repeat, and repeat again. Do as little as possible in interrupt handlers. If you want to do complex things, set a flag, and do these _outside_.
Rewrite your serial receive routine, in a manner like the EX_SISR. _Just_ buffer the data. Set a flag when you have a complete 'packet', and do the handling in the main code, when this flag is set.

Best Wishes
ckielstra



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

View user's profile Send private message

PostPosted: Sun Jul 10, 2011 7:27 am     Reply with quote

Just a few more remarks to save you future trouble:
1) Add the NOLVP fuse. Without this setting a glitch on the LVP pin (A6) will reset your processor.
2) Add the 'errors' directive to the #use rs232 line. This will have the compiler to add extra code to restart a stalled UART.
3) The atof function requires a zero terminated string. I doubt this is the case in your program.

In general, when working with embedded software it is better to never use floating point. Simple processors like the PIC have no floating point hardware and therefor it takes an incredible lot of processor instructions to do the math. Much better is to use a method called 'Fixed point integer' where you do calculations with normal integers and pretend there is a decimal point. For example, when you want to use the value 1.23 you do the math with the integer 123, and only in the final step when showing the calculation to the user you will insert the graphical '.'. The CCS compiler has the convenient %w parameter in the printf function to insert the dot sign for you. Fixed point integers are much faster than floating point, require less memory and are sometimes even more accurate (and sometimes less accurate).

Code:
   for(ii = 0 ; ii < bsize ; ++ii )
       buffer[ii] = 0;
Easier to read, and faster executing, is:
Code:
   memset(buffer, bsize, 0);


Code:
out[3]= pwm/65536;
out[4]=(pwm%65536)/256;
out[5]=(pwm%65536)%256;
The compiler is probably smart enough to optimize this code, but why take the chance if you can write easier to read code that is also lightning fast?
Code:
out[3] = make8(pwm, 2);  // Extract byte 2
out[4] = make8(pwm, 1);  // Extract byte 1
out[5] = make8(pwm, 0);  // Extract byte 0
Same can be done for the rpm and force variables.
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