Forum: Mikrocontroller und Digitale Elektronik Verständnissfrage Servo + PWM


von Nico B. (vegetico)


Lesenswert?

Moin,

ich spiel grade das erste Mal mit Servos und hab dafür den 
Modellbauservo Ansteuerung Artikel durchprobiert (als Hauptquelle).
Im Prinip war das zweite Beispiel meine Vorlage - lediglich mit anderen 
Werten (siehe code).
Die Positionen werden auch soweit angefangen - jedoch hört man nach der 
Ansteuerung ein relativ hohes Summen des Motors (egal ob Mitte, Links 
oder Rechts). Ich vermute mal, das ist weil ich die Pulse ja 
kontinuierlich sende.
Aber das Beispiel macht das doch eigentlich genau so.
Was mache ich hier mal wieder falsch??? Bin ich überhaupt im richtigen 
InterruptVetkor... OCF0 bzw. TimerCounter0 hat laut Datenblatt einen 
CompareMatch Interrupt - im Header finde ich den aber nicht.
PA0 ist nebenbei nur ne TestLED, die ich als 'Status' nehm und um zu 
sehen das die Frequenz so halbwechs passt. SleepOneSec is ne 1sec sleep.

Gruß
Nico

1
//OC0 at PB3
2
3
ISR( TIMER1_COMPA_vect )                // Interruptbehandlungsroutine
4
{
5
  // (4000000Hz/50Hz) = 80000 with 50Hz = 20ms Frequency
6
  // Timer prescaler = 64 ==> 80000/64 = 1250 ==> 1250 cycles form a 20ms pulse
7
  // calculate the amount of pulses for 1, 1.5 and 2ms (servo left, center and right)
8
  // 1/20 = x/1250 <=> x_L = 62.5; 2/20 = x/1250 <=> x_R=125, x_C = 94  
9
  OCR0 = 1250-OCR0;      
10
}
11
12
int main (void)
13
{  
14
  DDRA |= ((1<<PA0) | (1<<PA1));
15
16
  DDRB |= (1<<PB3); //PB3 Output
17
  
18
  //Toggle mode OC0 RefPage 84
19
  TCCR0 |= (1<<COM00);
20
  TCCR0 &= ~ (1<<COM01);
21
  
22
  //CTC mode RefPage 84
23
  TCCR0 |= (1<<WGM01);
24
  TCCR0 &= ~(1<<WGM00);
25
26
  //Prescaler 64 RefPage 85  
27
  TCCR0 |= ((1<<CS01) | (1<<CS00));
28
  TCCR0 &= ~(1<<CS02);
29
  
30
  TIFR |= (1<<OCF0);          // Timer-Compare Interrupt an
31
  
32
  OCR0 = 94; // Center position
33
  
34
  sei();                                // Interrupts global an
35
  
36
  while( 1 ) 
37
  {
38
    PORTA ^= (1<<PA0);
39
    OCR0 = 94;
40
    sleepOneSec();
41
    
42
    PORTA ^= (1<<PA0);
43
    OCR0 = 63;
44
    sleepOneSec();
45
    
46
    PORTA ^= (1<<PA0);
47
    OCR0 = 94;
48
    sleepOneSec();
49
    
50
    PORTA ^= (1<<PA0);
51
    OCR0 = 125;
52
    sleepOneSec();
53
  }
54
 
55
  return 0;
56
}

von Jakov K. (jackenkoffer)


Lesenswert?

Versuche mal einen größeren prescaler zu nehmen !
Gruß,
Jakov

von Nico B. (vegetico)


Lesenswert?

Weil OCR0 n 8bit Timer ist und der bei 1250-OCR0 nicht funktioniert???
Aber wenn ich doch
1
#define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
ausm dritten Beispiel nehm - dann müßte ich doch mit dem bei mir 
benutzen Prescaler von 64 hinkommen...

von Karl H. (kbuchegg)


Lesenswert?

> ISR( TIMER1_COMPA_vect )

Für welchen Timer könnte wohl diese ISR passend sein?
Timer 0, 1 oder 2?

von Karl H. (kbuchegg)


Lesenswert?

Nico B. schrieb:
> Weil OCR0 n 8bit Timer ist und der bei 1250-OCR0 nicht funktioniert???
> Aber wenn ich doch
>
1
> #define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
2
>
> ausm dritten Beispiel nehm - dann müßte ich doch mit dem bei mir
> benutzen Prescaler von 64 hinkommen...

Gesetz den Fall, dass sich letzters mathematisch ausgeht: die 1250 
können dann nicht passen.

von Nico B. (vegetico)


Lesenswert?

Das die ISR Vector falsch ist verstehe ich - allein schon vom Namen her. 
Was ich daran nicht verstehe - im Manual vom ATMega16 steht Timer0 
Compare Interrupt (Compare Match Interrupt Sources, S71) - den gibts 
aber nicht im Header:
1
/* Interrupt vectors */
2
/* Vector 0 is the reset vector. */
3
/* External Interrupt Request 0 */
4
#define INT0_vect      _VECTOR(1)
5
#define SIG_INTERRUPT0      _VECTOR(1)
6
7
/* External Interrupt Request 1 */
8
#define INT1_vect      _VECTOR(2)
9
#define SIG_INTERRUPT1      _VECTOR(2)
10
11
/* Timer/Counter2 Compare Match */
12
#define TIMER2_COMP_vect    _VECTOR(3)
13
#define SIG_OUTPUT_COMPARE2    _VECTOR(3)
14
15
/* Timer/Counter2 Overflow */
16
#define TIMER2_OVF_vect      _VECTOR(4)
17
#define SIG_OVERFLOW2      _VECTOR(4)
18
19
/* Timer/Counter1 Capture Event */
20
#define TIMER1_CAPT_vect    _VECTOR(5)
21
#define SIG_INPUT_CAPTURE1    _VECTOR(5)
22
23
/* Timer/Counter1 Compare Match A */
24
#define TIMER1_COMPA_vect    _VECTOR(6)
25
#define SIG_OUTPUT_COMPARE1A    _VECTOR(6)
26
27
/* Timer/Counter1 Compare Match B */
28
#define TIMER1_COMPB_vect    _VECTOR(7)
29
#define SIG_OUTPUT_COMPARE1B    _VECTOR(7)
30
31
/* Timer/Counter1 Overflow */
32
#define TIMER1_OVF_vect      _VECTOR(8)
33
#define SIG_OVERFLOW1      _VECTOR(8)
34
35
/* Timer/Counter0 Overflow */
36
#define TIMER0_OVF_vect      _VECTOR(9)
37
#define SIG_OVERFLOW0      _VECTOR(9)
38
39
/* Serial Transfer Complete */
40
#define SPI_STC_vect      _VECTOR(10)
41
#define SIG_SPI        _VECTOR(10)

OK, dann nehm ich mal nen anderen Prescaler und schau ob ich damit 
weiter komm - damit alles in OCR0 passt...

von Stefan E. (sternst)


Lesenswert?

Nico B. schrieb:
> Was ich daran nicht verstehe - im Manual vom ATMega16 steht Timer0
> Compare Interrupt (Compare Match Interrupt Sources, S71) - den gibts
> aber nicht im Header:

Es könnte helfen, sich alle Vektoren anzuschauen, und nicht nur die 
ersten 10 (müsste _VECTOR(19) sein).

von Nico B. (vegetico)


Lesenswert?

Fxxx, da unten kommt ja noch n TIMER0_COMP_vect...
Sorry, dachte die wären irgendwie gruppiert - und beim ersten Tippseln 
hatte ich wohl nen Rechtschreibfehler drin...
Dämlich...

von Nico B. (vegetico)


Lesenswert?

OK...
Eine (hoffentlich) letzte Frage.
Ich hab alle Änderungen von oben drin - jetzt habe ich noch ein Problem 
mit dem CTC mode...
Problem ist, dass sich mein Signal irgendwann invertiert, also aus:
1
_-______________
wird
1
-_--------------
Das Ganze passiert jede Sekunde - sprich es hängt mitm CTC und dem 
Interrupt zusammen... Ich verstehs aktuell aber nicht.
Der Code dafür ist wie folgt:
1
#define F_CPU 4000000UL
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
#define SERVO_DDR DDRD
8
#define SERVO_PORT PD7
9
#define SERVO_POSITION OCR2
10
11
#define SERVO_FREQU 78
12
#define SERVO_CENTER 6
13
#define SERVO_MAX 8
14
#define SERVO_MIN 4
15
16
ISR( TIMER2_COMP_vect )            
17
{
18
  SERVO_POSITION = SERVO_FREQU - SERVO_POSITION;    
19
}
20
21
void sleepOneSec();
22
23
int main (void)
24
{  
25
  DDRA |= ((1<<PA0) | (1<<PA1));
26
27
  SERVO_DDR |= (1<<SERVO_PORT); 
28
  
29
  //Toggle mode OC2 
30
  TCCR2 |= (1<<COM20);
31
  TCCR2 &= ~ (1<<COM21);
32
  
33
  //CTC mode 
34
  TCCR2 |= (1<<WGM21);
35
  TCCR2 &= ~(1<<WGM20);
36
37
  //Prescaler 1024 RefPage   
38
  TCCR2 |= ((1<<CS22)|(1<<CS21)|(1<<CS20));
39
  //TCCR2 &= ~ ((1<<CS21)|(1<<CS20));
40
  
41
  TIMSK |= (1<<OCIE2);  // Timer-Compare Interrupt an
42
  
43
  SERVO_POSITION = SERVO_CENTER;  // Center position
44
45
  sei();                 // Interrupts global an
46
  
47
  while( 1 ) 
48
  {
49
    PORTA ^= (1<<PA0);
50
    SERVO_POSITION = SERVO_MIN;
51
    sleepOneSec();
52
  }
53
 
54
  return 0;
55
}

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.