Guest User

Untitled

a guest
Feb 3rd, 2013
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.75 KB | None | 0 0
  1. /* ServoTimer2.cpp*/
  2. extern "C" {
  3. // AVR LibC Includes
  4. #include <inttypes.h>
  5. #include <avr/interrupt.h>
  6. }
  7. #include <Arduino.h>
  8. #include "ServoTimer2.h"
  9. static void initISR();
  10. static void writeChan(uint8_t chan, int pulsewidth);
  11.  
  12. #define FRAME_SYNC_INDEX 0 // frame sync delay is the first entry in the channel array
  13. #define FRAME_SYNC_PERIOD 20000 // total frame duration in microseconds
  14. #define FRAME_SYNC_DELAY ((FRAME_SYNC_PERIOD - ( NBR_CHANNELS * DEFAULT_PULSE_WIDTH))/ 128) // number of iterations of the ISR to get the desired frame rate
  15. #define DELAY_ADJUST 8 // number of microseconds of calculation overhead to be subtracted from pulse timings
  16.  
  17. static servo_t servos[NBR_CHANNELS+1]; // static array holding servo data for all channels
  18.  
  19. static volatile uint8_t Channel; // counter holding the channel being pulsed
  20. static volatile uint8_t ISRCount; // iteration counter used in the interrupt routines;
  21. uint8_t ChannelCount = 0; // counter holding the number of attached channels
  22. static boolean isStarted = false; // flag to indicate if the ISR has been initialised
  23.  
  24. ISR (TIMER2_OVF_vect)
  25. {
  26. ++ISRCount; // increment the overlflow counter
  27. if (ISRCount == servos[Channel].counter ) // are we on the final iteration for this channel
  28. {
  29. TCNT2 = servos[Channel].remainder; // yes, set count for overflow after remainder ticks
  30. }
  31. else if(ISRCount > servos[Channel].counter)
  32. {
  33. // we have finished timing the channel so pulse it low and move on
  34. if(servos[Channel].Pin.isActive == true) // check if activated
  35. digitalWrite( servos[Channel].Pin.nbr,LOW); // pulse this channel low if active
  36.  
  37. Channel++; // increment to the next channel
  38. ISRCount = 0; // reset the isr iteration counter
  39. TCNT2 = 0; // reset the clock counter register
  40. if( (Channel != FRAME_SYNC_INDEX) && (Channel <= NBR_CHANNELS) ){ // check if we need to pulse this channel
  41. if(servos[Channel].Pin.isActive == true) // check if activated
  42. digitalWrite( servos[Channel].Pin.nbr,HIGH); // its an active channel so pulse it high
  43. }
  44. else if(Channel > NBR_CHANNELS){
  45. Channel = 0; // all done so start over
  46. }
  47. }
  48. }
  49.  
  50. ServoTimer2::ServoTimer2()
  51. {
  52. if( ChannelCount < NBR_CHANNELS)
  53. this->chanIndex = ++ChannelCount; // assign a channel number to this instance
  54. else
  55. this->chanIndex = 0; // todo // too many channels, assigning 0 inhibits this instance from functioning
  56. }
  57.  
  58. uint8_t ServoTimer2::attach(int pin)
  59. {
  60. if( isStarted == false)
  61. initISR();
  62. if(this->chanIndex > 0)
  63. {
  64. //debug("attaching chan = ", chanIndex);
  65. pinMode( pin, OUTPUT) ; // set servo pin to output
  66. servos[this->chanIndex].Pin.nbr = pin;
  67. servos[this->chanIndex].Pin.isActive = true;
  68. }
  69. return this->chanIndex ;
  70. }
  71.  
  72. void ServoTimer2::detach()
  73. {
  74. servos[this->chanIndex].Pin.isActive = false;
  75. }
  76.  
  77. void ServoTimer2::write(int pulsewidth)
  78. {
  79. writeChan(this->chanIndex, pulsewidth); // call the static function to store the data for this servo
  80. }
  81.  
  82. int ServoTimer2::read()
  83. {
  84. unsigned int pulsewidth;
  85. if( this->chanIndex > 0)
  86. pulsewidth = servos[this->chanIndex].counter * 128 + ((255 - servos[this->chanIndex].remainder) / 2) + DELAY_ADJUST ;
  87. else
  88. pulsewidth = 0;
  89. return pulsewidth;
  90. }
  91.  
  92. boolean ServoTimer2::attached()
  93. {
  94. return servos[this->chanIndex].Pin.isActive ;
  95. }
  96.  
  97. static void writeChan(uint8_t chan, int pulsewidth)
  98. {
  99. // calculate and store the values for the given channel
  100. if( (chan > 0) && (chan <= NBR_CHANNELS) ) // ensure channel is valid
  101. {
  102. if( pulsewidth < MIN_PULSE_WIDTH ) // ensure pulse width is valid
  103. pulsewidth = MIN_PULSE_WIDTH;
  104. else if( pulsewidth > MAX_PULSE_WIDTH )
  105. pulsewidth = MAX_PULSE_WIDTH;
  106.  
  107. pulsewidth -=DELAY_ADJUST; // subtract the time it takes to process the start and end pulses (mostly from digitalWrite)
  108. servos[chan].counter = pulsewidth / 128;
  109. servos[chan].remainder = 255 - (2 * (pulsewidth - ( servos[chan].counter * 128))); // the number of 0.5us ticks for timer overflow
  110. }
  111. }
  112.  
  113. static void initISR()
  114. {
  115. for(uint8_t i=1; i <= NBR_CHANNELS; i++) { // channels start from 1
  116. writeChan(i, DEFAULT_PULSE_WIDTH); // store default values
  117. }
  118. servos[FRAME_SYNC_INDEX].counter = FRAME_SYNC_DELAY; // store the frame sync period
  119.  
  120. Channel = 0; // clear the channel index
  121. ISRCount = 0; // clear the value of the ISR counter;
  122.  
  123. /* setup for timer 2 */
  124. TIMSK2 = 0; // disable interrupts
  125. TCCR2A = 0; // normal counting mode
  126. TCCR2B = _BV(CS21); // set prescaler of 8
  127. TCNT2 = 0; // clear the timer2 count
  128. TIFR2 = _BV(TOV2); // clear pending interrupts;
  129. TIMSK2 = _BV(TOIE2) ; // enable the overflow interrupt
  130.  
  131. isStarted = true; // flag to indicate this initialisation code has been executed
  132. }
Advertisement
Add Comment
Please, Sign In to add comment