|
|
View previous topic :: View next topic |
Author |
Message |
alvin.ma
Joined: 04 Sep 2009 Posts: 10
|
18F4550 USB control servo problems |
Posted: Fri Sep 04, 2009 10:19 pm |
|
|
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
|
|
Posted: Sat Sep 05, 2009 1:26 am |
|
|
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
|
|
Posted: Sat Sep 05, 2009 5:24 am |
|
|
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
|
|
Posted: Wed Sep 16, 2009 7:11 pm |
|
|
Thank you, the problem is solved |
|
|
|
|
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
|