servo.c


1
//
2
// Programm fuer einen ATmega16
3
//
4
#define F_CPU 11056000UL
5
 
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <util/delay.h>
9
 
10
//
11
// Der Prescaler muss so gewählt werden, dass der Ausdruck
12
// für MILLISEC_BASE einen Wert kleiner als 128 ergibt
13
// MILLISEC_BASE ist der Timerwert, der 1 Millisekunde Zeitdauer ergeben
14
// soll.
15
//
16
#define PRESCALER      128
17
#define PRESCALER_BITS (1<<CS22) | ( 1 << CS20 )
18
 
19
#define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
20
#define CENTER         ( MILLISEC_BASE / 2 ) 
21
 
22
//
23
// Konfiguration der Servoleitungen
24
//
25
#define NR_SERVOS      8
26
#define SERVO_DDR      DDRD
27
#define SERVO_PORT     PORTD
28
uint8_t ServoPuls[NR_SERVOS] = { 1<<PD0, 1<<PD1, 1<<PD2, 1<<PD3,
29
                                 1<<PD4, 1<<PD5, 1<<PD6, 1<<PD7 };
30
//
31
// Werte für die Servoposition
32
// Gültige Werte laufen von 0 bis 2 * CENTER
33
// 0           ... ganz links
34
// CENTER      ... Mittelstellung
35
// 2 * CENTER  ... ganz rechts
36
//
37
volatile uint8_t ServoValue[NR_SERVOS];
38
 
39
ISR (TIMER2_COMP_vect) 
40
{
41
  static uint8_t ServoId = 0;
42
 
43
  //
44
  // den Puls des aktuellen Servos beenden
45
  //
46
  SERVO_PORT &= ~ServoPuls[ServoId];
47
 
48
  //
49
  // welches ist das nächste aktuelle Servo?
50
  //
51
  if( ++ServoId >= NR_SERVOS )
52
    ServoId = 0;
53
 
54
  //
55
  // die Ausgangsleitung fuer dieses Servo auf 1; den Puls beginnen
56
  //
57
  SERVO_PORT |= ServoPuls[ServoId];
58
 
59
  //
60
  // den Timer so einstellen, dass bei Pulsende, die ISR erneut aufgerufen wird
61
  //
62
  OCR2 = MILLISEC_BASE + ServoValue[ServoId];
63
}
64
 
65
void InitServo()
66
{
67
  uint8_t i;
68
 
69
  //
70
  // Die Servoleitungen auf Ausgang stellen
71
  //
72
  SERVO_DDR = ServoPuls[0] | ServoPuls[1] | ServoPuls[2] | ServoPuls[3] |
73
              ServoPuls[4] | ServoPuls[5] | ServoPuls[6] | ServoPuls[7];
74
 
75
  //
76
  // Alle Servos in Mittelstellung
77
  //
78
  for( i = 0; i < NR_SERVOS; ++i )
79
    ServoValue[i] = CENTER;
80
 
81
  //
82
  // Timer auf CTC Modus konfigurieren
83
  //
84
  OCR2 = MILLISEC_BASE + ServoValue[0];
85
  TIMSK |= (1<<OCIE2);
86
  TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // CTC mode
87
}
88
 
89
int main(void)
90
{
91
  InitServo();
92
 
93
  sei();
94
 
95
  _delay_ms( 1000 );
96
 
97
  //
98
  // testweise einfach alle 8 Servos ansteuern
99
  // jedes Servo soll sich unterschiedlich schnell bewegen
100
  //
101
  while( 1 ) {
102
 
103
 
104
    ServoValue[0] += 2;
105
    if( ServoValue[0] > 2*CENTER )
106
      ServoValue[0] -= 2*CENTER;
107
 
108
    ServoValue[1] += 1;
109
    if( ServoValue[1] > 2*CENTER )
110
      ServoValue[1] -= 2*CENTER;
111
 
112
    ServoValue[2] += 2;
113
    if( ServoValue[2] > 2*CENTER )
114
      ServoValue[2] -= 2*CENTER;
115
 
116
    ServoValue[3] += 3;
117
    if( ServoValue[3] > 2*CENTER )
118
      ServoValue[3] -= 2*CENTER;
119
 
120
    ServoValue[4] += 1;
121
    if( ServoValue[4] > 2*CENTER )
122
      ServoValue[4] -= 2*CENTER;
123
 
124
    ServoValue[5] += 3;
125
    if( ServoValue[5] > 2*CENTER )
126
      ServoValue[5] -= 2*CENTER;
127
 
128
    ServoValue[6] += 2;
129
    if( ServoValue[6] > 2*CENTER )
130
      ServoValue[6] -= 2*CENTER;
131
 
132
    ServoValue[7] += 1;
133
    if( ServoValue[7] > 2*CENTER )
134
      ServoValue[7] -= 2*CENTER;
135
 
136
    _delay_ms( 40 );
137
  }
138
}