go_away

Author Topic: Servo Motor Control w/ the PIC16F684  (Read 7795 times)

0 Members and 1 Guest are viewing this topic.

Offline CanabotsTopic starter

  • Contest Winner
  • Robot Overlord
  • ****
  • Posts: 245
  • Helpful? 6
  • It's not a bug, it's a feature!
Servo Motor Control w/ the PIC16F684
« on: October 15, 2008, 07:21:54 PM »
Hi,

I was wondering if anyone here would know how to implement servo control on a PIC16F684 using the PICkit 1. The programming software is the MPLAB IDE using C as the programming language and the PIC C Lite compiler. I've done a few searches on the internet and I own the book "123 PIC Microcontroller Experiments for the Evil Genius", though they have either shown only programs written in assembly language or the program that is in the book. I was wondering if anyone knows a simple program to make the servos go or backwards. 

Help is much appreciated :)

Canabots
My robotics, electronics, software, or other stuff blog:
www.saltech.wordpress.com

Offline Admin

  • Administrator
  • Supreme Robot
  • *****
  • Posts: 11,659
  • Helpful? 169
    • Society of Robots
Re: Servo Motor Control w/ the PIC16F684
« Reply #1 on: October 16, 2008, 09:46:39 PM »
This will help you understand it:
http://www.societyofrobots.com/actuators_servos.shtml

Just use the same code as from another PIC, but redefine the PIC and the output pins you are using.

Offline ArcMan

  • Supreme Robot
  • *****
  • Posts: 519
  • Helpful? 4
  • Mmmm... Plasma
Re: Servo Motor Control w/ the PIC16F684
« Reply #2 on: October 17, 2008, 09:14:58 AM »
This may not be as simple as you'd like, but here is a program I wrote to position servos (with speed control).  It accepts commands over the serial port.  The compiler is from CCS.

Code: [Select]
#include <16F873.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(SLAVE, SCL=PIN_C3, SDA=PIN_C4, ADDRESS=0xA0, FAST, FORCE_HW)

#include <stdlib.h>
#include <input.c>

static short pa1_rcvd = FALSE; // First byte of preamble received
static int pdata_byte = 0; // Packet data byte number
static int cmd_channel; // Commanded servo channel number (1-8)
static long cmd_pdur; // Commanded servo pulse duration
static int cmd_rate; // Commanded servo move rate (us per servo pulse - there are 50 pulses / sec)
static long pdur_msb;

#INT_SSP
void ssp_interupt ()
{
int rcv_data;

rcv_data = i2c_read(); // This is the I2C address byte
rcv_data = i2c_read(); // Data byte

if (pdata_byte > 0 ) { // The preamble has been received
switch (pdata_byte) {
case 1:
cmd_channel = rcv_data;
pdata_byte++;
break;
case 2:
pdur_msb = rcv_data;
pdata_byte++;
break;
case 3:
cmd_pdur = (pdur_msb<<8) | rcv_data;
pdata_byte++;
break;
case 4:
cmd_rate = rcv_data;
pdata_byte++;
break;
default:
break;
}
}

if (rcv_data == 0xFF) {
if (pa1_rcvd) // This is the second byte of the preamble
pdata_byte = 1; // Set packet data byte number to 1
else
pa1_rcvd = TRUE; // This may be the first byte of the preamble
}
else
pa1_rcvd = FALSE;
}

void main()
{
#define CH1_SP PIN_C5 // Channel 1 servo pulse output

// Pulse duration limits
#define PD_MAX 2000
#define PD_MIN 1000

long tpdur[9] = {0, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; // Target pulse duration
long cpdur[9] = {0, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; // Current pulse duration - used for rate function
int rate[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
long t1_preset;
int active_pulse, i, j;

// Float the I2C pins
output_float(PIN_C3);
output_float(PIN_C4);

output_low(CH1_SP);

// Timer 0 is the R/C servo pulse cycle timer
// Set to internal clock (5 MHz) / 256 = 51.2 us per count
// This produces a maximum delay of 13.1 ms, so the timer will have to be used twice per desired 20 ms cycle period.
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);

// Timer 1 is the R/C servo pulse duration timer
// Set to internal clock (5 MHz) = 0.2 us per count
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);

// Enable interrupts
enable_interrupts(INT_TIMER1); // Enable the Timer 1 overflow interrupt
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);

// Servo pulse cycle loop - executes once every 20 ms
while (TRUE) {
active_pulse = 1;

// Calculate the current pulse durations if the rate function is used (rate != 0)
for (j=1; j<=8; j++) { // For each servo channel
if (rate[j]>0 && tpdur[j]>cpdur[j]) {
cpdur[j] = cpdur[j] + rate[j];
if (cpdur[j] > tpdur[j])
cpdur[j] = tpdur[j];
}
if (rate[j]>0 && tpdur[j]<cpdur[j]) {
cpdur[j] = cpdur[j] - rate[j];
if (cpdur[j] < tpdur[j])
cpdur[j] = tpdur[j];
}
}

// Initiate Channel 1 pulse
t1_preset = 65536 - (cpdur[1] *5);
set_timer1(t1_preset);
output_high(CH1_SP);

// Wait 20 ms while watching for incoming I2C messages
for (i=0; i<=1; i++) {
set_timer0(0); // Clear the servo pulse cycle timer
while (get_timer0() < 195) { // delay 10 ms
if (pdata_byte == 5) { // A full servo position command packet has been received
pdata_byte = 0;
if (cmd_channel >= 1 && cmd_channel <= 8) { // A valid channel has been commanded

// Calculate the commanded pulse duration and limit it
if (cmd_pdur > PD_MAX)
cmd_pdur = PD_MAX;
if (cmd_pdur < PD_MIN)
cmd_pdur = PD_MIN;
tpdur[cmd_channel] = cmd_pdur; // Set the pulse duration for the commanded channel
rate[cmd_channel] = cmd_rate; // Set the rate for the commanded channel

// If the commanded rate is 0 (no rate setting), set current pulse duration to commanded pulse duration.
if (cmd_rate == 0)
cpdur[cmd_channel] = cmd_pdur;


}
}
}
}
}
}

// Timer 1 overflow interrupt handler
// Timer 1 overflows at the end of the servo pulse duration
#INT_TIMER1
void t1_handler()
{
output_low(CH1_SP);
}

Offline CanabotsTopic starter

  • Contest Winner
  • Robot Overlord
  • ****
  • Posts: 245
  • Helpful? 6
  • It's not a bug, it's a feature!
Re: Servo Motor Control w/ the PIC16F684
« Reply #3 on: October 18, 2008, 04:17:27 PM »
To Admin: I never knew you could take code from another PIC and have it work without much hassle. I tried some easy servo code I found on the Internet, made some adjustments and it compiled no problem. I have also read and enjoyed many of the tutorials on your site. Thanks

To ArcMan: Thank you for that code. It is a little advanced for me, but I can't wait to try it!


Thanks Again :D

Canabots
« Last Edit: October 18, 2008, 04:22:55 PM by Canabots »
My robotics, electronics, software, or other stuff blog:
www.saltech.wordpress.com

 


Get Your Ad Here