diff options
Diffstat (limited to 'msp430/libraries/Servo')
| -rw-r--r-- | msp430/libraries/Servo/Servo.cpp | 207 | ||||
| -rw-r--r-- | msp430/libraries/Servo/Servo.h | 83 | ||||
| -rw-r--r-- | msp430/libraries/Servo/examples/Knob/Knob.ino | 22 | ||||
| -rw-r--r-- | msp430/libraries/Servo/examples/Sweep/Sweep.ino | 31 | ||||
| -rw-r--r-- | msp430/libraries/Servo/keywords.txt | 24 |
5 files changed, 367 insertions, 0 deletions
diff --git a/msp430/libraries/Servo/Servo.cpp b/msp430/libraries/Servo/Servo.cpp new file mode 100644 index 0000000..8853dd9 --- /dev/null +++ b/msp430/libraries/Servo/Servo.cpp @@ -0,0 +1,207 @@ +/*
+ Servo.cpp - Interrupt driven Servo library for MSP430
+ Copyright (c) 2012 Petr Baudis. All right reserved.
+ Modified by Peter Brier 26-6-2012: Fixed timing/IRQ problem
+
+ Derived from:
+ Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
+ Copyright (c) 2009 Michael Margolis. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Energia.h"
+#include "Servo.h"
+
+#define F_TIMER (F_CPU/8L)
+#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to timer ticks (assumes prescale of 8)
+#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
+
+#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
+
+
+#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
+#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
+
+
+/************ static functions and data structures common to all instances ***********************/
+
+
+static servo_t servos[MAX_SERVOS]; // static array of servo structures
+static unsigned int ServoCount = 0; // the total number of attached servos
+
+static volatile int counter = 0; // Servo counter; -1 before first servo starts being serviced
+static volatile unsigned int totalWait = 0; // Total amount waited so far in the current period; after all servos, wait for the rest of REFRESH_INTERVAL
+
+#ifndef TIMERA0_VECTOR
+#define TIMERA0_VECTOR TIMER0_A0_VECTOR
+#endif /* TIMER0_A0_VECTOR */
+
+// Timer A0 interrupt service routine
+static void
+Timer_A(void)
+{
+ static unsigned long wait;
+ if (counter >= 0) {
+ /* Turn pulse off. */
+ digitalWrite(servos[counter].Pin.nbr, LOW);
+ }
+
+ /* Service next servo, while skipping any inactive servo records. */
+ do {
+ counter++;
+ } while (!servos[counter].Pin.isActive && counter < ServoCount);
+
+ // Counter range is 0-ServoCount, the last count is used to complete the REFRESH_INTERVAL
+ if (counter < ServoCount) {
+ /* Turn pulse on for the next servo. */
+ digitalWrite(servos[counter].Pin.nbr, HIGH);
+ /* And hold! */
+ totalWait += servos[counter].ticks;
+ CCR0 = servos[counter].ticks;
+ } else {
+ /* Wait for the remaining of REFRESH_INTERVAL. */
+ wait = usToTicks(REFRESH_INTERVAL) - totalWait;
+ totalWait = 0;
+ CCR0 = (wait < 1000 ? 1000 : wait);
+ counter = -1;
+ }
+}
+
+// Timer A0 interrupt service routine
+__attribute__((interrupt(TIMERA0_VECTOR)))
+static void
+Timer_A_int(void)
+{
+ Timer_A();
+}
+
+static boolean isTimerActive(void)
+{
+ // returns true if any servo is active
+ for(int i = 0; i < MAX_SERVOS; i++)
+ if (servos[i].Pin.isActive == true)
+ return true;
+ return false;
+}
+
+static void enableTimer(void)
+{
+ counter = -1;
+ totalWait = 0;
+
+ Timer_A(); // enable first servo
+
+ CCTL0 = CCIE; // CCR0 interrupt enabled
+ TACTL = TASSEL_2 + MC_1 + ID_3; // prescale SMCLK/8, upmode
+}
+
+static void disableTimer(void)
+{
+ // disable interrupt
+ CCTL0 = 0;
+ CCR0 = 0;
+}
+
+
+/****************** end of static functions ******************************/
+
+Servo::Servo()
+{
+ if( ServoCount < MAX_SERVOS) {
+ this->servoIndex = ServoCount++; // assign a servo index to this instance
+ servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values
+ }
+ else
+ this->servoIndex = INVALID_SERVO ; // too many servos
+}
+
+uint8_t Servo::attach(int pin)
+{
+ return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
+}
+
+uint8_t Servo::attach(int pin, int min, int max)
+{
+ if(this->servoIndex < MAX_SERVOS ) {
+ pinMode( pin, OUTPUT) ; // set servo pin to output
+ servos[this->servoIndex].Pin.nbr = pin;
+
+ // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
+ this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
+ this->max = (MAX_PULSE_WIDTH - max)/4;
+
+ boolean timer_active = isTimerActive();
+ servos[this->servoIndex].Pin.isActive = true;
+ if (!timer_active)
+ enableTimer();
+ }
+ return this->servoIndex ;
+}
+
+void Servo::detach()
+{
+ servos[this->servoIndex].Pin.isActive = false;
+ if (!isTimerActive())
+ disableTimer();
+}
+
+void Servo::write(int value)
+{
+ if(value < MIN_PULSE_WIDTH)
+ { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
+ if(value < 0) value = 0;
+ if(value > 180) value = 180;
+ value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
+ }
+ this->writeMicroseconds(value);
+}
+
+void Servo::writeMicroseconds(int value)
+{
+ // calculate and store the values for the given channel
+ byte channel = this->servoIndex;
+ if( (channel < MAX_SERVOS) ) // ensure channel is valid
+ {
+ if( value < SERVO_MIN() ) // ensure pulse width is valid
+ value = SERVO_MIN();
+ else if( value > SERVO_MAX() )
+ value = SERVO_MAX();
+ value = value - TRIM_DURATION;
+ value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
+ servos[channel].ticks = value; // this is atomic on a 16bit uC, no need to disable Interrupts
+ }
+}
+
+int Servo::read() // return the value as degrees
+{
+ return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
+}
+
+int Servo::readMicroseconds()
+{
+ unsigned int pulsewidth;
+ if( this->servoIndex != INVALID_SERVO )
+ pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION;
+ else
+ pulsewidth = 0;
+
+ return pulsewidth;
+}
+
+bool Servo::attached()
+{
+ return servos[this->servoIndex].Pin.isActive ;
+}
diff --git a/msp430/libraries/Servo/Servo.h b/msp430/libraries/Servo/Servo.h new file mode 100644 index 0000000..27a6a31 --- /dev/null +++ b/msp430/libraries/Servo/Servo.h @@ -0,0 +1,83 @@ +/* + Servo.h - Interrupt driven Servo library for MSP430 + Copyright (c) 2012 Petr Baudis. All right reserved. + Modified by Peter Brier 26-6-2012: Fixed timing/IRQ problem + + Derived from: + Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 + Copyright (c) 2009 Michael Margolis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Servo_H +#define Servo_H + +#include <inttypes.h> + +/* + This version attempts to be compatible with the Arduino Servo library, + but supports only a single timer. So do not add too many servos. :-) + */ + +/* + Note that the Servo uses TIMER0_A, which cannot be used for other + purposes, e.g. for TimerSerial. + + XXX: Also, some pins reused by TIMER0_A may be affected by this + library, but I do not understand the datasheet enough regarding this. + Most likely, you should avoid PWM on pin 2? (And other stuff too?) + */ + +#define Servo_VERSION 2 // software version of this library + +#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo [uS] +#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo [uS] +#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached +#define REFRESH_INTERVAL 20000 // servos refresh period in microseconds + +#define MAX_SERVOS 8 + +#define INVALID_SERVO 255 // flag indicating an invalid servo index + +typedef struct { + uint8_t nbr :6 ; // a pin number from 0 to 63 + uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false +} ServoPin_t; + +typedef struct { + ServoPin_t Pin; + unsigned int ticks; +} servo_t; + +class Servo +{ +public: + Servo(); + uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure + uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. + void detach(); + void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + int read(); // returns current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) + bool attached(); // return true if this servo is attached, otherwise false +private: + uint8_t servoIndex; // index into the channel data for this servo + int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH + int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH +}; + +#endif diff --git a/msp430/libraries/Servo/examples/Knob/Knob.ino b/msp430/libraries/Servo/examples/Knob/Knob.ino new file mode 100644 index 0000000..886e107 --- /dev/null +++ b/msp430/libraries/Servo/examples/Knob/Knob.ino @@ -0,0 +1,22 @@ +// Controlling a servo position using a potentiometer (variable resistor) +// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott> + +#include <Servo.h> + +Servo myservo; // create servo object to control a servo + +int potpin = 0; // analog pin used to connect the potentiometer +int val; // variable to read the value from the analog pin + +void setup() +{ + myservo.attach(9); // attaches the servo on pin 9 to the servo object +} + +void loop() +{ + val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023) + val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (value between 0 and 180) + myservo.write(val); // sets the servo position according to the scaled value + delay(15); // waits for the servo to get there +} diff --git a/msp430/libraries/Servo/examples/Sweep/Sweep.ino b/msp430/libraries/Servo/examples/Sweep/Sweep.ino new file mode 100644 index 0000000..fb326e7 --- /dev/null +++ b/msp430/libraries/Servo/examples/Sweep/Sweep.ino @@ -0,0 +1,31 @@ +// Sweep +// by BARRAGAN <http://barraganstudio.com> +// This example code is in the public domain. + + +#include <Servo.h> + +Servo myservo; // create servo object to control a servo + // a maximum of eight servo objects can be created + +int pos = 0; // variable to store the servo position + +void setup() +{ + myservo.attach(9); // attaches the servo on pin 9 to the servo object +} + + +void loop() +{ + for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees + { // in steps of 1 degree + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } + for(pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees + { + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } +} diff --git a/msp430/libraries/Servo/keywords.txt b/msp430/libraries/Servo/keywords.txt new file mode 100644 index 0000000..ca5ba79 --- /dev/null +++ b/msp430/libraries/Servo/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map Servo +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Servo KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +read KEYWORD2 +attached KEYWORD2 +writeMicroseconds KEYWORD2 +readMicroseconds KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### |
