Go Down

Topic: need help making a library (Read 476 times) previous topic - next topic

jm

Oct 31, 2007, 01:16 am Last Edit: Oct 31, 2007, 01:32 am by jm Reason: 1
hi all -

i've written some r/c servo controller code. i'd like to release it as a library. i downloaded the Test library example, but i just can't understand it at all. i have absolutely no idea where to put all the different parts of my code. i don't know c++, only c. could anyone give me some clues? here's the code as written into a sketch, which works fine:

Code: [Select]

// eight-channel servo system - by Jeff Mann copyright 2007 all rights reserved

// if we have an ATmega168, we can use timer 0, which is running in
// fast pwm mode, and keep timer 2 available for phase correct pwm.
// NOTE: this requires that the timer0 overflow interrupt routine in
// lib/targets/arduino/wiring.c be commented out! find the following:
//
// SIGNAL(SIG_OVERFLOW0)
// {
//      timer0_overflow_count++;
// }
// ...and comment it out. remember to re-enable it for other programs!

#if defined(__AVR_ATmega168__)
#define USE_TIMER_0
#endif

// limits on servo pulse width - standard is 1000-2000 microseconds
// wide is roughly 500-2250 microseconds, but that may damage your servo!
#define MAX_SERVO_PULSE 2000
#define MIN_SERVO_PULSE 1000

// utilities to clear/set bits in special function registers
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#define TRUE 1
#define FALSE 0

#define SERVO 3 // as opposed to INPUT or OUTPUT

/* variables for Servos */
extern volatile unsigned long timer0_overflow_count; // timer0 from wiring.c
int servoStatus = 0; // define which servo pins output pulses or not
byte processServos = FALSE;
byte servoCount = 0;
byte cycleCount = 0;
byte cycles;
byte turnOff = 0;

// define the mapping of logical servo numbers to arduino pins.
// it's not recommended to change this. if you want to,
// you can re-arrange these, but you must always have exactly 8 servos,
// listed here (numbered 0-7), whether you use them or not.
#define TOTAL_DIGITAL_PINS 14
#define NOT_A_SERVO 255
byte digital_pin_to_servo_array[14] = {
 NOT_A_SERVO, // pin 0 - RX - cannot use
 NOT_A_SERVO, // pin 1 - TX - cannot use
 0,           // pin 2
 1,           // pin 3 - PWM 2B on ATmega168
 2,           // pin 4
 3,           // pin 5 - PWM 0B on ATmega168
 4,           // pin 6 - PWM 0A on ATmega168, but not working if using servos
 5,           // pin 7
 6,           // pin 8
 NOT_A_SERVO, // pin 9  - PWM 1A
 NOT_A_SERVO, // pin 10 - PWM 1B
 NOT_A_SERVO, // pin 11 - PWM 2(A) but not working on atmega8 when using servos
 7,           // pin 12
 NOT_A_SERVO, // pin 13 - LED
};


typedef struct {
 byte pin;
 byte cycles;
 byte ticks;
}
servo_t;

servo_t servo_array[8];

#ifdef USE_TIMER_0
ISR(TIMER0_OVF_vect) {
 timer0_overflow_count++; // for millis() clock
 if(processServos) {
   if((cycleCount == 0) && (servoStatus & (1 << servo_array[servoCount].pin))) {
     digitalWrite(servo_array[servoCount].pin, HIGH);
   }
   if(cycleCount == cycles) turnOff = TRUE;
   ++cycleCount;
 }
}

ISR(TIMER0_COMPA_vect) {
 if(processServos) {
   // turn off the pin for the current servo if flagged
   if(turnOff) {
     if(servoStatus & (1 << servo_array[servoCount].pin)) {
       digitalWrite(servo_array[servoCount].pin, LOW);
     }
     turnOff = FALSE;
   }
   if(cycleCount == 3) {
     if(++servoCount > 7) servoCount = 0;
     // load values for next cycle
     cycles = servo_array[servoCount].cycles;
     OCR0A = servo_array[servoCount].ticks;
     cycleCount = 0;
   }
 }
}
#else
ISR(TIMER2_OVF_vect) {
 if(processServos) {
   if((cycleCount == 0) && (servoStatus & (1 << servo_array[servoCount].pin))) {
     digitalWrite(servo_array[servoCount].pin, HIGH);
   }
   if(cycleCount == cycles) turnOff = TRUE;
   ++cycleCount;
 }
}

ISR(TIMER2_COMP_vect) {
 if(processServos) {
   // turn off the pin for the current servo if flagged
   if(turnOff) {
     if(servoStatus & (1 << servo_array[servoCount].pin)) {
       digitalWrite(servo_array[servoCount].pin, LOW);
     }
     turnOff = FALSE;
   }
   if(cycleCount == 3) {
     if(++servoCount > 7) servoCount = 0;
     // load values for next cycle
     cycles = servo_array[servoCount].cycles;
     OCR2 = servo_array[servoCount].ticks;
     cycleCount = 0;
   }
 }
}
#endif

// continued in next post!



jm

(the rest of the code)

Code: [Select]

// (continued from previous post!!
// eight-channel servos - copyright Jeff Mann 2007 all rights reserved

// user api
// -----------------------------------------------------------------------------
// turns on a servo pulse of the specified length, on the specified pin
// note: disables pwm on pin 11 (pin 6 on ATmega168) if used.
void servoWrite(byte pin, int microseconds) {
 if(digital_pin_to_servo_array[pin] != NOT_A_SERVO) {
   if((! servoStatus) || (processServos == FALSE)) {
     // no servos are active, need to reconfigure pwm timer for servos' use
#ifdef USE_TIMER_0
     // using timer 0 on ATmega168 "arduino plus", already in fastpwm mode
     cbi(TCCR0A, COM0A1); // disconnect timer 0A from pwm output pin 6
#else
     // using timer 2 on ATmega8
     cbi(TCCR2,COM21);  // disconnect timer 2 from pwm output pin 11
     sbi(TCCR2,WGM21);  // set timer 2 for fast pwm mode
#endif
     processServos = TRUE; // flag ISR to process servo pulses
   }

   if ( microseconds > MAX_SERVO_PULSE ) {
     microseconds = MAX_SERVO_PULSE;
   }
   else if ( microseconds < MIN_SERVO_PULSE ) {
     microseconds = MIN_SERVO_PULSE;
   }
   servoStorePulseWidth(digital_pin_to_servo_array[pin], microseconds);
   if(!(servoStatus & (1 << pin))) { // if this servo is not already active
     setPinMode(pin, SERVO); // register this pin as active with a servo
   }

 }
}

void setPinMode(byte pin, byte mode) {
 if(mode == SERVO) {
   if(digital_pin_to_servo_array[pin] != NOT_A_SERVO) {
     servoStatus = servoStatus | (1 << pin);
     pinMode(pin,OUTPUT);
   }
   else if(mode == INPUT) {
     servoStatus = servoStatus &~ (1 << pin);
     pinMode(pin,INPUT);
   }
   else if(mode == OUTPUT) {
     servoStatus = servoStatus &~ (1 << pin);
   }
 }
}


// private functions
// -----------------------------------------------------------------------------
// convert microseconds to timer cycles + ticks, and store in the servo array
void servoStorePulseWidth(byte servoNumber, int microseconds) {
 // divide microseconds by 4 to get total number of 4uS timer ticks
 microseconds = microseconds >> 2;
 // divide by 256 to get number of 256-tick cycles
 servo_array[servoNumber].cycles = microseconds >> 8;  
 // get leftover number of ticks
 servo_array[servoNumber].ticks = microseconds % 256;
}


// example sketch

int servoPosition1 = 1500;
int servoPosition2 = 1500;
int servoPosition3 = 1500;

void setup() {

 byte i;

 // servo stuff:
 // initialize pin data in servo array so we can do a reverse lookup
 for(i = 0; i < TOTAL_DIGITAL_PINS; ++i) {
   if (digital_pin_to_servo_array[i] != NOT_A_SERVO) {
     servo_array[digital_pin_to_servo_array[i]].pin = i;
   }
 }
 // initialize position data in servo array. these are never actually
 // output, but required to have sane values in the array.
 for (i=0; i<=7; ++i) {
   servoStorePulseWidth(i, 1500);
   

 }

 // turn on timer interrupts for servos. interrupt service routines will be
 // active, but not output any pulses until servoWrite() is called.
#ifdef USE_TIMER_0
 // using timer 0, compare unit A, for servo pulses. already set for /64
 // prescale and overflow interrupt enabled, for arduino millis() clock.
 // already set for fastpwm for "arduino plus" additional pwm outputs.
 sbi(TIMSK0, OCIE0A); // enable timer 0A compare match interrupt
#else
 // using timer 2 compare unit for servo pulses. already set for /64
 // prescale. initially set for phase correct pwm output; we will change
 // that when servoWrite() is called. here we enable the interrupts.
 sbi(TIMSK,TOIE2);  // enable timer 2 overflow interrupt
 sbi(TIMSK, OCIE2); // enable timer 2 compare match interrupt
#endif

processServos = TRUE; // turns on pulse outputs

 // user setup stuff goes here
 
 //Serial.begin(9600); // 9600, 14400, 38400, 57600, 115200

}

// symbolic names for pin numbers
#define servoPin1 2
#define servoPin2 4
#define servoPin3 6
#define ledPin 13


void loop() {
 
 digitalWrite(ledPin, HIGH);   // sets the LED on

 servoWrite(servoPin1, servoPosition1); // turns on servo pulse on pin 2
 servoWrite(servoPin2, servoPosition2);
 servoWrite(servoPin3, servoPosition3);
 servoPosition1 += 1;
 if (servoPosition1 > 2000) servoPosition1 = 1000;
 servoPosition2 += 1;
 if (servoPosition2 > 2000) servoPosition2 = 1000;
 servoPosition3 += 1;
 if (servoPosition3 > 2000) servoPosition3 = 1000;
 
 delay(5);

}

mellis

I wrote a tutorial on writing libraries.  I hope it helps answer some of your questions.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy