Forum: Mikrocontroller und Digitale Elektronik PWM für Servo


von Mike N. (drumy)


Lesenswert?

Hallo Leute,
nach mehr stündigem Googlen und Forum durchsuchen konnte ich nichts 
finden daher Post ich mal.

Ich habe nen ATMega 168 und möchte gern einen Servo ansteuern über eine 
PWM. Dafür habe ich OCR0A für den Servo und OCR0B fürs Relais gesetzt.

Ich habe mir ein kleines C Programm geschrieben das meine Servo aber nur 
Fiepen lässt statt sich zu drehen.

Sieht wer nen programmier/Denkfehler?

Liebe Grüße
Mike
1
/*###################################
2
  ###################################
3
  ##### PWM für Servor-Motor ########
4
  #####                      ########
5
  #####   Datum:21.07.2013   ########
6
  ###################################
7
  ###################################
8
 */
9
#ifndef F_CPU
10
#define F_CPU 8000000UL
11
#endif
12
13
#include <avr/io.h>
14
#include <util/delay.h>
15
//#include <avr/iom168.h>
16
#include <stdint.h>
17
18
19
void InitPWM()
20
{
21
   /*
22
   TCCR0B - Timer Counter Control Register (TIMER0)
23
   -----------------------------------------------
24
25
   Bit    Name                Wert
26
   ----------------------------------------------------------
27
   BIT 7 : FOC0   Force Output Compare      0
28
   BIT 6 : WGM00  Wave form generartion mode   0
29
   BIT 5 : COM01  Compare Output Mode          0
30
   BIT 4 : COM00  Compare Output Mode          0
31
32
   BIT 3 : WGM02  Wave form generation mode   0
33
   BIT 2 : CS02   Clock Select          0
34
   BIT 1 : CS01   Clock Select                 0
35
   BIT 0 : CS00   Clock Select                 1
36
37
   Einstellungen PWM
38
   --------------------------
39
40
   Timer Clock = CPU Clock (/1024)
41
   Mode        = Fast PWM
42
   PWM Output  = Non Inverted
43
44
45
   */
46
47
48
   TCCR0A |= 0xA3;
49
   TCCR0B |= 0x01;
50
51
   //Output Setzen
52
53
   DDRD |= 0x60;
54
}
55
56
/******************************************************************
57
Setzt Vout auf OCR0A und OCR0B PIN.
58
Wert: Zwischen 0 - 255
59
60
0= 0%
61
62
255= 100%
63
64
65
         Wert
66
 Vout=  ------ x 5v
67
         255
68
69
*********************************************************************/
70
71
void SetPWMOut(uint8_t wert)
72
{
73
  OCR0A=wert;
74
  OCR0B=wert;
75
}
76
77
/********************************************************************
78
79
Pause
80
81
*********************************************************************/
82
83
void Pause()
84
{
85
_delay_ms(15);
86
}
87
88
void main()
89
{
90
91
92
   //PWM Initialisieren Channel 0
93
   InitPWM();
94
95
   while(1)
96
   {
97
      //PWM mit 50%
98
     for(int i=0;i<200;i=i+10)
99
     {
100
       SetPWMOut(i);
101
       _delay_ms(1);
102
     }
103
104
     for(int i=200;i>=0;i=i-10)
105
     {
106
       SetPWMOut(i);
107
       _delay_ms(1);
108
     }
109
110
   }
111
}

von Falk B. (falk)


Lesenswert?

@ Mike N. (drumy)

>nach mehr stündigem Googlen und Forum durchsuchen konnte ich nichts
>finden

Dann bist du en grottenschlechter Sucher.

http://www.mikrocontroller.net/search?query=%2BServo+%2Bavr&forums[]=1&forums[]=19&forums[]=9&forums[]=10&forums[]=2&forums[]=4&forums[]=3&forums[]=6&forums[]=31&forums[]=17&forums[]=11&forums[]=8&forums[]=14&forums[]=12&forums[]=7&forums[]=5&forums[]=15&forums[]=13&forums[]=18&forums[]=16&max_age=-&sort_by_date=0

>Ich habe nen ATMega 168 und möchte gern einen Servo ansteuern über eine
>PWM. Dafür habe ich OCR0A für den Servo und OCR0B fürs Relais gesetzt.

>Ich habe mir ein kleines C Programm geschrieben das meine Servo aber nur
>Fiepen lässt statt sich zu drehen.

>Sieht wer nen programmier/Denkfehler?

8 MHz CPU Takt / 1024 = 8kHz / 256 = 32 Hz

Das ist OK.

Aber deine PWM von 0-200 in 10er Schritten ist es nicht. Ein Servosignal 
hat eine Pulsbreite von 1ms (=linker Anschlag) 1,5ms (Mittelstellung) 
bis 2ms (rechter Anschlag). Darum erzeugt der Rest der Welt eine 
Servosignal mit Timer 1, der ist nämlich 16 Bit und kann damit das 
Servosignal optimal erzeugen. Periodendauer um die 20ms.

von Mike N. (drumy)


Lesenswert?

Also gut gefunden schon aber nichts was so richtig gepasst hat..
Gut dann ist mein fehler quasi nur das ich besser den 16 Bit statt 8 Bit 
Timer nehmen soll?

von Michael (Gast)


Lesenswert?

Mike N. schrieb:
> Also gut gefunden schon aber nichts was so richtig gepasst hat..
> Gut dann ist mein fehler quasi nur das ich besser den 16 Bit statt 8 Bit
> Timer nehmen soll?

Du kannst auch einen 8-Bit Timer für die 1..2ms Pulsbreite verwenden und 
die (unkritischen) 20ms aus irgendeinem Task-Takt ableiten.

von Falk B. (falk)


Lesenswert?

@ Mike N. (drumy)

>Also gut gefunden schon aber nichts was so richtig gepasst hat..
>Gut dann ist mein fehler quasi nur das ich besser den 16 Bit statt 8 Bit
>Timer nehmen soll?

Ja.

von Peter (Gast)


Lesenswert?

Ich habe letzte Woche auch einen Servo mit dem Atmega328 zum laufen 
gebracht.

Falk hat das aber schon schön beschrieben.

An deiner Stelle würde ich auch den 16bit Timer verwenden.
Wenn du den 8 bit Timer verwendest ist die Auflösung der 1-2ms sehr 
beschränkt.

Richte den prescaler so ein dass du auf etwas mehr als 20ms mit maxValue 
für den Timer kommst. (Für diesen einfache Beispiel ~ Wert 250, weil 
maxValue beim Timer0 oder 2 256 ist)

Dann rechne dir 1-2ms aus. 200 wäre viel zu viel. 1ms wäre dann ~12 und 
2ms ~25.


(Außerdem solltest/könntest du compare inverted nehmen, weil du zuerst 1 
haben möchtest, dann 0 für die längere Zeit)

von Spess53 (Gast)


Lesenswert?

Hi

>Richte den prescaler so ein dass du auf etwas mehr als 20ms mit maxValue
>für den Timer kommst. (Für diesen einfache Beispiel ~ Wert 250, weil
>maxValue beim Timer0 oder 2 256 ist)

Wozu brauchst du noch einen 8-Bit-Timer. Ein 16-Bit-Timer reicht 
vollkommen.


>(Außerdem solltest/könntest du compare inverted nehmen, weil du zuerst 1
>haben möchtest, dann 0 für die längere Zeit)

Ja. Und das ist 'non inverted'.

MfG Spess

von Michael (Gast)


Lesenswert?

Peter schrieb:
> Wenn du den 8 bit Timer verwendest ist die Auflösung der 1-2ms sehr
> beschränkt.

So beschränkt nun auch wieder nicht. Mit 8 Bit liegt die Auflösung 
immerhin bei 2 Prozent.
AVR-Tutorial: Servo: Ansteuerung mit dem 8-Bit Timer 2

von Mike N. (drumy)


Lesenswert?

habs jetzt umgeschrieben aber irgendwie macht er jetzt keinen muks 
mehr..
1
/*###################################
2
  ###################################
3
  ##### PWM für Servor-Motor ########
4
  #####                      ########
5
  #####   Datum:21.07.2013   ########
6
  ###################################
7
  ###################################
8
 */
9
#ifndef F_CPU
10
#define F_CPU 8000000UL
11
#endif
12
13
#include <avr/io.h>
14
#include <util/delay.h>
15
//#include <avr/iom168.h>
16
#include <stdint.h>
17
18
19
void InitPWM()
20
{
21
   /*
22
     Einstellungen PWM
23
   --------------------------
24
25
   Timer Clock = CPU Clock (/8)
26
   Mode        = Fast PWM
27
   PWM Output  = Non Inverted
28
29
30
   */
31
32
33
   TCCR1A |= 0xA3;
34
   TCCR1B |= 0x1A;
35
36
   //Output Setzen
37
38
   DDRB |= 0x60;
39
}
40
41
/******************************************************************
42
Setzt Vout auf OCR0A und OCR0B PIN.
43
Wert: Zwischen 0 - 255
44
45
0= 0%
46
47
255= 100%
48
49
50
         Wert
51
 Vout=  ------ x 5v
52
         255
53
54
*********************************************************************/
55
56
void SetPWMOut(uint8_t wert)
57
{
58
  OCR1A=wert;
59
  OCR1B=wert;
60
}
61
62
/********************************************************************
63
64
Pause
65
66
*********************************************************************/
67
68
void Pause()
69
{
70
_delay_ms(15);
71
}
72
73
void main()
74
{
75
76
77
   //PWM Initialisieren Channel 0
78
   InitPWM();
79
80
   while(1)
81
   {
82
83
     for(int i=0;i<1000;i++)
84
     {
85
       SetPWMOut(i);
86
       _delay_ms(19);
87
     }
88
89
     for(int i=1000;i>=0;i--)
90
     {
91
       SetPWMOut(i);
92
       _delay_ms(19);
93
     }
94
95
   }
96
}

von spess53 (Gast)


Lesenswert?

Hi

>   TCCR1A |= 0xA3;
>   TCCR1B |= 0x1A;

Du machst es denen, die dir helfen wollen und auch dir selbst echt 
schwer.

Wenn du die Schreibweise
1
TCCR1A |= (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11)
2
TCCR1B |= (1<<WGM13)|(1<<WGM12)|(1<<CS11)
benutzt weiß jeder sofort, was da eingestellt ist.

>habs jetzt umgeschrieben aber irgendwie macht er jetzt keinen muks
>mehr..

Kein Wunder. Du willst den PWM-Mode 14 mit ICR1 als Top-Wert benutzen. 
Da must du aber auch ICR1 mit einem Wert, in dem Fall 20000, versehen. 
OCR1A und OCR1B dürfen sich für 1..2ms im Bereich von 1000...2000 
bewegen.

MfG Spess

von Mike N. (drumy)


Lesenswert?

spess53 schrieb:
> Kein Wunder. Du willst den PWM-Mode 14 mit ICR1 als Top-Wert benutzen.
> Da must du aber auch ICR1 mit einem Wert, in dem Fall 20000, versehen.
> OCR1A und OCR1B dürfen sich für 1..2ms im Bereich von 1000...2000
> bewegen.


gemacht ändert nichts an der servo steht still..
1
ICR1=20000

von Falk B. (falk)


Lesenswert?

Miss mit einem Multimeter die Spannung an deinem PWM Pin. Dort muss bei 
1ms Puls und 20ms Periodendauer 1/20 VCC messbar sein, bei 2ms 
logischerweise 2/20 Vcc. Optimalerweise misst man mit einem Oszi, dann 
sieht man direkt, was los ist.

von Karl H. (kbuchegg)


Lesenswert?

>    DDRB |= 0x60;


Wieso 0x60

AM Mega168 liegt OC1A am Pin PB1 und OC1B am Pin PB2


Gewöhn dir doch bitte diese bescheuerten Hex-Zahlen Schreibweisen ab!
Ich hab wirklich keine Lust mehr zum 500-millionsten mal wieder mal eine 
Hex-Zahl gedanklich in Bits zu zerlegen, nur damit ich dann deinen Job 
machen kann und im Datenblatt nachsehe, welche Pins du eigentlich auf 
Ausgang stellst und ob das die richtigen sind.

  DDRB |= ( 1 << PB1 ) | ( 1 << PB2 );

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.