Subversion Repositories HomeAutomation

Rev

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
*/