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

Timer0 configured with Project Wizard not working properly

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



Joined: 25 Feb 2014
Posts: 34
Location: Brazil

View user's profile Send private message

Timer0 configured with Project Wizard not working properly
PostPosted: Wed Aug 24, 2016 7:44 am     Reply with quote

Hello all!

I'm trying to implement a timer0 interruption using PIC16F627A but it doesn't seem to work as I expect to.

I expected to get a signal with period of 4ms (1ms high + 3ms low)
But actually it's giving me a signal of 16,4ms (4ms high + 12,4ms)

I configured the timer0 using Project Wizard.

Please, could someone pointing out my mistake?

Tks in advance!

My code:
Code:

#include <16F627A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(internal=4000000,restart_wdt)

#use FIXED_IO( A_outputs=PIN_A1)
#use FIXED_IO( B_outputs=PIN_B4)

#define OUT1   PIN_A1
#define LED   PIN_B4

#INT_TIMER0
void  TIMER0_isr(void)
{
   output_bit(OUT1, TRUE); // Putting the data pin high
   delay_us(1000);
   output_bit(OUT1, FALSE); // Lowering the pin
}

void main()
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16|RTCC_8_bit);      //4,0 ms overflow


   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   
   while(TRUE)
   {
      //TODO: User Code
      output_bit(LED,true); // Putting the data pin high
      delay_ms(1000); // Delaying the pulse for 'time' period
      output_bit(LED,false); // Putting the data pin high
   }

}
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Wed Aug 24, 2016 8:18 am     Reply with quote

The problem is not the wizard. It's using delays inside an interrupt.

You should be getting a compiler warning 'interrupts disabled to prevent re-entrancy'.

Code cannot be called inside 'itself'. Problem is that the delay code you are using in the main, is the same code as the delay you are using in the interrupt. So the interrupt waits till the main delay finishes before it is called.....

Honestly, just set the interrupt to trigger at 1mSec, and code the interrupt as:
Code:

#INT_TIMER0
void  TIMER0_isr(void)
{
   static int8 operation=0;
   if (operation==0)
      output_bit(OUT1, TRUE); // Putting the data pin high
   else   
      output_bit(OUT1, FALSE); // Lowering the pin
   if (operation++ == 3)
      operation=0;
}

void main(void)
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4|RTCC_8_bit);      //1,0 ms overflow


   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   
   while(TRUE)
   {
      //TODO: User Code
      output_bit(LED,true); // Putting the data pin high
      delay_ms(1000); // Delaying the pulse for 'time' period
      output_bit(LED,false); // Putting the data pin high
   }
}

The LED will be on for one interrupt in 4.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Aug 24, 2016 8:21 am     Reply with quote

compile this instead

Code:

#include <16F627A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                 

#use delay(internal=4000000)

#define OUT1   PIN_A1
#define LED   PIN_B4

#INT_TIMER0
void  TIMER0_isr(void)
{   output_toggle(out1); }

void main()
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16|RTCC_8_bit);     


   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   
   while(1)
   { delay_cycles(1);   }

}


your a1 pin should have a symmetric 4ms on 4 ms off duty now
-does it ?
cleberalbert



Joined: 25 Feb 2014
Posts: 34
Location: Brazil

View user's profile Send private message

PostPosted: Wed Aug 24, 2016 12:42 pm     Reply with quote

I'm sorry but my objective is just quite a bit deeper than I said previously. The code I posted was just a pseudo-prototype to try to be more simple and easy to understand. But will give more details:

All what I need is to control 5 servomotors individually (20ms/5 = 4ms) and their duty cycle will vary depending of a data received through serial port. It justifies why I need to vary the period-on with delay instead of other timer0 overflow.

I've already implemented successfully a code to perform this PWM control with the PIC16F676. What I need now is to change to PIC16F627A.

To change I just edit the first line to
Code:
#include <16F627A.h>
and change the output ports. I expected it to work but it doesn't.

Ttelmah,

I think now I could explain to you why I need to use a delay inside an interrupt instead to use another overflow to set the level down. Because the on-period will vary unpredictably between 1 and 2 milliseconds.

However I ran your code and it gave me a signal around 4ms on and 12ms off.

asmboy,

Your code gave me a symmetric 16.4ms on 16.4ms off.


My code for PIC16F676:
Code:

#include <16F676.h>

#FUSES NOWDT
#FUSES INTRC_IO
#FUSES NOPUT
#FUSES NOPROTECT
#FUSES NOBROWNOUT
#FUSES NOMCLR
#FUSES NOCPD
#FUSES RESERVED                 //Used to set the reserved FUSE bits
 
#use delay(clock=4000000)

#define SERVO1_OUT   PIN_A5
#define SERVO2_OUT   PIN_C1
#define SERVO3_OUT   PIN_C2
#define SERVO4_OUT   PIN_C3
#define SERVO5_OUT   PIN_C4

void PWM(int8 servo_out)
{
   unsigned int16 serial_read;

   serial_read = 0; //Serial reading will be implemented yet
   output_bit(servo_out, TRUE); // Putting the data pin high
   delay_us(1000 + serial_read); // Delaying the pulse for 'time' period. Angle'll vary between 0° and 180°
   output_bit(servo_out, FALSE); // Lowering the pin
   serial_read = 0;
}

void main()
{
   int8 servo = 0;
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16|RTCC_8_bit);      //4,0 ms overflow

   while(TRUE)
   {
   if (interrupt_active(INT_RTCC))
   {
      clear_interrupt(INT_RTCC);
      switch(++servo)
      {
      case 1:
      //SERVO 1
      PWM(SERVO1_OUT);
      break;
      case 2:
      //SERVO 2
      PWM(SERVO2_OUT);
      break;
      case 3:
      //SERVO 3
      PWM(SERVO3_OUT);
      break;
      case 4:
      //SERVO 4
      PWM(SERVO4_OUT);
      break;
      case 5:
      //SERVO 5
      PWM(SERVO5_OUT);
      servo = 0;
      break;
      }
   }
   }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Wed Aug 24, 2016 2:35 pm     Reply with quote

Honestly the answer is not to use a timer interrupt.

Servos have no requirement for accurate 'off' times.
In fact you can handle four servos 'sequentially', just doing the pulse for servo 1, then the pulse for servo 2, then servo 3, then servo 4. Then start again. This is actually how they are done in a real 'historical' RC. On these the pulses for all the servos are sent 'one after the other' in the radio stream, with a long 'pause' at the end. The receiver detects the pause, and routes the first pulse after the pause to the first servo, then the second to the second servo etc.. Once all the pulses have been sent, it goes back to looking for the pause. Trying to do all four at once, is making life harder than it has to be....
You can get really accurate pulse times using the CCP, and big advantage of this, is that the times will not be changed if your code is doing other things (like receiving serial etc..). I've posted code to do this here a little while ago, and PCM_Programmer has also done this (mine was showing how to use polling in the main loop, his using the CCP interrupt).
cleberalbert



Joined: 25 Feb 2014
Posts: 34
Location: Brazil

View user's profile Send private message

PostPosted: Wed Aug 24, 2016 3:08 pm     Reply with quote

Tks for replying!!

I can see my solution is not the best or even not elegant, but honestly I prefer try to adapt my old code for PIC16F676 to PIC16F627A because it would be faster than pause and try to understand and implement your or PCM_Programmer's code (would be more adequade I know that) but this little board is just a small part of a too much bigger system in which I need to work on and worry about deadline. It is just a case of scheduling priorities.

Sure another time when I'm more loose I'll care more about accuracy so, study your code but for now could you help me to make this code work on PIC16F627A as well as it works on PIC16F676?
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Thu Aug 25, 2016 1:09 am     Reply with quote

Why are you using INT_RTCC?.

This does nothing as posted. The interrupt will be set every 4mSec. Since your servo output code routines together take an absolute minimum of 4mSec, it'll always be true when you test it. So it is pointless....
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