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

Emulating a hobby servo.....

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



Joined: 09 Aug 2004
Posts: 97

View user's profile Send private message

Emulating a hobby servo.....
PostPosted: Fri Apr 20, 2007 11:10 am     Reply with quote

Hi All,

I'm using a PIC12F629 to emulate a hobby servo. The PIC is connected to a hobby receiver and will be used to control a relay. The PIC measures the pulse width of the receiver output which varies from 1.0 mS to 2.0 mS, and switches the relay ON at about 1.6 mS, and OFF at about 1.4 mS - this hysteresis is added to prevent glitching around the switching point. I have this functionality working fine, but I'm having trouble getting a "loss of signal" feature to work - the pulses from the receiver repeat about every 20mS, and I'd like to turn OFF my relay whenever the pulse train goes away for a longer period. The input from the receiver can go either hi or low when the received signal is lost. Anyway, my code worked fine when I was just measuring the pulse width, but now that I'm trying to measure "frame period" as well, it no longer works. The problem is the relay switches ON/OFF rapidly whenever it seems like it should just be ON. All my attempts to find the problem have been unsuccessful. Here is the code:

Code:


#include <12F629.h>
#fuses INTRC_IO,NOWDT,NOBROWNOUT,NOPROTECT,MCLR
#use delay(clock=4000000)

#define Rx_Input          Pin_A4
#define Relay_Output       Pin_A2
#define LCD_Output          Pin_A0
#define LED_Output         Pin_A5
#define Off               0
#define On               1
#define Min_Width         0x08      // 1.0mS / 128uS = 08dec = 08h.         
#define Max_Width         0x0F      // 2.0mS / 128uS = 16dec = 0Fh.
#define Low_Trip          0x0A      // 1.4mS / 128uS = 10dec = 0Ah.
#define High_Trip          0x0B      // 1.6mS / 128uS = 12dec = 0Ch.
#define Max_Frame         0x9C      //  20mS / 128us = 156dec = 9Ch.

short Output;

#use rs232(baud=9600, xmit=LCD_Output)

void wait_for_low_to_high(void)
{
      set_rtcc(0);                              // reset Timer0
      while(input(Rx_Input))                        // here we see if the Rx_Input is high
      {
      if (get_rtcc() > Max_Frame)                  // still high, so we check for a time out
         {                                    // time out, so turn off output!!
         output_low(Relay_Output);
         output_low(LED_Output);
         Output = Off;
      }
   }

      while(!input(Rx_Input))                        // here we see if the Rx_Input is low
   {
      if (get_rtcc() > Max_Frame)                  // still low, so we check for a time out
      {                                    // time out, so turn off output!!
         output_low(Relay_Output);
         output_low(LED_Output);
         Output = Off;
      }
   }

}

void wait_for_low(void)
{
      while(input(Rx_Input))
   {
      if (get_rtcc() > Max_Frame)                  // still high, so we check for a time out
         {                                    // time out, so turn off output!!
         output_low(Relay_Output);
         output_low(LED_Output);
         Output = Off;
      }
   } 
}

void main(void)
{
   // Here we make our variable declarations.
      int PulseWidth;
   int BeginPulse;

   output_low(Relay_Output);
   output_low(LED_Output);
   Output = 0;

// Here we setup the counter. With the 4 MHz internal oscillator, the timer is updated every 1 uS.
// We further prescale this value by 128, so the actual timer increment period is 128 uS.

   setup_counters( RTCC_INTERNAL, RTCC_DIV_128 );
   
   while(1)
   {
         // Here we wait for the servo signal to go high. When it does, we zero the
      // timer and begin counting. As soon as the servo signal goes low again, we
      // read the RTCC to determine the pulse width.

      wait_for_low_to_high();
         BeginPulse = get_rtcc();
         wait_for_low();
         PulseWidth = (get_rtcc() - BeginPulse);

      // Here we add a little bit of protection if the pulse is too short, or too long.
      if (Pulsewidth < Min_Width)
         PulseWidth = Min_Width;
      
      if (Pulsewidth > Max_Width)
         PulseWidth = Max_Width;
      
      // Here we have some diagnostic code. Used for troubleshooting
         //printf("Counter value: %2X\n\r", PulseWidth);

      if ((Output == Off) && (PulseWidth >= High_Trip))
      {
         output_high(Relay_Output);
         output_high(LED_Output);
         Output = On;
      }

      if ((Output == On) && (PulseWidth <= Low_Trip))
      {
         output_low(Relay_Output);
         output_low(LED_Output);
         Output = Off;
      }

      }
 
}


_________________
John Morley
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Apr 20, 2007 4:37 pm     Reply with quote

Can you post the source code for the program that existed before
you made the changes to detect the lack of an input pulse ?
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Sat Apr 21, 2007 3:47 am     Reply with quote

the timer keeps rolling over from 255 to zero, I see no point to make tests like (get_rtcc() > Max_Frame)
John Morley



Joined: 09 Aug 2004
Posts: 97

View user's profile Send private message

PostPosted: Mon Apr 23, 2007 9:10 am     Reply with quote

Hi All,

PCM: I can do that if necessary. Basically, the code is the same except I don't do any timeout checking in the wait_for_low_to_high() and wait_for_low() routines..... I think my problem is related to the Timer0 rollover as suggested.....

libor: I think you found the root cause of my problem - Timer0 is rolling over approximately every 32 mS (128 uS X 255), and yet I keep checking it.

OK, I've been trying to come up with a solution to this problem, but nothing is readily apparent to me. I need to stay inside these two subroutines until the digital input criteria is met, while also checking to see if the total time spent in the routine exceeds my timeout. Obviously, once the timeout occurs I have to stop checking the timer....... Can one of you guys suggest a modification to my code to do this? The other possibility is that my code architecture is flawed - is this the best way to measure the width of a repetitive pulse, and also the time between successive pulses?

Thanks!
_________________
John Morley
John Morley



Joined: 09 Aug 2004
Posts: 97

View user's profile Send private message

PostPosted: Mon Apr 23, 2007 3:00 pm     Reply with quote

Hi All,

OK, I got it working by adding a boolean flag to each subroutine to disable the timeout check once a timeout had been reached. Now, things are still a bit tight using the divide by 128 clock prescaler as was necessary to allow Timer0 to count up to more than 20mS. I'm going to switch over to the 16 bit Timer1, and that should give me plenty of additional breathing room!

Thanks!
_________________
John Morley
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