Rev 207 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed
| Rev 207 | Rev 209 | ||
|---|---|---|---|
| Line 1... | Line 1... | ||
| 1 | /* |
1 | /* |
| 2 | * PWM output to control a RC servo |
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. |
|
| 3 | * |
6 | * |
| 4 | * Author: Erik Larsson |
7 | * Author: Erik Larsson |
| 5 | * Date: 2007-01-04 |
8 | * Date: 2007-01-04 |
| 6 | * |
9 | * |
| - | 10 | * TODO anpassa för fler hastigheter än 8 MHz |
|
| - | 11 | * testa libbet, det fungerar ännu bara i eqlazers huvud |
|
| 7 | */ |
12 | */ |
| 8 | 13 | ||
| 9 | /*----------------------------------------------- |
14 | /*----------------------------------------------- |
| 10 | * Includes |
15 | * Includes |
| 11 | * ---------------------------------------------*/ |
16 | * ---------------------------------------------*/ |
| 12 | #include <avr/io.h> |
17 | #include <avr/io.h> |
| 13 | #include <stdio.h> |
18 | #include <stdio.h> |
| 14 | - | ||
| - | 19 | #include <stdlib.h> |
|
| 15 | #include <rc_servo.h> |
20 | #include <rc_servo.h> |
| 16 | 21 | ||
| 17 | 22 | ||
| 18 | /*---------------------------------------------- |
23 | /*---------------------------------------------- |
| 19 | * Functions |
24 | * Functions |
| 20 | * --------------------------------------------*/ |
25 | * --------------------------------------------*/ |
| 21 | 26 | ||
| 22 | /* |
27 | /* |
| 23 | * Initiate PWM output. |
28 | * Initiate PWM output. |
| 24 | */ |
29 | */ |
| 25 | void rcServoInit(){ |
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 |
|
| 26 | 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 |
|
| 27 | } |
57 | } |
| 28 | 58 | ||
| - | 59 | /* |
|
| - | 60 | * Set the servo to an absolute position. |
|
| - | 61 | * Interval -128 to 127. |
|
| - | 62 | */ |
|
| 29 | void setPosition(int8_t abs_pos){ |
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; |
|
| 30 | 69 | #else |
|
| - | 70 | OCR1A = temp_pos; |
|
| - | 71 | #endif |
|
| 31 | } |
72 | } |
| 32 | 73 | ||
| - | 74 | /* |
|
| - | 75 | * Alter the position rel_pos steps. |
|
| - | 76 | * Interval -128 to 127. |
|
| - | 77 | */ |
|
| 33 | void alterPosition(int8_t rel_pos){ |
78 | void alterPosition(int8_t rel_pos){ |
| - | 79 | uint16_t temp_pos; |
|
| 34 | 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 |
|
| 35 | } |
103 | } |
| 36 | 104 | ||
| - | 105 | /* |
|
| - | 106 | * Get current position of the servo. |
|
| - | 107 | */ |
|
| 37 | int8_t getPosition(){ |
108 | int8_t getPosition(){ |
| 38 | 109 | ||
| - | 110 | return (OCR1A - PWM_CENTER_PULSE)/STEP; |
|
| 39 | } |
111 | } |
| 40 | 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 | */ |
|