PWM für Servo

OP #3252271
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
}
#3252276
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.
Gast #3252330
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.
Gast #3252357
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)
Gast #3252396
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
OP #3252687
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
}
Gast #3252780
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
#3253461
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 );

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren