Forum: Mikrocontroller und Digitale Elektronik Potentiometer + Servomotor I Atmega328PB


von Phillip E. (phillipernst1998)


Lesenswert?

Guten Tag,

ich bins wieder. Ich habe hier die Erweituerung zu meinem vorherigen 
Beitrag. diesmal muss mit dem Potentiometer ein Servomotor bewegt 
werden. Ich habe den Code so gut es geht vervollständigt nur gibt es 
einige Unstimmigkeiten im Code die ich bis jetzt nicht rausfinden 
konnte. Vielleicht kann hier jemand weiterhelfe, hat dass letzte mal so 
gut geklappt! :D

Ich glaube bei diesen zwei Punkten liegt mein Fehler.

1.

Dazu ist der Timer/Counter 1 so zu konfigurieren, dass er im Fast PWM 
Mode mit
einer Taktteilung im Teilverhältnis von 1/8 betrieben wird, die 
PWM-Frequenz über
OCR1A auf 20 ms eingestellt wird und OCR1B das Tastverhältnis bestimmt.

2.

In den beiden ISRs des Timer/Counter 1 (Overflow und Compare-Match B) 
soll der
für die Poti-Steuerung genutzte Port-Pin jeweils passend zum benötigten 
PWMSignal modifiziert werden.

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
}

von m.n. (Gast)


Lesenswert?

Phillip E. schrieb:
> diesmal muss mit dem Potentiometer ein Servomotor bewegt
> werden.

Das würde ich noch einmal überdenken ;-)

von S: Landolt (Gast)


Angehängte Dateien:

Lesenswert?

> ... beiden ISRs des Timer/Counter 1 (Overflow und Compare-Match B)
Dann ist die Capture-ISR ('ISR(TIMER1_CAPT_vect)') wohl nicht das 
Richtige, siehe Anhang.

> OCR1B = (2000/1023) * ...
Als C-Laie weiß ich nicht, ob mit Brüchen gerechnet werden kann, mein 
avrasm2  kann nur Ganzzahlen, macht also z.B. aus '(2000/1023)*100' 100 
statt dem erwarteten 195.

von S: Landolt (Gast)


Lesenswert?

PS:
Also der avrasm2 rechnet schon mit Brüchen, aber das (Zwischen-)Ergebnis 
ist eine ganze Zahl. Man muss gegebenenfalls die Faktoren umstellen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.