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 | }
|