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

18F4550 USB control servo problems

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



Joined: 04 Sep 2009
Posts: 10

View user's profile Send private message

18F4550 USB control servo problems
PostPosted: Fri Sep 04, 2009 10:19 pm     Reply with quote

Hi all,
I am going to use 18F4550 for controlling the two servo throught USB by enter command from PC.
In the beginning, I wrote the code for self controlling the servos, the result is ok.
Here is the code.
Code:

#include <18F4550.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)  // Jumpers: 8 to 11, 7 to 12

#include <stdlib.h>


//const int high = 1;
//const int low = 0;

int port_d_image=0;
int servo_state=0;
signed int16 SPW_1 = 58036;
signed int16 SPW_2 = 55536;
int16 different = 65536;
int16 Servo_1 = 1500;   // unit in us
int16 Servo_2 = 1500;   // unit in us
int16 a;

void servo_setting()
{

   SPW_1 = 65536 - (Servo_1 /0.2); //58036 = 1500us
   SPW_2 = 65536 - (Servo_2 /0.2); //55536 = 2000us
   different = 65536 - abs(SPW_1 - SPW_2);

}

#INT_TIMER1
void timer1_interrupt() {

   switch(servo_state)        // and set pin as needed
   {
   case 0:  if (Servo_1==Servo_2)
            {
               set_timer1(SPW_1);
               servo_state=3;
            }
            else if (Servo_1<Servo_2)
            {
               set_timer1(SPW_1);// sets timer to interrupt in (0xE2B4 for 1.5ms)
               servo_state=1;
            }
            else
            {
               set_timer1(SPW_2);
               servo_state=2;
            }
            bit_set(port_d_image,5);
            bit_set(port_d_image,6);
            setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
            break;
   case 1:  set_timer1(different);                       // sets timer to interrupt in (0xF63C for 0.5ms)
            bit_clear(port_d_image,5);
            setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
            servo_state+=2;
            break;
   case 2:  set_timer1(different);                       // sets timer to interrupt in (0xF63C for 0.5ms)
            bit_clear(port_d_image,6);
            setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
            servo_state++;
            break;
   default: set_timer1(0x3CB0);                       // sets timer to interrupt in 20ms (0x3CB0 for 10ms)
            bit_clear(port_d_image,5);
            bit_clear(port_d_image,6);
            setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
            servo_state=0;
   }
   output_d(port_d_image);                   // outputs the waveform
}


void wait() {           // This function waits for either ~1s or until a
  int countdown;        // event happens (in this case a rs232 character)
  countdown=100;
  while((--countdown!=0)&&!kbhit())
    delay_ms(10);
}

void main() {
   int8 data;
   set_tris_d(0);
   set_tris_b(1);
   servo_setting();
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);
   output_d(0);
   while( TRUE ) {
   
      //disable_interrupts(INT_TIMER1);
      bit_clear(port_d_image,5);
      bit_clear(port_d_image,6);
      Servo_1 = 1652;      //x-axis
      Servo_2 = 1541;      //y-axis
      servo_setting();
      //enable_interrupts(INT_TIMER1);
      wait();
     
      //disable_interrupts(INT_TIMER1);
      bit_clear(port_d_image,5);
      bit_clear(port_d_image,6);
      Servo_1 = 1402;
      Servo_2 = 1624;
      servo_setting();
      //enable_interrupts(INT_TIMER1);
      wait();
   
      //disable_interrupts(INT_TIMER1);
      bit_clear(port_d_image,5);
      bit_clear(port_d_image,6);
      Servo_1 = 1902;
      Servo_2 = 1458;
      servo_setting();
      //enable_interrupts(INT_TIMER1);
      wait();
     
  }
}

However, I find that this function no longer work properly as I added the USB function with usb_cdc.h the desired 1500us pulse width changed to 630us.....I feel frusrate on this problem, anyone can help me?
here is the code:
Code:

#include <18F4550.h>
#include <math.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP, VREGEN, USBDIV, HSPLL, PLL5, CPUDIV1, NODEBUG
#use delay (clock=20000000)

#include "usb_cdc.h"

int port_d_image=0;
int servo_state=0;
int16 x_servo=0;
int16 y_servo=0;
signed int16 SPW_1 = 58036;
signed int16 SPW_2 = 55536;
int16 different = 65536;
int16 Servo_1 = 7500;   // unit in us
int16 Servo_2 = 7500;   // unit in us


void servo_setting()
{

   SPW_1 = 65536 - (Servo_1); //58036 = 1500us
   SPW_2 = 65536 - (Servo_2); //55536 = 2000us
   different = 65536 - abs(SPW_1 - SPW_2);
}

void print_guide()
{
   printf(usb_cdc_putc, "\r\n\n1-2 get input 1&2");
   printf(usb_cdc_putc, "\r\n3-4 toggle output 1&2");
   printf(usb_cdc_putc, "\r\ni-read IR, s-read sonar");
   printf(usb_cdc_putc, "\r\nX - set servo x pulse width" );
   printf(usb_cdc_putc, "\r\nY - set servo x pulse width \n" );
}

int16 ASCII_to_int(char c)
{
   int16 temp_int =0;
   switch (c){
      case '0':
         temp_int=0;
         break;
      case '1':
         temp_int=1;
      break;
      case '2':
         temp_int=2;
      break;
      case '3':
         temp_int=3;
      break;
      case '4':
         temp_int=4;
      break;
      case '5':
         temp_int=5;
      break;
      case '6':
         temp_int=6;
      break;
      case '7':
         temp_int=7;
      break;
      case '8':
         temp_int=8;
      break;
      case '9':
         temp_int=9;
      break;
      default:
         break;
   }
   return (temp_int);
}
#INT_TIMER1
void timer1_interrupt()
{
   switch(servo_state)        // and set pin as needed
   {
   case 0:
      if (Servo_1==Servo_2) {
         set_timer1(SPW_1);
         servo_state=3;
      } else if (Servo_1<Servo_2) {
         set_timer1(SPW_1);// sets timer to interrupt in (0xE2B4 for 1.5ms)
         servo_state=1;
      } else {
         set_timer1(SPW_2);
         servo_state=2;
      }
      bit_set(port_d_image,6);
      bit_set(port_d_image,5);
      setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
      break;
   case 1:
      set_timer1(different);                       // sets timer to interrupt in (0xF63C for 0.5ms)
      bit_clear(port_d_image,6);
      setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
      servo_state+=2;
      break;
   case 2:
      set_timer1(different);                       // sets timer to interrupt in (0xF63C for 0.5ms)
      bit_clear(port_d_image,5);
      setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
      servo_state++;
      break;
   default:
      set_timer1(0x3CB0);                       // sets timer to interrupt in 20ms (0x3CB0 for 10ms)
      bit_clear(port_d_image,6);
      bit_clear(port_d_image,5);
      setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
      servo_state=0;
   }
   output_d(port_d_image);      // outputs the waveform
}

void main()
{

   int16 temp_int;
   char c;
   unsigned char arr[6];         // Buffer for the sent bytes
   
   set_tris_d(6);
   servo_setting();
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);
   
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0);
   set_adc_channel(0);
   
   servo_setting();
    usb_init();

   while (TRUE) {
   
      if (usb_enumerated()) {
     
         if (usb_cdc_kbhit()) {
            c=usb_cdc_getc();
 
               if (c=='x') {
                  printf(usb_cdc_putc,"\r\nServo X pulse width in us (1000-2000, step: 1us): ");
                  x_servo=0;

                 
                  temp_int=ASCII_to_int(usb_cdc_getc());
                  printf(usb_cdc_putc,"%LU", temp_int);
                  x_servo=temp_int * 1000;
                 
                  temp_int=ASCII_to_int(usb_cdc_getc());
                  printf(usb_cdc_putc,"%LU", temp_int);
                  x_servo=temp_int * 100 + x_servo;
                 
                  temp_int=ASCII_to_int(usb_cdc_getc());
                  printf(usb_cdc_putc,"%LU", temp_int);
                  x_servo=temp_int * 10 + x_servo;
                 
                  temp_int=ASCII_to_int(usb_cdc_getc());
                  printf(usb_cdc_putc,"%LU", temp_int);
                  x_servo=temp_int + x_servo;

                  printf(usb_cdc_putc,"\r\nServo X pulse width %LU ", x_servo);
                  Servo_1 = 5 * x_servo ;
                  print_guide();
                   
               }

               bit_clear(port_d_image,6);
               bit_clear(port_d_image,5);
               servo_setting();           
         }
         delay_ms(5);
      }
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Sep 05, 2009 1:26 am     Reply with quote

Quote:

signed int16 SPW_1 = 58036;
signed int16 SPW_2 = 55536;
int16 different = 65536;

I didn't look closely at your code, but I noticed a few problems.

A 'signed int16' can't hold a positive number of 58036. The range of
values that it can hold is -32768 to 32767.

Also, an 'int16' can't hold 65536. It can hold a positive number in the
range from 0 to 65535.


Quote:
#include <18F4550.h>
#include <math.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP, VREGEN, USBDIV, HSPLL, PLL5, CPUDIV1, NODEBUG
#use delay (clock=20000000)

In the code above, you have two oscillator fuses, HS and HSPLL.
That's wrong. You should only use one fuse. I'll assume that you
really want to use HSPLL. If so, your #use delay() statement is wrong.
With a 20 MHz crystal, and the HSPLL and PLL5 fuses, your PIC is running
at 48 MHz. The #use delay() statement should be changed to show this.


Your program may have other bugs or things that are not coded in an
efficient way. I don't have time to look at more of them right now.
Ttelmah
Guest







PostPosted: Sat Sep 05, 2009 5:24 am     Reply with quote

The problem is your clock fuses.
You need to select _either_ HS (which will then run the CPU at 20MHz - set clock accordingly), _or_ HSPLL, in which case the CPU will run at 48MHz. You then need to adjust the clock setting to match this.
You have both selected, and if you 'or' them together, you get the HSPLL behaviour, giving you a 48MHz CPU clock, and with the clock statement set to 20MHz, timings 20/48 the length they should be......

Best Wishes
alvin.ma



Joined: 04 Sep 2009
Posts: 10

View user's profile Send private message

PostPosted: Wed Sep 16, 2009 7:11 pm     Reply with quote

Thank you, the problem is solved Smile
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