Subversion Repositories HomeAutomation

Rev

Rev 207 | Blame | Last modification | View Log | SVN | RSS feed

  1. /*
  2.  * PWM output to control a RC servo
  3.  *
  4.  * It is possible to use both OCR1A and OCR1B, but they uses the same value.
  5.  * If it's desired to control A and B individually some rewriting is necessary.
  6.  *
  7.  * Author: Erik Larsson
  8.  * Date: 2007-01-04
  9.  *
  10.  * TODO anpassa för fler hastigheter än 8 MHz
  11.  * testa libbet, det fungerar ännu bara i eqlazers huvud
  12.  */
  13.  
  14. /*-----------------------------------------------
  15.  * Includes
  16.  * ---------------------------------------------*/
  17. #include <avr/io.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <rc_servo.h>
  21.  
  22.  
  23. /*----------------------------------------------
  24.  * Functions
  25.  * --------------------------------------------*/
  26.  
  27. /*
  28.  * Initiate PWM output.
  29.  */
  30. void rcServoInit(){
  31.     // set up counter 1 (16 bit) to act as a dual channel PWM generator
  32.     // we want OC1A and B to be set on reaching BOTTOM, clear on reaching
  33.     // compare match, use ICR1 as TOP and have a prescale of 8.
  34. #if DOUBLE_PWM
  35.     TCCR1A |= (1<<COM1A1) // set OC1A/B at TOP
  36.         | (1<<COM1B1) // clear OC1A/B when match
  37.         | (1<<WGM11); // mode 14 (fast PWM, clear TCNT1 on match ICR1)
  38.     TCCR1B |= (1<<WGM13)
  39.         | (1<<WGM12)
  40.         | (1<<CS11); // timer uses main system clock with 1/8 prescale
  41.     ICR1 = 20000; // used for TOP, makes for 50 hz PWM
  42.     OCR1A = 1500; // servo at center
  43.     OCR1B = 1500; // servo at center
  44.     DDRB |= (1<<PB1)
  45.         | (1<<PB2);  // have to set up pins as outputs
  46. #else
  47.     TCCR1A |= (1<<COM1A1) // set OC1A/B at TOP
  48.         // clear OC1A/B when match
  49.         | (1<<WGM11); // mode 14 (fast PWM, clear TCNT1 on match ICR1)
  50.     TCCR1B |= (1<<WGM13)
  51.         | (1<<WGM12)
  52.         | (1<<CS11); // timer uses main system clock with 1/8 prescale
  53.     ICR1 = 20000; // used for TOP, makes for 50 hz PWM
  54.     OCR1A = 1500; // servo at center
  55.     DDRB |= (1<<PB1);  // have to set up pins as outputs
  56. #endif
  57. }
  58.  
  59. /*
  60.  * Set the servo to an absolute position.
  61.  * Interval -128 to 127.
  62.  */
  63. void setPosition(int8_t abs_pos){
  64.     uint16_t temp_pos;
  65.     temp_pos = (uint16_t)PWM_CENTER_PULSE + abs_pos*STEP;
  66. #if DOUBLE_PWM
  67.     OCR1A = temp_pos;
  68.     OCR1B = temp_pos;
  69. #else
  70.     OCR1A = temp_pos;
  71. #endif
  72. }
  73.  
  74. /*
  75.  * Alter the position rel_pos steps.
  76.  * Interval -128 to 127.
  77.  */
  78. void alterPosition(int8_t rel_pos){
  79.     uint16_t temp_pos;
  80.  
  81.     temp_pos = OCR1A;
  82.     temp_pos = temp_pos + rel_pos*STEP;
  83. #if DOUBLE_PWM
  84.     if(temp_pos>=PWM_MAX_PULSE){
  85.         OCR1A = PWM_MAX_PULSE;
  86.         OCR1B = PWM_MAX_PULSE;
  87.     }else if(temp_pos<=PWM_MIN_PULSE){
  88.         OCR1A = PWM_MIN_PULSE;
  89.         OCR1B = PWM_MIN_PULSE;
  90.     }else{
  91.         OCR1A = temp_pos;
  92.         OCR1B = temp_pos;
  93.     }
  94. #else
  95.     if(temp_pos>=PWM_MAX_PULSE){
  96.         OCR1A = PWM_MAX_PULSE;
  97.     }else if(temp_pos<=PWM_MIN_PULSE){
  98.         OCR1A = PWM_MIN_PULSE;
  99.     }else{
  100.         OCR1A = temp_pos;
  101.     }
  102. #endif
  103. }
  104.  
  105. /*
  106.  * Get current position of the servo.
  107.  */
  108. int8_t getPosition(){
  109.  
  110.     return (OCR1A - PWM_CENTER_PULSE)/STEP;
  111. }
  112.  
  113. /*
  114. http://members.shaw.ca/climber/avrtimers.html
  115.  
  116.  To change the servo position all you have to do is assign a value to OCR1A or B.
  117.  With an 8 MHz clock the normal range you use is 1000 to 2000.
  118.  I especially like it at 8 MHz because the timing for normal servo control
  119.  is pulse widths of (usually) 1.0 to 2.0 milliseconds. Just multiply that
  120.  by 1000 and you get the value to assign to OCR1A or B.
  121.  
  122. If you want to use a different system clock then all you have to do is
  123. adjust the value you assign ICR1 and the useable range to assign OCR1A
  124. and B to control the servos is 5% to 10% of the value you use for ICR1.
  125. For example, for a 1 MHz clock (like the default RC clock from the factory)
  126. use 2500 for ICR1 and 125 - 250 for the range of values to give OCR1A and B.
  127. */
  128.