Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2136 - 1
 
2
/********************************************************************/
3
/*                                                                                                                                                                                                                                                                      */
4
/*                                                                       NG-Video 5,8GHz                                                                                                                                */
5
/*                                                                                                                                                                                                                                                                      */
6
/*                                                              Copyright (C) 2011 - gebad                                                                                              */
7
/*                                                                                                                                                                                                                                                                      */
8
/*      This code is distributed under the GNU Public License                                           */
9
/*      which can be found at http://www.gnu.org/licenses/gpl.txt                               */
10
/*                                                                                                                                                                                                                                                                      */
11
/*      using                                                                                                                                                                                                                                           */
12
/*! \file servo.c \brief Interrupt-driven RC Servo function library.*/
13
/*                                                                                                                                                                                                                                                                      */
14
/*File Name             : 'servo.c'                                                                                                                                                                             */
15
/*Title                         : Interrupt-driven RC Servo function library                                    */
16
/*Author                                : Pascal Stang - Copyright (C) 2002                                                                     */
17
/*Created                               : 7/31/2002                                                                                                                                                                     */
18
/*Revised                               : 8/02/2002                                                                                                                                                                     */
19
/*Version                               : 1.0                                                                                                                                                                                           */
20
/*Target MCU            : Atmel AVR Series                                                                                                                                      */
21
/*Editor Tabs           : 2                                                                                                                                                                                                     */
22
/*                                                                                                                                                                                                                                                                      */
23
/*This code is distributed under the GNU Public License                                                 */
24
/*                              which can be found at http://www.gnu.org/licenses/gpl.txt       */
25
/*                                                                                                                                                                                                                                                                      */
26
/********************************************************************/
27
 
28
//############################################################################
29
//# HISTORY  ng_servo.c
30
//#
31
//# 25.08.2013 Cebra
32
//# - add: #ifdef USE_TRACKING
33
//#
34
//# 24.04.2013 OG
35
//# - chg: umbenannt servo_test(void) nach _servo_test(void)
36
//#        das verursachte in meinem PKT-Projekt Errors weil die Funktion 
37
//#        servo_test() ebenfalls ein servo.c vorhanden ist
38
//############################################################################
39
 
40
 
41
#include <avr/interrupt.h>
42
#include <avr/io.h>
43
 
44
#include "../tracking/ng_servo.h"
45
#include "../tracking/tracking.h"
46
#include "../HAL_HW3_9.h"
47
#include "../eeprom/eeprom.h"
48
//#include "config.h"
49
#ifdef USE_TRACKING
50
// Global variables
51
uint16_t ServoPosTics;
52
uint16_t ServoPeriodTics;
53
 
54
// servo channel registers
55
ServoChannelType ServoChannels[SERVO_NUM_CHANNELS];
56
 
57
const ServoConst_t ServoConst[2] = {{SERVO_MAX, SERVO_MIN, SERVO_STEPS, SERVO_PRESCALER},
58
                                    {SERVO_MAX * 4, SERVO_MIN * 4, (SERVO_STEPS + 1) * 4 - 1, SERVO_PRESCALER / 4}};
59
 
60
// Servo limits (depend on hardware)
61
const servo_limit_t servo_limit[2][3] = {{{SERVO_I0_RIGHT_MIN, SERVO_I0_RIGHT_MAX},
62
                                         {SERVO_I0_LEFT_MIN, SERVO_I0_LEFT_MAX},
63
                                         {SERVO_I0_MIDDLE_MIN, SERVO_I0_MIDDLE_MAX}},
64
                                         {{SERVO_I1_RIGHT_MIN, SERVO_I1_RIGHT_MAX},
65
                                         {SERVO_I1_LEFT_MIN, SERVO_I1_LEFT_MAX},
66
                                         {SERVO_I1_MIDDLE_MIN, SERVO_I1_MIDDLE_MAX}}};
67
 
68
// Servopositionen normiert für 950µs, 2,05ms und 1,5ms ==> Ergebnis Schritte. Da Zeit in µs ist F_CPU*e-1
69
const steps_pw_t steps_pw[2] = {{(uint64_t)950*F_CPU*1e-6/SERVO_PRESCALER + 0.5, (uint64_t)2050*F_CPU*1e-6/SERVO_PRESCALER + 0.5,(uint64_t)1500*F_CPU*1e-6/SERVO_PRESCALER + 0.5},
70
                                {(uint64_t)950*4*F_CPU*1e-6/SERVO_PRESCALER + 0.5, (uint64_t)2050*4*F_CPU*1e-6/SERVO_PRESCALER + 0.5, (uint64_t)1500*4*F_CPU*1e-6/SERVO_PRESCALER + 0.5}};
71
 
72
// anzufahrende Servopositionen 0=MIN, 1=MID, 2=MAX
73
const uint8_t PosIdx[POSIDX_MAX] = {1, 0, 1, 2 };
74
 
75
// functions
76
void _servo_test(void)
77
{
78
  //Dummy
79
}
80
//! initializes software PWM system 16-bit Timer
81
// normaler Weise wird ein Serv-PWM Signal aller 20ms wiederholt
82
// Werte: rev, min, max, mid vorher über servoSet...() initialisieren und einmal servoSetPosition(...) ausführen!!!
83
void servoInit(uint8_t servo_period)
84
{ uint16_t OCValue; // set initial interrupt time
85
 
86
 
87
 
88
 
89
        // disble Timer/Counter1, Output Compare A Match Interrupt
90
        TIMSK1 &= ~(1<<OCIE1A);
91
        // set the prescaler for timer1
92
        if (Config.sIdxSteps == STEPS_255) {
93
                TCCR1B &= ~((1<<CS11) | (1<<CS10));
94
                TCCR1B |= (1<<CS12);                                                    // prescaler 256, Servo-Schritte 185 bei 180 grd Winkel
95
        }
96
        else {
97
                TCCR1B &= ~(1<<CS12);
98
                TCCR1B |= (1<<CS11) | (1<<CS10);                // prescaler 64,        Servo-Schritte 740 bei 180 grd Winkel
99
        }
100
        // attach the software PWM service routine to timer1 output compare A
101
        // timerAttach(TIMER1OUTCOMPAREA_INT, servoService);
102
        // enable channels
103
        for(uint8_t channel=0; channel < SERVO_NUM_CHANNELS; channel++) {
104
                // set default pins assignments SERVO2 Pin 4; SERVO1 Pin 5
105
                ServoChannels[channel].pin = (1 << (SERVO2 + channel));
106
        }
107
        ServoPosTics = 0; // set PosTics
108
        // set PeriodTics
109
        ServoPeriodTics = F_CPU / ServoConst[Config.sIdxSteps].prescaler * servo_period * 1e-3;
110
        // read in current value of output compare register OCR1A
111
        OCValue =       OCR1AL;                 // read low byte of OCR1A
112
        OCValue += (OCR1AH << 8);               // read high byte of OCR1A
113
        OCValue += ServoPeriodTics;             // increment OCR1A value by nextTics
114
        // set future output compare time to this new value
115
        OCR1AH = OCValue >> 8;                  // write high byte
116
        OCR1AL = OCValue & 0x00FF;              // write low byte
117
        TIMSK1 |= (1<<OCIE1A);                          // enable the timer1 output compare A interrupt
118
        coldstart = 1;
119
}
120
 
121
void servoSetDefaultPos(void)
122
{
123
        servoSetPosition(SERVO_PAN, ServoSteps());            // Ausgangsstellung SERVO_PAN
124
        servoSetPosition(SERVO_TILT,ServoSteps());                        // Ausgangsstellung SERVO_TILT
125
}
126
 
127
uint16_t pw_us(uint16_t Steps)
128
{
129
        return(Steps * ServoConst[Config.sIdxSteps].prescaler/(F_CPU * 1e-6)    + 0.5); // Zeit pro Schritt (Wert * e-1) in µs
130
}
131
 
132
uint16_t ServoSteps(void)
133
{
134
        return(ServoConst[Config.sIdxSteps].steps);
135
}
136
 
137
void servoSet_rev(uint8_t channel, uint8_t val)
138
{
139
        ServoChannels[channel].rev = val & 0x01;
140
}
141
 
142
void servoSet_min(uint8_t channel, uint16_t min)
143
{
144
        ServoChannels[channel].min = ServoConst[Config.sIdxSteps].min + min;
145
}
146
 
147
void servoSet_max(uint8_t channel, uint16_t max)
148
{
149
        ServoChannels[channel].max = ServoConst[Config.sIdxSteps].max - max;
150
}
151
 
152
void servoSet_mid(uint8_t channel, uint16_t mid)
153
{
154
        ServoChannels[channel].mid = mid;
155
        // Faktor 16, bzw. 16/2 um mit einer Nachkommastelle zu Rechnen 
156
        ServoChannels[channel].mid_scaled = (8 * (ServoChannels[channel].max - ServoChannels[channel].min) + \
157
                                            (16 * mid - 8 * ServoConst[Config.sIdxSteps].steps))/16 + ServoChannels[channel].min;
158
}
159
 
160
//! turns off software PWM system
161
void servoOff(void)
162
{
163
        // disable the timer1 output compare A interrupt
164
        TIMSK1 &= ~(1<<OCIE1A);
165
}
166
 
167
//! set servo position on channel (raw unscaled format)
168
void servoSetPositionRaw(uint8_t channel, uint16_t position)
169
{
170
        // bind to limits
171
        if (position < ServoChannels[channel].min) position = ServoChannels[channel].min;
172
        if (position > ServoChannels[channel].max) position = ServoChannels[channel].max;
173
        // set position
174
        ServoChannels[channel].duty = position;
175
}
176
 
177
//! set servo position on channel
178
// input should be between 0 and ServoSteps() (entspricht Maximalausschlag)
179
void servoSetPosition(uint8_t channel, uint16_t position)
180
{ uint16_t pos_scaled;
181
 
182
        // calculate scaled position
183
        if (ServoChannels[channel].rev != 0) position = ServoConst[Config.sIdxSteps].steps - position;
184
        if (position < ServoConst[Config.sIdxSteps].steps/2)
185
                //bei Position < Servomittelstellung    Position*(Mitte - Min)/(Servoschritte/2)
186
                pos_scaled = ServoChannels[channel].min + ((int32_t)position*2*(ServoChannels[channel].mid_scaled-ServoChannels[channel].min))/ \
187
                                                                 ServoConst[Config.sIdxSteps].steps;
188
        else
189
                //bei Position >= Servomittelstellung
190
                pos_scaled = ServoChannels[channel].mid_scaled + (uint32_t)(position - ServoConst[Config.sIdxSteps].steps / 2) \
191
                                                                 * 2 * (ServoChannels[channel].max-ServoChannels[channel].mid_scaled)/ServoConst[Config.sIdxSteps].steps;
192
        // set position
193
        servoSetPositionRaw(channel, pos_scaled);
194
}
195
 
196
// Umrechnung Winkel in Servoschritte
197
void servoSetAngle(uint8_t servo_nr, int16_t angle)
198
{
199
        servoSetPosition(servo_nr, (uint16_t)((uint32_t)angle * ServoConst[Config.sIdxSteps].steps / 180));
200
}
201
 
202
//Interruptroutine
203
ISR(TIMER1_COMPA_vect)
204
{ static uint8_t ServoChannel;
205
        uint16_t nextTics;
206
        uint16_t OCValue; // schedule next interrupt
207
 
208
        if(ServoChannel < SERVO_NUM_CHANNELS) {
209
                PORTD &= ~ServoChannels[ServoChannel].pin;              // turn off current channel
210
        }
211
        ServoChannel++; // next channel
212
        if(ServoChannel != SERVO_NUM_CHANNELS) {
213
                // loop to channel 0 if needed
214
                if(ServoChannel > SERVO_NUM_CHANNELS)           ServoChannel = 0;
215
                // turn on new channel
216
                PORTD |= ServoChannels[ServoChannel].pin;
217
                // schedule turn off time
218
                nextTics = ServoChannels[ServoChannel].duty;
219
        }
220
        else {
221
                // ***we could save time by precalculating this
222
                // schedule end-of-period
223
                nextTics = ServoPeriodTics-ServoPosTics;
224
        }
225
        // read in current value of output compare register OCR1A
226
        OCValue =       OCR1AL;                 // read low     byte of OCR1A
227
        OCValue += (OCR1AH <<8);                // read high byte of OCR1A
228
        OCValue += nextTics;                    // increment OCR1A value by nextTics
229
        // set future output compare time to this new value
230
        OCR1AH = OCValue >> 8;                  // write high byte
231
        OCR1AL = OCValue & 0x00FF;              // write low    byte
232
 
233
        ServoPosTics += nextTics;               // set our new tic position
234
        if(ServoPosTics >= ServoPeriodTics) ServoPosTics = 0;
235
}
236
#endif