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

Interrupt affecting main code
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
picman62



Joined: 12 Dec 2014
Posts: 77

View user's profile Send private message

Interrupt affecting main code
PostPosted: Tue Feb 10, 2015 4:43 pm     Reply with quote

I've got a problem with a frequency counter not working right when the LED starts blinking.
I have this LED in a TIMER0 interrupt and the frequency counter in the main code. When the interrupt is excluded, the frequency counter works precisely. But when the LED interrupt is engaged, the frequency counter becomes erratic with eg. in a signal of 5KHz is read as 5722Khz.
There's an int_rb interrupt that calls both counter and LED when button B7 is pressed.

Code is below.
Please, what is the correct approach of getting this right?
Thanks in advance.

Code:

#include <16f877a.h>
#fuses hs,nowdt,nocpd,nolvp,noprotect
#use delay(clock=20M)
#use fast_io(c)
BYTE signal = 0;
#include <LCD.C>
#include <LCD_bargraph.c>
short int led0;

#int_timer0
void TimerLED()
{
  led0 = !led0;
output_bit (pin_c1,led0);
set_timer0(303 + get_timer0()); // get_timer() //value for LED rate
}

#int_rb
void button_isr()
{
     if( !input(PIN_B7) && !signal )
      signal = 1;
     
  else
   
   
   if( !input(PIN_B7) && signal )
      signal = 0;   
}
void main()
{
    set_tris_c(0b00000001);
    enable_interrupts(global);
    enable_interrupts(int_timer0 );
    enable_interrupts(INT_RB);
   LCD_init();

while(true)
{
INT1 SW4;
BOOLEAN ISPRESSED_KEY4=FALSE;       // Boolean logic=0;
 if ( (SW4 && !ISPRESSED_KEY4) )
   {
        ISPRESSED_KEY4=TRUE;
     
     if ((cont==1)||(cont==2)||(cont==3))
     
      do
      {
      if(signal)
      {
     
      set_timer1(0);
      setup_timer_1(t1_external | T1_DIV_BY_1);
      delay_ms(1000);       
      setup_timer_1(T1_DISABLED);
      value=get_timer1();
     
     
      if(Cont==1)
      {
      printf (lcd_putc,"\fFREQ        %LU\r\n",value);
      A=value/200;
      B=value/300;
      C=value/400;
      D=value/10000;
      }
      if(value>=counter-(3) && value<=counter+(2))
     {
      bargraph(A);
      setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_64);
     }
       
      }
     
     }
        while(signal);

        if (!SW4) ISPRESSED_KEY4=FALSE;
}
}
   
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 5:16 pm     Reply with quote

Check the PIC data sheet. What's wrong in the items shown in bold
below ? What's the size of Timer0 ?
Quote:
#include <16f877a.h>
#fuses hs,nowdt,nocpd,nolvp,noprotect
#use delay(clock=20M)
#use fast_io(c)
BYTE signal = 0;
#include <LCD.C>
#include <LCD_bargraph.c>
short int led0;

#int_timer0
void TimerLED()
{
led0 = !led0;
output_bit (pin_c1,led0);
set_timer0(303 + get_timer0()); // get_timer() //value for LED rate
}
picman62



Joined: 12 Dec 2014
Posts: 77

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 5:35 pm     Reply with quote

Thanks, you're right. Should be 256 max. I was playing with the led rate and got lost in the value limit.

I just set it to 6 (256-6), but no change. Frequency counter offset value decreased but still showing something like 5180Hz for a 5KHz signal.
Something else is affecting its precision.
You've mentioned the PIC datasheet. But what info should I search for?
Also, did you find something wrong in the instructions I wrote, besides the TIMER0 value?
Regards.
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 5:48 pm     Reply with quote

hmm.... I've looked a few times but......

you have a variable named 'value' ,
in your code 1/2 way down...
value=get_timer1();

yet I can't see where you've originally delcared it.
CCS C doesn't really like 'mid program declarations, though it might 'assume' it's an 8 bit variable. if so then...
B=value/300;
C=value/400;
D=value/10000; will give bad answers.


just ideas...

Jay
picman62



Joined: 12 Dec 2014
Posts: 77

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 6:56 pm     Reply with quote

Well, I spent all day away from my protoboard and was simulating everyting in PT.
I just got home and put the code to test in the hardware. Actually the frequency counter is indeed working. But not the LED. When pinB7 button is pressed, counter comes in but LED just light up. It does not blink at all. I changed the prescaler and the timer0 initial value. Nothing.
Maybe this is the reason why PT was showing the frequencies completely offset.
Either the LED is not really flashing or it is flashing so fast that it is not happening.
Whatever the reason, it might be related to how the code is written. That's why I asked PCM programmer if he thinks it's ok or not.

Anyway, this code for timer0 interrupt originally featured a 18F2550 PIC. I believe it's got a 16bit timer0. But as I am using values in the 256 limit, I see no problems, right? It must be something else.

Temtronic, the code is working fine with the declarations as they are. The only issue I have right now is really the LED.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 7:22 pm     Reply with quote

Quote:

But when the LED interrupt is engaged, the frequency counter becomes
erratic with eg. in a signal of 5KHz is read as 5722Khz.

That's because the Timer0 interrupt is occurring repeatedly during the
delay_ms(1000) execution time. Each interrupt injects maybe 15 usec
of additional delay. I don't know what your Timer0 interrupt rate is.
If you were interrupting at 10 KHz, then you would lengthen the
delay_ms(1000) by 150 ms more. Your external clock counter would
have a longer time to count pulses. It will give you a higher count.
That is what you are seeing.

If you don't want interrupts interfering with your frequency counter code
then disable interrupts before entering the code, and re-enable them after:
Quote:


disable_interrupts(GLOBAL);

set_timer1(0);
setup_timer_1(t1_external | T1_DIV_BY_1);
delay_ms(1000);
setup_timer_1(T1_DISABLED);
value=get_timer1();
enable_interrupts(GLOBAL);

Your LED and your INT_RB won't work for 1 second. I don't know if this
is important to you or not. I suggest do whatever is the most simple
thing to quickly finish your program. Do a solution that is simple and
that you can understand. If my proposed solution above works, then
use it.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 2:03 am     Reply with quote

The real key is to get away from the idea of using delay_ms, as a timing source. It's never going to be accurate if your processor is doing anything else.

Create a background 'tick' interrupt. Some useful interval. Use the count of this as your timing, rather than delay_ms.

As PCM_programmer says, you can stop the interrupts as an alternative,, but then (of course) you lose any arriving serial data.

I suggest instead of trying to get a timing of the LED, by updating the count, you use timer2, which can be set to give accurate timings.

So (for instance)
setup_timer2(T2_DIV_16,249,10);

Will give an interrupt 125 times a second.

Then if your LED wants to flash every second:
Code:

#define PER_SECOND 125
int8 count;
#int_timer0
void TimerLED()
{
   static int8 led_count=(PER_SECOND-1);
   if (led_count)
       --led_count;
   else
   {
       output_toggle(PIN_C1);
       led_count=(PER_SECOND-1);
   }
   if (count)
      --count;
}


Then to delay, just set 'count' to the count required, and wait till it gets to zero. To get accurate timings, you'd ideally wait till the timer update occurs, before waiting. So:
Code:

    //With the above timer, for one second:
    count=1;
    while (count);
    //Now trigger the start event for your detection 'set timer' etc..

    count=(PER_SECOND-1);
    while(count);
    //get here one second later.


Experiment.
picman62



Joined: 12 Dec 2014
Posts: 77

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 8:21 am     Reply with quote

I wrote another code only featuring the timer0 interrupt and the counter instruction in the main. It worked now.
I used Ttelmah's code, but another similar code also worked.
Code:

#include <16f877a.h>
#fuses hs,nowdt,nocpd,nolvp,noprotect, brownout
#use delay(clock=20M)
#use fast_io(c)
#include <LCD.C>
#define PER_SECOND 125
int count;

#int_timer0
void TimerLED()
{
  static int8 led_count=(PER_SECOND-1);
   if (led_count)
       --led_count;
   else
   {
       output_toggle(PIN_C1);
       led_count=(PER_SECOND-1);
   }
   if (count)
      --count;
}

unsigned int16 value;
 
void main()
{
   set_tris_c(0b00000001);
    enable_interrupts(global);
    enable_interrupts(int_timer0 );
    setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);//for three cases I have prescalers of 8, 16 and 64
   LCD_init();

   while(1)
   {
   
      set_timer1(0); 
      setup_timer_1(t1_external | T1_DIV_BY_1);
      delay_ms(1000);       
 
      setup_timer_1(T1_DISABLED);
      value=get_timer1();
      lcd_gotoxy(11,4);
      printf(lcd_putc,"\f%LU HZ   ",value);     
     
   }
}

Note that I did not feature any button.
So the problem appears to reside in my code somewhere.
I suspect this could be the #int_rb. When button is pressed, counter and LED are on, but LED is inside a TIMER0 interrupt... Maybe this is the problem, since I have read here somewhere that an interrupt should not be inside another interrupt. I will include the int_rb interrupt next and will report back.


PCM programmer wrote:


If you don't want interrupts interfering with your frequency counter code
then disable interrupts before entering the code, and re-enable them after:

Thanks. I did this, but LED remained lit (no flashing) and counter suffered a heavy offset from the real frequency reading.



Telmah wrote:

Then to delay, just set 'count' to the count required, and wait till it gets to zero. To get accurate timings, you'd ideally wait till the timer update occurs, before waiting.
Experiment.

Thanks.
My LED time rate is not critical at all. I simply set it for fast blink when a given freq is read and slower blink when it offsets from that freq by some value. I also plan to use the TIMER2 for PWM, so I guess I can use TIMER0 for your instruction.

I noticed that if I change prescaler value in TIMER0 for faster or slower LED flashing, the frequency counter value is affected.
For a faster blink, frequency offsets higher, for a slower blink, the opposite happens.
Is there any way to avoid this condition?
Mike Walne



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

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 11:42 am     Reply with quote

picman62 wrote:
I wrote another code only featuring the timer0 interrupt and the counter instruction in the main. It worked now.

.........
.........

I used Ttelmah's code, but another similar code also worked.
My LED time rate is not critical at all. I simply set it for fast blink when a given freq is read and slower blink when it offsets from that freq by some value. I also plan to use the TIMER2 for PWM, so I guess I can use TIMER0 for your instruction.

I noticed that if I change prescaler value in TIMER0 for faster or slower LED flashing, the frequency counter value is affected.
For a faster blink, frequency offsets higher, for a slower blink, the opposite happens.
Is there any way to avoid this condition?


You've got me confused.
In one sentence you say it works, then later there's a problem.

Please clarify.

Mike
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 11:56 am     Reply with quote

Another problem is you don't know enough about C or program design
or debugging methods to be able to solve your problems. Every time
we try to help you, it typically doesn't work, and you can't fix it.
It either doesn't work or you're dissatified with it. So every one of your
threads ends in disappointment. Then everyone walks away and forgets
it until you do the next thread.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 1:15 pm     Reply with quote

He is also missing the vital point of my code.
The point was to do the sample timing using the 'count' value, so that the time for sample would not change as other things happened in interrupts. Instead he has just used the LED flash part of it and kept the standard delay....
picman62



Joined: 12 Dec 2014
Posts: 77

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 2:35 pm     Reply with quote

Yes, I don't know enough C to solve my problems. But I am striving. I knew nothing in early december. Thanks to some reading in this forum, today I am in the end part of my first code which is not so simple.

Mike, when I say it works, I was refering to the LED code in the TIMER0 interrupt I got from Ttelmah. The previous one did not.

Back to the topic, I inserted the #int_rb interrupt instruction and it also seemed to work in the 'interrupt code' I wrote to test this particular piece..
So I will go back to my routine to track this issue and make it work there too.

Ttelmah wrote:
Quote:

He is also missing the vital point of my code.
The point was to do the sample timing using the 'count' value, so that the time for sample would not change as other things happened in interrupts. Instead he has just used the LED flash part of it and kept the standard delay....

Exactly. This would be my next question to you. I couldn't figure where to insert this last part of your code.
Code:

//With the above timer, for one second:
    count=1;
    while (count);
    //Now trigger the start event for your detection 'set timer' etc..

    count=(PER_SECOND-1);
    while(count);
    //get here one second later.


Thanks in advance.
Mike Walne



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

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 3:21 pm     Reply with quote

picman62 wrote:

Mike, when I say it works, I was refering to the LED code in the TIMER0 interrupt I got from Ttelmah. The previous one did not.
I'm still no wiser.

You need to marshal your thoughts.
Make a simple, clear, concise list of what needs to happen.
Show us the latest version of your code.
Explain what works and precisely what is wrong with what does not.

Simply dabbing code in an ad-hoc fashion will get you nowhere.
At this stage you've got us all guessing.

Mike
picman62



Joined: 12 Dec 2014
Posts: 77

View user's profile Send private message

PostPosted: Thu Feb 12, 2015 4:00 am     Reply with quote

Mike Walne wrote:

You need to marshal your thoughts.
Make a simple, clear, concise list of what needs to happen.
Show us the latest version of your code.
Explain what works and precisely what is wrong with what does not.

Simply dabbing code in an ad-hoc fashion will get you nowhere.
At this stage you've got us all guessing.

Mike

Very well then.
I could trace the syntax issue in my code and now LED works along with the counter as desired.

So my list of help now resumes only to fix the counter offset problem. How to set the frequency counter correctly to work with interrupts.

As I am using delays for the counter, it's being affected by the time rate the LED flashes.

The LED is not critical to my project. But the counter is. The more precise it is, the better.
Now I see that this counter using delays, only work if it's not disturbed by any other instructions which also involves time. Also, in this counter, the resolution is dependent of gate time of the delay(1000ms).

This is why I found Ttelmah's suggestion interesting. Because it would count ticks and sounds like similar to the reciprocal counting approach where instead of counting the PIC's input signal, it counts the periods of the master clock.
I would apprecitate if Ttelmah could give details of the second part of his code above and how it would be written for my case.
I would like to keep the LED in timer0 as it is and use TIMER1 for the counter task. TIMER2 will be used for my last task , PWM.

Thanks for this help in advance.
Regards.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Thu Feb 12, 2015 4:10 am     Reply with quote

Replace:
Code:

      set_timer1(0);
      setup_timer_1(t1_external | T1_DIV_BY_1);
      delay_ms(1000);       
 
      setup_timer_1(T1_DISABLED);
      value=get_timer1();

//With
      setup_timer_1(t1_external | T1_DIV_BY_1);
      count=1;
      while (count)
         ; //wait for interrupt
   
      count=(PER_SECOND-1);
      set_timer1(0); //start the count

      while(count)
         ; //wait for one second
      setup_timer_1(T1_DISABLED);
      value=get_timer1();


With the timer interrupt setup as I originally posted.
However the interrupt needed to be on timer2, not timer0. I forgot to change this in my post.

If you want to change the LED flash rate, don't change the timer rate, but change the value used to re-load led_count.

You can still use the PWM with timer2 being used like this, it'll just run at 1250Hz. If this isn't suitable, then calculate the changes needed.

The point is that timer2, can be set to give an exact division by a factor (16*250*10), which gives exactly 125 interrupts per second, allowing you to get an accurate time. It's the only timer on these earlier PIC's that allows this sort of accuracy.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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