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

servo cycle variation between s/w and oscilloscope
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
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

servo cycle variation between s/w and oscilloscope
PostPosted: Sun Oct 23, 2005 11:57 am     Reply with quote

This code is being developed to control a six-legged robot with IR vision. Right now I'm just trying to center one servo using an interrupt routine off Timer_0. The rest of the program prints out values to an LCD for debugging and reads data from a IR range finder.

In the code, the servo is being sent a delay of 1500 us in the ISR. This has been confirmed with the LCD print. In addition, the interrupt has been set to cycle every 16 ms with the setup_timer_0 statement.

On an oscilloscope however, the servo is being sent a high pulse of about 1250 us with a period of 66 ms.

I'm getting kind of x-eyed looking at the code and I am a newbie so any help would be appreciated.

Also, the code snippet below, when it has positive values in it, doesn't seem to affect the interrupt timing:
Code:
set_timer0(0);


Thanks....Harry
Code:
#include <16F628.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#include <LCD_4LINE.c> //this file set up to use port B

#define quar_mov 250
#define GP2D02_VIN PIN_B3
#define GP2D02_VOUT PIN_A2

//Interrupt Service Routine (ISR)=========================

#int_TIMER0                        // This function is called every time
void servo_isr()                   // the RTCC (timer0) overflows (255->0).
{                                  // For this program this shld be :) 50 times
int reading=0;                     // per second.
long quarter= 2;                   // 4 servo positions: 1,2,3,4
int counter=9;

//Position the servo(s)===================================
long position;
position = quarter * quar_mov;
output_high(PIN_A0);
delay_ms(1);
delay_us(position);
output_low(PIN_A0);

//Collect the IR reading==================================

   output_low(GP2D02_VIN);         // start cycle with Vin low
   delay_ms(1);                 // give the sensor a little time before we bug it
   while (!input(GP2D02_VOUT));    //wait for Vout to go high
   do {
      delay_cycles(4);        // minimum wait is 2us, max is 170us, 4 worked
      output_low(GP2D02_VIN);      // tell the sensor that we want a bit
      delay_cycles(2);             // might be as low as 1 (maybe), 2 worked
      reading=reading<<1;          // left shift the reading value
      reading=reading|(input(GP2D02_VOUT)); // put the newest reading into the
                                            // LSB of reading
      output_high(GP2D02_VIN);     // we read bit, and get ready for the next one
      counter--;
      } while (counter>0);

//LCD print statements====================================

      lcd_gotoxy(1,1);
      printf(lcd_putc," IR Measurement");
      lcd_gotoxy(1,2);
      printf(lcd_putc,"================");
      lcd_gotoxy(1,3);
      printf(lcd_putc,"Value = %3u", reading);
      lcd_gotoxy(1,4);
      printf(lcd_putc,"Position =%lu",position);
}

//Setup LCD, pins, Timer_0, interrupts====================

void main()
{
lcd_init();
setup_comparator(NC_NC_NC_NC);
set_timer0(0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(1);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 23, 2005 12:50 pm     Reply with quote

The problem is caused by passing a 16-bit variable to a function
that is expecting an 8-bit variable.
Quote:

In the code, the servo is being sent a delay of 1500 us in the ISR
On an oscilloscope however, the servo is being sent a high pulse
of about 1250 us

long position;

delay_us(position);


From the CCS manual:
Quote:
DELAY_US()

Syntax: delay_us (time)

Parameters: time - a variable 0-255 or a constant 0-65535


See this thread for a work-around:
http://www.ccsinfo.com/forum/viewtopic.php?t=16656&highlight=longdelayus
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Sun Oct 23, 2005 1:43 pm     Reply with quote

Thanks...the long_delay_us works perfectly...within the accuracy of my scope anyway. I've still got a couple of questions about the following code.
Code:
set_timer0(0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);


1. By my calculations RTCC_DIV_64 should give me a little over a 16 ms period. I'm actually getting 66 ms.

2. I'm not clear on why I need "enable_interrupts(GLOBAL)" to get the interrupt working.

3."set_timer0(0)" does nothing regardless of which positive value I put in the argument. I thought I could shorten the interrupt time by putting in a value that reduces 256.

Thanks....Harry
Ttelmah
Guest







PostPosted: Sun Oct 23, 2005 2:43 pm     Reply with quote

Remember that all the timers clocks run off the master clock/4. So youhave clock/4/64/256. This is probably the factor of about 4* the time you are expecting.
Yes you can set the clock 'forward', but it'll ony effect that one cycle of the interrupt. If you want a longer adjustable time, look at the CTC modules, which allow timer2, to be repeatedly reset automatically.

Best Wishes
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 23, 2005 3:01 pm     Reply with quote

Or preset Timer0 (also called RTCC) inside the isr. Example:
http://www.ccsinfo.com/forum/viewtopic.php?t=24530&highlight=intrtcc
dyeatman



Joined: 06 Sep 2003
Posts: 1923
Location: Norman, OK

View user's profile Send private message

PostPosted: Sun Oct 23, 2005 3:03 pm     Reply with quote

Harry,
In the datasheet on page 21 look at the INTCON bit 7 (GIE). Per page 16 that bit is set to 0 at POR and that disables ALL interrupts.

ENABLE_INTERUPTS(GLOBAL) sets this bit to 1 allowing all UNMASKED (individualy enabled) interrupts to occur.
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Sun Oct 23, 2005 6:42 pm     Reply with quote

Ttelmah wrote:
Remember that all the timers clocks run off the master clock/4. So youhave clock/4/64/256. This is probably the factor of about 4* the time you are expecting.


I've taken a smaller portion of the code and gotten it to work as expected, that is, a 16 ms period with a prescaler of 64. The same code, within the larger program, seems to go to 66 ms.

Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Sun Oct 23, 2005 6:45 pm     Reply with quote

PCM programmer wrote:
Or preset Timer0 (also called RTCC) inside the isr. Example:
http://www.ccsinfo.com/forum/viewtopic.php?t=24530&highlight=intrtcc


I've taken your code example and applied it to my code. At least now I've gotten the preload to work by putting it inside the ISR function. The results have gotten even more hairy but you've given me something to work with.

Thanks....Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Sun Oct 23, 2005 6:47 pm     Reply with quote

dyeatman wrote:
Harry,
In the datasheet on page 21 look at the INTCON bit 7 (GIE). Per page 16 that bit is set to 0 at POR and that disables ALL interrupts.

ENABLE_INTERUPTS(GLOBAL) sets this bit to 1 allowing all UNMASKED (individualy enabled) interrupts to occur.


Thanks for the explanation, all this help has taken my confidence level from zero to "tentative first steps".

Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Mon Oct 24, 2005 10:06 am     Reply with quote

I'm stuck again! I've pulled just the timer_0 interrupt and servo centering routines out of the program in my first post and they work as designed. The oscilloscope shows a 1500 us pulse and a 20 ms period. Here is the code:
Code:
#include <16F628.h>
#fuses XT, NOWDT, NOPROTECT
#use delay(clock=4000000)

#define quar_mov 250

//Long delay function====================================

void long_delay_us(long count)
{
char i;
i = (char)(count >> 8);
while(i >= 1)
{
i--;
delay_us(253);
restart_wdt();
}
delay_us((char)count);
}

//Interrupt Service Routine (ISR)=========================

#int_TIMER0                        // This function is called every time
void servo_isr()                   // the RTCC (timer0) overflows (255->0).
{
                                   // For this program this shld be :) 50 times
int reading=0;                     // per second.
long quarter= 2;                   // 4 servo positions: 1,2,3,4
int counter=9;

//Position the servo(s)===================================

long position;
set_timer0 (100);
position = quarter * quar_mov;
output_high(PIN_A0);
delay_ms(1);
long_delay_us(position);
output_low(PIN_A0);

}

main()
{
  setup_comparator(NC_NC_NC_NC);
  setup_timer_0(RTCC_INTERNAL | RTCC_DIV_128);
  enable_interrupts(INT_TIMER0);
  enable_interrupts(GLOBAL);
  while(true);
}


The code from my first post, which includes additional IF rangefinder and LCD print routines but the same servo and interrupt routines, give the correct pulse of 1500 us but a period of around 85 ms.

Any ideas?

Thanks....Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Mon Oct 24, 2005 10:07 am     Reply with quote

I'm stuck again! I've pulled just the timer_0 interrupt and servo centering routines out of the program in my first post and they work as designed. The oscilloscope shows a 1500 us pulse and a 20 ms period. Here is the code:
Code:
#include <16F628.h>
#fuses XT, NOWDT, NOPROTECT
#use delay(clock=4000000)

#define quar_mov 250

//Long delay function====================================

void long_delay_us(long count)
{
char i;
i = (char)(count >> 8);
while(i >= 1)
{
i--;
delay_us(253);
restart_wdt();
}
delay_us((char)count);
}

//Interrupt Service Routine (ISR)=========================

#int_TIMER0                        // This function is called every time
void servo_isr()                   // the RTCC (timer0) overflows (255->0).
{
                                   // For this program this shld be :) 50 times
int reading=0;                     // per second.
long quarter= 2;                   // 4 servo positions: 1,2,3,4
int counter=9;

//Position the servo(s)===================================

long position;
set_timer0 (100);
position = quarter * quar_mov;
output_high(PIN_A0);
delay_ms(1);
long_delay_us(position);
output_low(PIN_A0);

}

main()
{
  setup_comparator(NC_NC_NC_NC);
  setup_timer_0(RTCC_INTERNAL | RTCC_DIV_128);
  enable_interrupts(INT_TIMER0);
  enable_interrupts(GLOBAL);
  while(true);
}


The code from my first post, which includes additional IF rangefinder and LCD print routines but the same servo and interrupt routines, give the correct pulse of 1500 us but a period of around 85 ms.

I've just noticed that I've made some changes to the original code so I will post that also.

Any ideas?

Thanks....Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

Please read prvious post.
PostPosted: Mon Oct 24, 2005 10:14 am     Reply with quote

Here is a copy of the original post with a few changes. Please refer to my last post.
Code:

#include <16F628.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#include <LCD_4LINE.c> //this file set up to use port B

#define quar_mov 250
#define GP2D02_VIN PIN_B3
#define GP2D02_VOUT PIN_A2

//Long delay function


void long_delay_us(long count)
{
char i;
i = (char)(count >> 8);
while(i >= 1)
{
i--;
delay_us(253);
restart_wdt();
}
delay_us((char)count);
}

//Interrupt Service Routine (ISR)=========================

#int_TIMER0                        // This function is called every time
void servo_isr()                   // the RTCC (timer0) overflows (255->0).
{
                                   // For this program this shld be :) 50 times
int reading=0;                     // per second.
long quarter= 2;                   // 4 servo positions: 1,2,3,4
int counter=9;

//Position the servo(s)===================================

long position;
set_timer0 (100);
position = quarter * quar_mov;
output_high(PIN_A0);
delay_ms(1);
long_delay_us(position);
output_low(PIN_A0);

//Collect the IR reading==================================

   output_low(GP2D02_VIN);         // start cycle with Vin low
   delay_ms(1);                    // give the sensor a little time before we bug it
   while (!input(GP2D02_VOUT));    //wait for Vout to go high
   do {
      delay_cycles(4);             // minimum wait is 2us, max is 170us, 4 worked
      output_low(GP2D02_VIN);      // tell the sensor that we want a bit
      delay_cycles(2);             // might be as low as 1 (maybe), 2 worked
      reading=reading<<1;          // left shift the reading value
      reading=reading|(input(GP2D02_VOUT)); // put the newest reading into the
                                            // LSB of reading
      output_high(GP2D02_VIN);     // we read bit, and get ready for the next one
      counter--;
      } while (counter>0);

//LCD print statements====================================

      lcd_gotoxy(1,1);
      printf(lcd_putc," IR Measurement");
      lcd_gotoxy(1,2);
      printf(lcd_putc,"================");
      lcd_gotoxy(1,3);
      printf(lcd_putc,"Value = %3u", reading);
      lcd_gotoxy(1,4);
      printf(lcd_putc,"Position =%lu",position);
}

//Setup LCD, pins, Timer_0, interrupts====================

void main()
{
lcd_init();
setup_comparator(NC_NC_NC_NC);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_128);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(1);
}


Thanks....Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Mon Oct 24, 2005 11:39 am     Reply with quote

The period gets extended from 20 ms to 85 ms when I include the IR rangefinder routine within the ISR. I guess it must use up about 55 ms of time. Back to the drawing board!
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

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

PostPosted: Mon Oct 24, 2005 11:50 am     Reply with quote

Do as little as possible in an interrupt routine. If possible, set a flag and process it in the main loop.
kender



Joined: 09 Aug 2004
Posts: 768
Location: Silicon Valley

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Mon Oct 24, 2005 12:40 pm     Reply with quote

Put the IR rangefinder code into the main() loop together with all of the collision avoidance intelligence and the LCD code. It's unadvisable to have delays and slow serial communication in the ISR.
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