Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
207 eqlazer 1
/*
2
 * PWM output to control a RC servo
3
 *
209 eqlazer 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
 *
207 eqlazer 7
 * Author: Erik Larsson
8
 * Date: 2007-01-04
9
 *
209 eqlazer 10
 * TODO anpassa för fler hastigheter än 8 MHz
11
 * testa libbet, det fungerar ännu bara i eqlazers huvud
207 eqlazer 12
 */
13
 
14
/*-----------------------------------------------
15
 * Includes
16
 * ---------------------------------------------*/
17
#include <avr/io.h>
18
#include <stdio.h>
209 eqlazer 19
#include <stdlib.h>
207 eqlazer 20
#include <rc_servo.h>
21
 
22
 
23
/*----------------------------------------------
24
 * Functions
25
 * --------------------------------------------*/
26
 
27
/*
28
 * Initiate PWM output.
29
 */
30
void rcServoInit(){
209 eqlazer 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
207 eqlazer 57
}
58
 
209 eqlazer 59
/*
60
 * Set the servo to an absolute position.
61
 * Interval -128 to 127.
62
 */
207 eqlazer 63
void setPosition(int8_t abs_pos){
209 eqlazer 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
207 eqlazer 72
}
73
 
209 eqlazer 74
/*
75
 * Alter the position rel_pos steps.
76
 * Interval -128 to 127.
77
 */
207 eqlazer 78
void alterPosition(int8_t rel_pos){
209 eqlazer 79
    uint16_t temp_pos;
207 eqlazer 80
 
209 eqlazer 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
207 eqlazer 103
}
104
 
209 eqlazer 105
/*
106
 * Get current position of the servo.
107
 */
207 eqlazer 108
int8_t getPosition(){
109
 
209 eqlazer 110
    return (OCR1A - PWM_CENTER_PULSE)/STEP;
207 eqlazer 111
}
112
 
209 eqlazer 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
*/