1 | #define F_CPU 16000000
|
2 |
|
3 | //Nachfolgend müssen zwei Bibliotheks-Dateien eingebunden werden (bitte Punkte passend ersetzen)
|
4 | #include <avr/interrupt.h>
|
5 | #include <avr/io.h>
|
6 |
|
7 | // Deklaration der globalen Variablen
|
8 | int16_t servo_offset; // Wert (negativ oder positiv) der als Offset mit dem
|
9 | // Mittenpositionswert des Servos verrechnet wird
|
10 |
|
11 | //Compare-Register-Werte für PWM-Betrieb
|
12 | #define SERVO_PERIOD 40000 // Compare-Wert 40.000 entspricht 20 ms
|
13 | #define SERVO_PULSE_MAX 4000 // Compare-Wert 4.000 entspricht 2 ms = Servo-Maximalwert
|
14 | #define SERVO_PULSE_MID 3000 // Compare-Wert 3.000 entspricht 1,5 ms = Servo-Mittelstellung
|
15 | #define SERVO_PULSE_MIN 2000 // Compare-Wert 2.000 entspricht 1 ms = Servo-Minimalwert
|
16 |
|
17 | // Interrupt-Service-Routine des ADC
|
18 | ISR(ADC_vect) // An dieser Stelle muss die Deklarations-Kopfzeile korrekte vervollständigt werden
|
19 | {
|
20 |
|
21 | servo_offset = ADCL; // servo_offset aus ADC-Wert berechnen
|
22 | servo_offset += (ADCH<<8); // im Wertebereich -1024 ... 1023
|
23 | // (ACHTUNG: ADC-Wert ist unsigned integer)
|
24 |
|
25 | OCR1B = (2000/1023)* servo_offset + 2000; // Compare-Wert für t_high = 1 ... 2 ms aus
|
26 | // servo_offset berechnen
|
27 | // (ACHTUNG: OCR1B-Wert ist unsigned integer)
|
28 | }
|
29 |
|
30 | // Interrupt-Service-Routine des Timer/Counter 0
|
31 | ISR(TIMER0_COMPA_vect) // An dieser Stelle muss die Deklarations-Kopfzeile korrekt vervollständigt werden
|
32 | {
|
33 | ADCSRA |= (1<<ADSC); // Neue ADC-Sequenz starten
|
34 | }
|
35 |
|
36 | // Interrupt-Service-Routine des Timer/Counter 1 (Startzeitpunkt einer neuen PWM-Periode)
|
37 | ISR(TIMER1_CAPT_vect) // An dieser Stelle muss die Deklarations-Kopfzeile korrekt vervollständigt werden
|
38 | {
|
39 | PORTC |= 0xFF; // Servo-Ausgang selektiv auf HIGH
|
40 | }
|
41 |
|
42 | // Interrupt-Service-Routine des Timer/Counter 1 (Endzeitpunkt der HIGH-Phase einer PWM-Periode)
|
43 | ISR(TIMER1_CAPT_vect) // An dieser Stelle muss die Deklarations-Kopfzeile korrekt vervollständigt werden
|
44 | {
|
45 | PORTC &= ~(1 << 2); // Servo-Ausgang selektiv auf LOW
|
46 | }
|
47 |
|
48 | int main(void)
|
49 | {
|
50 | // ADC initialisieren
|
51 | ADMUX = (1 << REFS0 ); // ADC Referenzspannung AVcc, rechtsbündige
|
52 | // Ausrichtung für 10 Bit, Kanal 0 als ADC-Eingang
|
53 | // (ACHTUNG: Ausrichtung und Bitbreite sind anders als
|
54 | // in V3 Teil1 !!!)
|
55 | ADCSRA =(1 << ADEN) | (1 << ADIE) |( 1 << ADPS0) | ( 1 << ADPS2); // ADC aktivieren, ADC Interrupt, Frequenzteiler 32
|
56 |
|
57 | // Timer/Counter 0 initialisieren: CTC Modus, Prescaler 1/1024, Interrupt-Intervall 10 ms genau wie in V3 Teil1
|
58 | TCCR0A = (1<<WGM01);
|
59 | TCCR0B = (1<<CS02)|(1<<CS00) ;
|
60 | OCR0A = 156 ; // s. Formel aus Versuchsbeschreibung zu Versuch 2
|
61 | TIMSK0 = (1<<OCIE0A); // Compare-Interrupt A freigeben
|
62 |
|
63 | // Timer/Counter 1 initialisieren als PWM-Generator: Fast PWM, Prescaler 1/8, Compare Match IRQ B, Overflow IRQ
|
64 | // -> t_periode = 20 ms, t_high = 1,5 ms (Servo-Mittelstellung)
|
65 | TCCR1A = (1<<WGM10)|(1<<WGM11) ;
|
66 | TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS11);
|
67 | OCR1A = SERVO_PERIOD; // Bestimmt die PWM-Periodendauer
|
68 | OCR1B = SERVO_PULSE_MID; // Bestimmt die PWM-Pulsweite für Servo-Mittelstellung
|
69 | TIMSK1 = (1<<OCIE1B)|(1<<TOIE1); // Compare-Interrupt B und Overflow-Interrupt freigeben
|
70 |
|
71 | // Servo initialisieren
|
72 | DDRC |= 0b00000100; // Servo-Ausgang selektiv auf OUTPUT
|
73 | PORTC &= ~(1 << 2); // Servo-Ausgang selektiv auf LOW
|
74 |
|
75 | sei(); // Interrupts global freigeben
|
76 |
|
77 | while (1)
|
78 | {
|
79 | // Hier ist kein Code erforderlich
|
80 | }
|
81 | }
|