BrickUp API Service for Docker version.

FR_DCBServo.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. #include <avr/interrupt.h>
  2. #include <Arduino.h> // updated from WProgram.h to Arduino.h for Arduino 1.0+, pva
  3. #include "FR_DCBServo.h"
  4. #define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009
  5. #define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
  6. #define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
  7. //#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
  8. static servo_t servos[MAX_SERVOS]; // static array of servo structures
  9. static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
  10. uint8_t ServoCount = 0; // the total number of attached servos
  11. // sequence vars
  12. servoSequencePoint initSeq[] = {{0,100},{45,100}};
  13. //sequence_t sequences[MAX_SEQUENCE];
  14. // convenience macros
  15. #define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
  16. #define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
  17. #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
  18. #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
  19. #define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
  20. #define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
  21. /************ static functions common to all instances ***********************/
  22. static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
  23. {
  24. if( Channel[timer] < 0 )
  25. *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
  26. else{
  27. if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )
  28. digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
  29. }
  30. Channel[timer]++; // increment to the next channel
  31. if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
  32. // Extension for slowmove
  33. if (SERVO(timer,Channel[timer]).speed) {
  34. // Increment ticks by speed until we reach the target.
  35. // When the target is reached, speed is set to 0 to disable that code.
  36. if (SERVO(timer,Channel[timer]).target > SERVO(timer,Channel[timer]).ticks) {
  37. SERVO(timer,Channel[timer]).ticks += SERVO(timer,Channel[timer]).speed;
  38. if (SERVO(timer,Channel[timer]).target <= SERVO(timer,Channel[timer]).ticks) {
  39. SERVO(timer,Channel[timer]).ticks = SERVO(timer,Channel[timer]).target;
  40. SERVO(timer,Channel[timer]).speed = 0;
  41. }
  42. }
  43. else {
  44. SERVO(timer,Channel[timer]).ticks -= SERVO(timer,Channel[timer]).speed;
  45. if (SERVO(timer,Channel[timer]).target >= SERVO(timer,Channel[timer]).ticks) {
  46. SERVO(timer,Channel[timer]).ticks = SERVO(timer,Channel[timer]).target;
  47. SERVO(timer,Channel[timer]).speed = 0;
  48. }
  49. }
  50. }
  51. // End of Extension for slowmove
  52. // Todo
  53. *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
  54. if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated
  55. digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
  56. }
  57. else {
  58. // finished all channels so wait for the refresh period to expire before starting over
  59. if( (unsigned)*TCNTn < (usToTicks(REFRESH_INTERVAL) + 4) ) // allow a few ticks to ensure the next OCR1A not missed
  60. *OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
  61. else
  62. *OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
  63. Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
  64. }
  65. }
  66. #ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
  67. // Interrupt handlers for Arduino
  68. #if defined(_useTimer1)
  69. SIGNAL (TIMER1_COMPA_vect)
  70. {
  71. handle_interrupts(_timer1, &TCNT1, &OCR1A);
  72. }
  73. #endif
  74. #if defined(_useTimer3)
  75. SIGNAL (TIMER3_COMPA_vect)
  76. {
  77. handle_interrupts(_timer3, &TCNT3, &OCR3A);
  78. }
  79. #endif
  80. #if defined(_useTimer4)
  81. SIGNAL (TIMER4_COMPA_vect)
  82. {
  83. handle_interrupts(_timer4, &TCNT4, &OCR4A);
  84. }
  85. #endif
  86. #if defined(_useTimer5)
  87. SIGNAL (TIMER5_COMPA_vect)
  88. {
  89. handle_interrupts(_timer5, &TCNT5, &OCR5A);
  90. }
  91. #endif
  92. #elif defined WIRING
  93. // Interrupt handlers for Wiring
  94. #if defined(_useTimer1)
  95. void Timer1Service()
  96. {
  97. handle_interrupts(_timer1, &TCNT1, &OCR1A);
  98. }
  99. #endif
  100. #if defined(_useTimer3)
  101. void Timer3Service()
  102. {
  103. handle_interrupts(_timer3, &TCNT3, &OCR3A);
  104. }
  105. #endif
  106. #endif
  107. static void initISR(timer16_Sequence_t timer)
  108. {
  109. #if defined (_useTimer1)
  110. if(timer == _timer1) {
  111. TCCR1A = 0; // normal counting mode
  112. TCCR1B = _BV(CS11); // set prescaler of 8
  113. TCNT1 = 0; // clear the timer count
  114. #if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
  115. TIFR |= _BV(OCF1A); // clear any pending interrupts;
  116. TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt
  117. #else
  118. // here if not ATmega8 or ATmega128
  119. TIFR1 |= _BV(OCF1A); // clear any pending interrupts;
  120. TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
  121. #endif
  122. #if defined(WIRING)
  123. timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
  124. #endif
  125. }
  126. #endif
  127. #if defined (_useTimer3)
  128. if(timer == _timer3) {
  129. TCCR3A = 0; // normal counting mode
  130. TCCR3B = _BV(CS31); // set prescaler of 8
  131. TCNT3 = 0; // clear the timer count
  132. #if defined(__AVR_ATmega128__)
  133. TIFR |= _BV(OCF3A); // clear any pending interrupts;
  134. ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt
  135. #else
  136. TIFR3 = _BV(OCF3A); // clear any pending interrupts;
  137. TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt
  138. #endif
  139. #if defined(WIRING)
  140. timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
  141. #endif
  142. }
  143. #endif
  144. #if defined (_useTimer4)
  145. if(timer == _timer4) {
  146. TCCR4A = 0; // normal counting mode
  147. TCCR4B = _BV(CS41); // set prescaler of 8
  148. TCNT4 = 0; // clear the timer count
  149. TIFR4 = _BV(OCF4A); // clear any pending interrupts;
  150. TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt
  151. }
  152. #endif
  153. #if defined (_useTimer5)
  154. if(timer == _timer5) {
  155. TCCR5A = 0; // normal counting mode
  156. TCCR5B = _BV(CS51); // set prescaler of 8
  157. TCNT5 = 0; // clear the timer count
  158. TIFR5 = _BV(OCF5A); // clear any pending interrupts;
  159. TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt
  160. }
  161. #endif
  162. }
  163. static void finISR(timer16_Sequence_t timer)
  164. {
  165. //disable use of the given timer
  166. #if defined WIRING // Wiring
  167. if(timer == _timer1) {
  168. #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
  169. TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
  170. #else
  171. TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
  172. #endif
  173. timerDetach(TIMER1OUTCOMPAREA_INT);
  174. }
  175. else if(timer == _timer3) {
  176. #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
  177. TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
  178. #else
  179. ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
  180. #endif
  181. timerDetach(TIMER3OUTCOMPAREA_INT);
  182. }
  183. #else
  184. //For arduino - in future: call here to a currently undefined function to reset the timer
  185. #endif
  186. }
  187. static boolean isTimerActive(timer16_Sequence_t timer)
  188. {
  189. // returns true if any servo is active on this timer
  190. for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
  191. if(SERVO(timer,channel).Pin.isActive == true)
  192. return true;
  193. }
  194. return false;
  195. }
  196. /****************** end of static functions ******************************/
  197. FR_DCBServo::FR_DCBServo()
  198. {
  199. if( ServoCount < MAX_SERVOS) {
  200. this->servoIndex = ServoCount++; // assign a servo index to this instance
  201. servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009
  202. this->curSeqPosition = 0;
  203. this->curSequence = initSeq;
  204. }
  205. else
  206. this->servoIndex = INVALID_SERVO ; // too many servos
  207. }
  208. uint8_t FR_DCBServo::attach(int pin)
  209. {
  210. return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
  211. }
  212. uint8_t FR_DCBServo::attach(int pin, int min, int max)
  213. {
  214. if(this->servoIndex < MAX_SERVOS ) {
  215. pinMode( pin, OUTPUT) ; // set servo pin to output
  216. servos[this->servoIndex].Pin.nbr = pin;
  217. // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
  218. this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
  219. this->max = (MAX_PULSE_WIDTH - max)/4;
  220. // initialize the timer if it has not already been initialized
  221. timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
  222. if(isTimerActive(timer) == false)
  223. initISR(timer);
  224. servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
  225. }
  226. return this->servoIndex ;
  227. }
  228. void FR_DCBServo::detach()
  229. {
  230. servos[this->servoIndex].Pin.isActive = false;
  231. timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
  232. if(isTimerActive(timer) == false) {
  233. finISR(timer);
  234. }
  235. }
  236. void FR_DCBServo::write(int value)
  237. {
  238. if(value < MIN_PULSE_WIDTH)
  239. { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
  240. // updated to use constrain() instead of if(), pva
  241. value = constrain(value, 0, 180);
  242. value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
  243. }
  244. this->writeMicroseconds(value);
  245. }
  246. void FR_DCBServo::writeMicroseconds(int value)
  247. {
  248. // calculate and store the values for the given channel
  249. byte channel = this->servoIndex;
  250. if( (channel >= 0) && (channel < MAX_SERVOS) ) // ensure channel is valid
  251. {
  252. if( value < SERVO_MIN() ) // ensure pulse width is valid
  253. value = SERVO_MIN();
  254. else if( value > SERVO_MAX() )
  255. value = SERVO_MAX();
  256. value -= TRIM_DURATION;
  257. value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
  258. uint8_t oldSREG = SREG;
  259. cli();
  260. servos[channel].ticks = value;
  261. SREG = oldSREG;
  262. // Extension for slowmove
  263. // Disable slowmove logic.
  264. servos[channel].speed = 0;
  265. // End of Extension for slowmove
  266. }
  267. }
  268. // Extension for slowmove
  269. /*
  270. write(value, speed) - Just like write but at reduced speed.
  271. value - Target position for the servo. Identical use as value of the function write.
  272. speed - Speed at which to move the servo.
  273. speed=0 - Full speed, identical to write
  274. speed=1 - Minimum speed
  275. speed=255 - Maximum speed
  276. */
  277. void FR_DCBServo::write(int value, uint8_t speed) {
  278. // This fuction is a copy of write and writeMicroseconds but value will be saved
  279. // in target instead of in ticks in the servo structure and speed will be save
  280. // there too.
  281. int degrees = value;
  282. if (speed) {
  283. if (value < MIN_PULSE_WIDTH) {
  284. // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
  285. // updated to use constrain instead of if, pva
  286. value = constrain(value, 0, 180);
  287. value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
  288. }
  289. // calculate and store the values for the given channel
  290. byte channel = this->servoIndex;
  291. if( (channel >= 0) && (channel < MAX_SERVOS) ) { // ensure channel is valid
  292. // updated to use constrain instead of if, pva
  293. value = constrain(value, SERVO_MIN(), SERVO_MAX());
  294. value = value - TRIM_DURATION;
  295. value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
  296. // Set speed and direction
  297. uint8_t oldSREG = SREG;
  298. cli();
  299. servos[channel].target = value;
  300. servos[channel].speed = speed;
  301. SREG = oldSREG;
  302. }
  303. }
  304. else {
  305. write (value);
  306. }
  307. }
  308. void FR_DCBServo::write(int value, uint8_t speed, bool wait) {
  309. write(value, speed);
  310. if (wait) { // block until the servo is at its new position
  311. if (value < MIN_PULSE_WIDTH) {
  312. while (read() != value) {
  313. delay(5);
  314. }
  315. } else {
  316. while (readMicroseconds() != value) {
  317. delay(5);
  318. }
  319. }
  320. }
  321. }
  322. void FR_DCBServo::stop() {
  323. write(read());
  324. }
  325. void FR_DCBServo::slowmove(int value, uint8_t speed) {
  326. // legacy function to support original version of FR_DCBServo
  327. write(value, speed);
  328. }
  329. // End of Extension for slowmove
  330. int FR_DCBServo::read() // return the value as degrees
  331. {
  332. return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
  333. }
  334. int FR_DCBServo::readMicroseconds()
  335. {
  336. unsigned int pulsewidth;
  337. if( this->servoIndex != INVALID_SERVO )
  338. pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009
  339. else
  340. pulsewidth = 0;
  341. return pulsewidth;
  342. }
  343. bool FR_DCBServo::attached()
  344. {
  345. return servos[this->servoIndex].Pin.isActive ;
  346. }
  347. uint8_t FR_DCBServo::sequencePlay(servoSequencePoint sequenceIn[], uint8_t numPositions, bool loop, uint8_t startPos) {
  348. uint8_t oldSeqPosition = this->curSeqPosition;
  349. if( this->curSequence != sequenceIn) {
  350. //Serial.println("newSeq");
  351. this->curSequence = sequenceIn;
  352. this->curSeqPosition = startPos;
  353. oldSeqPosition = 255;
  354. }
  355. if (read() == sequenceIn[this->curSeqPosition].position && this->curSeqPosition != CURRENT_SEQUENCE_STOP) {
  356. this->curSeqPosition++;
  357. if (this->curSeqPosition >= numPositions) { // at the end of the loop
  358. if (loop) { // reset to the beginning of the loop
  359. this->curSeqPosition = 0;
  360. } else { // stop the loop
  361. this->curSeqPosition = CURRENT_SEQUENCE_STOP;
  362. }
  363. }
  364. }
  365. if (this->curSeqPosition != oldSeqPosition && this->curSeqPosition != CURRENT_SEQUENCE_STOP) {
  366. // CURRENT_SEQUENCE_STOP position means the animation has ended, and should no longer be played
  367. // otherwise move to the next position
  368. write(sequenceIn[this->curSeqPosition].position, sequenceIn[this->curSeqPosition].speed);
  369. //Serial.println(this->seqCurPosition);
  370. }
  371. return this->curSeqPosition;
  372. }
  373. uint8_t FR_DCBServo::sequencePlay(servoSequencePoint sequenceIn[], uint8_t numPositions) {
  374. return sequencePlay(sequenceIn, numPositions, true, 0);
  375. }
  376. void FR_DCBServo::sequenceStop() {
  377. write(read());
  378. this->curSeqPosition = CURRENT_SEQUENCE_STOP;
  379. }
  380. /*
  381. To do
  382. int FR_DCBServo::targetPosition() {
  383. byte channel = this->servoIndex;
  384. return map( servos[channel].target+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
  385. }
  386. int FR_DCBServo::targetPositionMicroseconds() {
  387. byte channel = this->servoIndex;
  388. return servos[channel].target;
  389. }
  390. bool FR_DCBServo::isMoving() {
  391. byte channel = this->servoIndex;
  392. int servos[channel].target;
  393. }
  394. */