Pages: [1]   Go Down
Author Topic: help with interrupts for installation  (Read 783 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I am working on an installation that uses a sensor, a Servo motor and a lot of LEDs through shift register. Each of that parts work fine so far, but now that I want to combine them, I get an error: the standard Arduino library for Servos as well as the script that I use for the LEDs (http://www.picano.nl/microcontrollers/arduino/control-many-leds-with-pwm) are both using timer1 for interrupts - and this seems to create a conflict "multiple definition of `__vector_11'".

I am not familiar with interrupts and its programming. Can someone please give me a hint what I can do to avoid the conflict?
I have read, that timer2 could be used as well, but it is 8bit instead of 16 bits. Should I change one of the parts from timer1 to timer2? (Generally I would say this installation does need more precision for the LEDs than for the servo, but I have no idea how an 8bit based interrupt would effect the Servo).

thx alot in advance,
ullala :-)
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8601
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Best post your code, but you must have two ISR(xx) functions.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

ok. The first part is the code for fading LEDs with shiftregister (adapted from http://www.picano.nl/microcontrollers/arduino/control-many-leds-with-pwm)
If I activate line one as first step to combine it with Servo motor, the error happens.

Code:
//#include <Servo.h> // if activating this line -> error


#define __dataPin 8
#define __clockPin 9
#define __latchPin 10

#define __dataBit 0
#define __clockBit 1
#define __latchBit 2
#define __shiftPORT PORTB

#define numLedsInArray 18
#define __numPinsPerLed 3
#define maxBrightness 99
#define __invertOutputs  // if defined, outputs are inverted
#define __ledFreq 60

#define indexRed 0
#define indexGre 1
#define indexBlu 2
#define __numOutputs numLedsInArray*__numPinsPerLed


unsigned char LEDstates[numLedsInArray][__numPinsPerLed];

/* Let a pointer point to the first led. (& means 'the address of')  */
unsigned char * ledStart = &LEDstates[0][0];

/* Let a pointer point to the last led. (& means 'the address of')  */
unsigned char * ledEnd = &LEDstates[numLedsInArray-1][__numPinsPerLed-1];


//########################################\\

void setup() {    
  int k;
  /* Set all duty cycles to zero */
  for(k=0 ; k<(__numOutputs);k++){
    ledStart[k]=0;
  }
  
  // initialize the shift reg control pins as outputs:
  pinMode(__dataPin, OUTPUT);
  pinMode(__clockPin, OUTPUT);
  pinMode(__latchPin, OUTPUT);

  /* Setup timer: configure and enable timer1 for a compare and match A interrupt.
   * Configuring the timer is done by setting registry bits to the correct setting. */

  /* Configure timer1 in CTC mode: clear the timer on compare match
   * See the Atmega328 Datasheet 15.9.2 for an explanation on CTC mode.
   * See table 15-4 in the datasheet. */

  bitSet(TCCR1B,WGM12);
  bitClear(TCCR1B,WGM13);
  bitClear(TCCR1A,WGM11);
  bitClear(TCCR1A,WGM10);


  /*  Select clock source: internal I/O clock, without a prescaler
   *  This is the fastest possible clock source for the highest accuracy.
   *  See table 15-5 in the datasheet. */

  bitSet(TCCR1B,CS10);
  bitClear(TCCR1B,CS11);
  bitClear(TCCR1B,CS12);

  /* The timer will generate an interrupt when the value we load in OCR1A matches the timer value.
   * One period of the timer, from 0 to OCR1A will therefore be (OCR1A+1)/(timer clock frequency).
   * We want the frequency of the timer to be (LED frequency)*(number of brightness levels)
   * So the value we want for OCR1A is: timer clock frequency/(LED frequency * number of bightness levels)-1 */
  OCR1A = round(16E6/(__ledFreq*(maxBrightness+1)))-1;
  /* Finally enable the timer interrupt
  /* See datasheet  15.11.8) */
  bitSet(TIMSK1,OCIE1A);
  Serial.begin(9600);
  
  // ullala starting code 
}

//########################################\\


/* Install the Interrupt Service Routine (ISR) for Timer1 compare and match A.
 * We can define a function on the interrupt vector that corresponds to this interrupt source.
 * See table  11-1 for the interrupt vectors */
ISR(TIMER1_COMPA_vect) {

  /* Define a counter that will increase 1 with every interrupt.
   * By defining it as a static variable it will survive between function calls.
   * A static variable is automatically initialized to zero. */
  static unsigned char counter;

  /* Define a pointer that will be used to access the values for each led */
  unsigned char * ledPtr;

  /* Write shift register latch clock low */
  bitClear(PORTB,__latchBit);
  /* loop over all leds. Led 0 is sent out latest, so it is output 0 of the first shift register.
  /* This loop takes 20 clockcycles the comparison is true, 19 when it is false.*/
  for (ledPtr = ledEnd; ledPtr >= ledStart ; ledPtr--)  {

    /* Write shift register shift clock low */
    bitClear(PORTB,__clockBit); // Write SHIFT clock LOW
    /* #ifndef means: if not defined. By this define, you choose to invert the outputs  
     * The difference with a normal if statement, is that it is chosen at compile time:
     * only one of the two lines will be in the compiled code.  
     * Here we compare the counter with the set dutycylce for each led and write the result to the data pin */
#ifndef __invertOutputs
    bitWrite(PORTB,__dataBit, *ledPtr>counter );
#else
    bitWrite(PORTB,__dataBit, *ledPtr<=counter );
#endif
    /* Write shift register shift clock high */
    bitSet(PORTB,__clockBit);
  }
  /* Write shift register latch clock high */
  bitSet(PORTB,__latchBit);

  /* increase the counter with 1 */
  counter++;

  /* Reset counter if it exceeds maximum brightness */
  if(counter>maxBrightness){
    counter=0;
  }
}

//########################################\\

void loop() {
  // skipping that content to keep the message shorter
}

Reaching maximum message length, seperating into 2 messages...
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

continued message...

The following is Servo.h from the Arduino library:
Code:
/*
  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
*/

/*
  
  A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
  The servos are pulsed in the background using the value most recently written using the write() method

  Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
  Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
  The sequence used to sieze timers is defined in timers.h

  The methods are:

   Servo - Class for manipulating servo motors connected to Arduino pins.

   attach(pin )  - Attaches a servo motor to an i/o pin.
   attach(pin, min, max  ) - Attaches to a pin setting min and max values in microseconds
   default min is 544, max is 2400  
 
   write()     - Sets the servo angle in degrees.  (invalid angle that is valid as pulse in microseconds is treated as microseconds)
   writeMicroseconds() - Sets the servo pulse width in microseconds
   read()      - Gets the last written servo pulse width as an angle between 0 and 180.
   readMicroseconds()   - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
   attached()  - Returns true if there is a servo attached.
   detach()    - Stops an attached servos from pulsing its i/o pin.
 */

#ifndef Servo_h
#define Servo_h

#include <inttypes.h>

/*
 * Defines for 16 bit timers used with  Servo library
 *
 * If _useTimerX is defined then TimerX is a 16 bit timer on the curent board
 * timer16_Sequence_t enumerates the sequence that the timers should be allocated
 * _Nbr_16timers indicates how many 16 bit timers are available.
 *
 */

// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
#define _useTimer1
#define _useTimer3
#define _useTimer4
typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t ;

#elif defined(__AVR_ATmega32U4__)  
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;

#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;

#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;

#else  // everything else
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ;                  
#endif

#define Servo_VERSION           2      // software version of this library

#define MIN_PULSE_WIDTH       544     // the shortest pulse sent to a servo  
#define MAX_PULSE_WIDTH      2400     // the longest pulse sent to a servo
#define DEFAULT_PULSE_WIDTH  1500     // default pulse width when servo is attached
#define REFRESH_INTERVAL    20000     // minumim time to refresh servos in microseconds

#define SERVOS_PER_TIMER       12     // the maximum number of servos controlled by one timer
#define MAX_SERVOS   (_Nbr_16timers  * SERVOS_PER_TIMER)

#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

again splitting (not that I want to but I was asked to post the code...)
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry it looks like I am not allowed to post Servo.ccp in one piece. :-(
If you are interested, can you please check it from your Arduino library?

Back to the topic:
The conflict is logical, I just don't know what to do instead.
I meanwhile also tried to use the "SoftwareServo" from http://www.arduino.cc/playground/ComponentLib/Servo, but then the motor is stuttering.
Any help appreciated!
thx :-)
Logged

0
Offline Offline
Shannon Member
****
Karma: 215
Posts: 12516
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you can configure the LED stuff to use timer2 that will probably do - the Servo library will need the full 16bit counter resolution to work properly, looking at the LED stuff it seems to only need the timer for a regular interrupt - 8 bit timer ought to do (though you'll probably need to change the prescaler value).
Logged

[ I won't respond to messages, use the forum please ]

0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

ok, I'll try to do so, thx alot!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Just to let you know: it meanwhile works quite well. I left the LED part with it's timer1 as it is, and continued testing the "SoftwareServo". I've added an interrupt with timer2 to make the Software Servo "Refresh" call happen automatically.
For this installation it works quite good.
Thx for your time!
Logged

Pages: [1]   Go Up
Jump to: