Servosteuerung mit ATMEGA88 und Assembler

OP #4294435
Lesenswert?

Sehr geehrtes Forum,
ich habe mal wieder ein Problem :|.
(Newbie Problem, einfaches Programm, nicht sinnvoll)

Ich möchte gerne einen Servo ansteuern.
Diesen versorge ich extern mit 5 V, und habe dessen GND
auch mit dem GND des Chips verbunden, welcher übrigstens auch mit 5V
versorgt wird.

Mein Servo hat die Kabelfarben Rot, Gelb und Braun, d.h. Rot = 5V, Braun 
= GND und Geld = Signal?

Nun habe ich folgendes Programm, welches ich schon mehrmals mit dem 
Debugger auf richtige Wartezeit der Wartemethoden geprüft habe, ebenso 
wie auch durch Testen der WAIT_1_SEC Methode mit einer LED in echt.
1
.include "m88def.inc"   
2

3
/*
4

5
  Servosteuerung, durch Pulse zwischen 1ms und 2ms, alle 20ms
6

7
  Taktfrequenz des MC: 1 MHz
8
*/
9

10
.CSEG 
11
//  Definitionen
12
.def POSITION = R20
13
  
14
// Richtung der IO Ports definieren
15
LDI R16, 0b11111111    // 1=Output, 0=Input
16
OUT DDRD, R16
17

18
// Stackpointer initialisieren
19
LDI R16, low(RAMEND)
20
OUT SPL, R16
21
LDI R16, high(RAMEND)
22
OUT SPH, R16
23

24
// Main Methode
25

26
MAIN:
27
  LDI POSITION, 20 // Servo nach links stellen  = 2,0 ms
28
  RCALL SERVO_COMMAND
29
  RCALL WAIT_1_SEC
30

31
  LDI POSITION, 15 // Servo nach mitte stellen  = 1,5 ms
32
  RCALL SERVO_COMMAND
33
  RCALL WAIT_1_SEC
34

35
  LDI POSITION, 10 // Servo nach rechts stellen = 1,0 ms
36
  RCALL SERVO_COMMAND
37
  RCALL WAIT_1_SEC
38

39
RJMP MAIN
40

41
// Servo Motor Positionieren
42
SERVO_COMMAND:
43
  LDI R25, 10
44
  
45
  SERVO_COMMAND_2:
46

47
    MOV R21,R20
48
    SBI PORTD,PD0
49
    SERVO_COMMAND_1:
50
      RCALL WAIT_100_MIC_SECS
51
      DEC R20
52
      BRNE SERVO_COMMAND_1
53

54
    MOV R20,R21
55
    CBI PORTD, PD0
56
    RCALL WAIT_10_MIL_SECS
57
    RCALL WAIT_10_MIL_SECS
58

59
    DEC R25
60
    BRNE SERVO_COMMAND_2
61
RET
62

63

64
// WAIT 100_MIC_SECS
65
WAIT_100_MIC_SECS:
66
  LDI R17, 3
67
  WAIT_100_MIC_SECS_2:
68
    LDI R16,9
69
    WAIT_100_MIC_SECS_1:
70
      DEC R16
71
      BRNE WAIT_100_MIC_SECS_1
72
    DEC R17
73
    BRNE WAIT_100_MIC_SECS_2
74
  NOP
75
  NOP
76
  NOP
77
RET
78

79
// WAIT 10_MIL_SECS
80
WAIT_10_MIL_SECS:
81
  LDI R18, 100
82
  WAIT_10_MIL_SECS_1:
83
    RCALL WAIT_100_MIC_SECS
84
    DEC R18
85
    BRNE WAIT_10_MIL_SECS_1
86
RET
87

88
// WAIT 1_SEC
89
WAIT_1_SEC:
90
  LDI R19, 100
91
  WAIT_1_SEC_1:
92
    RCALL WAIT_10_MIL_SECS
93
    DEC R19
94
    BRNE WAIT_1_SEC_1
95
RET

Das Programm sendet also 10 mal einen Impuls, welcher 2ms dauert, und im 
Abstand von 20ms. Der Servo sollte also nach links.
Dann wartet das Programm 1 Sekunde.
Dann 10 mal einen Impuls, welcher 1,5ms dauert, und ebenfalls im Abstand 
von 20ms. Der Servo sollte also in die mitte.
Dann wartet das Programm 1 Sekunde.
Dann 10 mal einen Impuls, welcher 1,0ms dauert, und ebenfalls im Abstand 
von 20ms. Der Servo sollte also rechts.
Dann wartet das Programm 1 Sekunde.

Ich hab das Signal meines MCs auch schon an ne LED gelegt, es kommt 
definitiv beim Servo an.

Nun passiert folgendes: Der Servo dreht sich bis zum Anschlag nach 
rechts, egal ob ich 1,0ms, 1,5ms oder 2,0ms Pulse sende.

Kann mir jemand sagen was ich falsch mache?

Ich habe den Anschluss mehrfach überprüft, und denke, dass ich laut 
diesem Tutorial 
https://www.mikrocontroller.net/articles/Modellbauservo_Ansteuerung auch 
richtig mit meinen Annahmen in Bezug auf die Belegung gehe.

Danke sehr für eure Hilfe,
m.f.G.: Developer_X
Gast #4294515
Lesenswert?

Ich weiss ja nicht ob sich da was geändert hat, aber früher (TM) musste 
das Signal kontinuierlich gesendet werden und
1ms / 2ms waren vollausschlag li/re und 1,5ms Neutral. Alles dazwischen 
irgendwas anderes. Pausen mochte das System garnicht =Ausfall, ggf. 
Notstellung.

Wie schon geschrieben, das Datenblatt ist Dein Freund.

//hufnala
#4294583
Lesenswert?

A. B. schrieb:

> Dann wartet das Programm 1 Sekunde.

Du kannst nicht 1 Sekunde lang nichts tun.
Ein Servo will ständig Pulse!

Die Pulse sagen ihm, welche Position es anfahren (und halten) soll. 
Kommen keine Pulse mehr, dann macht es irgendwas (je nach Typ).
D.h. wenn du das Servo 1 Sekunde lang an einer Position halten willst, 
dann musst du ihm auch 1 Sekunde lang genau die Pulslänge dafür 
schicken.

Und spätestens jetzt rächt sich dein Delay-Ansatz. Denn wenn man das 
geschickt macht, dann erzeugt der Timer ganz von alleine ständig die 
richtigen Pulse.

Ich hab deine Code-Zeiten jetzt nicht kontrolliert und nachgerechnet. 
Aber wenn du erst mal von einem ständigen Wechsel des Servos Abstand 
nimmst, dann schickst du ihm erst mal einfach nur eine immer gleiche 
Pulslänge. Zb 1.7ms. Das Servo muss dann genau diese Position anfahren. 
Als Gegentest schickst du ihn eine andere Pulslänge (natürlich ständig). 
Zum Bleistift 1.2ms. Das Servo muss dann diese andere Position anfahren. 
Und natürlich halten.

Wenn es das nicht tut, dann stimmen deine Pulslängen nicht.

(Deine Kabelbelegung dürfte stimmen. Rot ist Spannung, Braun ist Masse, 
Gelb ist Signal)
OP #4295001
Lesenswert?

So, ich habe mir das lange nochmal durch den Kopf gehen lassen.

Ich habe hier, ein ganz primitives C-Programm, viel schneller lesbar als 
ein Assembler Programm
1
#include <avr/io.h>          
2
#include <util/delay.h>
3

4
int main (void) 
5
{            
6
   DDRD  = 0xFF;             
7
   PORTD = 0b00000000;
8

9
   while(1) 
10
   {               
11
    PORTD = 0b00000001;
12
    _delay_us(1500);
13

14
    PORTD = 0b00000000;
15
    _delay_ms(20);
16
   }  
17

18
   return 0;          
19
}

Ich mein hier sieht man doch, dass die Signale dauerhaft gesendet 
werden, und zwar dauerhaft, im Abstand von 20ms, für eine Pulsdauer von 
1,5ms.

Was konkret passiert: Jedes mal wenn der MC solch einen Puls sendet, 
reagiert der Servo, und dreht sich rechts an den Anschlag, egal wie lang 
ich die Pulslänge mache.

Denkt ihr, es könnte ein Fehler am Servo sein?
Er dreht sich nur in die eine Richtung.

Danke für eine Antwort,
m.f.G.: Developer_X
#4295002
Lesenswert?

A. B. schrieb:

> Denkt ihr, es könnte ein Fehler am Servo sein?

Wenn ich mal davon ausgehe, dass die Verkabelung stimmt, dann kommt auch 
noch die Stromversorgung in Frage.
Servos können richtige Dreckschweine sein und dir massenhaft Störungen 
auf die Versorungsspannung einkoppeln. Die muss gut gesiebt werden, 
sonst schmiert dir der µC dauernd ab.
OP #4295010
Lesenswert?

Ich weiß woran es noch liegen könnte:
Wie stellt man bei der Delay.h ein, welche Taktgeschwindigkeit
am MC eingestellt ist? (Ich nutze C nicht, deswegen weiß ich das nicht 
:( )

Ich habe nämlich eine Geschwindigkeit von 1MHz, könnte diese auf 8 MHz 
hochsetzen, hat beides aber auch nichts gebracht.
#4295015
Lesenswert?

A. B. schrieb:
> Aber er kann nicht kaputt sein, da dieser reagiert, oder?

'türlich kann er trotzdem defekt sein. Das Servo bestimmt seine Position 
anhand eines Potentiometers auf der Achse. Hat bspw. der Schleifer 
keinen richtigen Kontakt mehr, spinnt das Servo. Da hilft nur Gegenprobe 
mit einem (funktionierenden) RC-Empfänger oder Servotester.
OP #4295016
Lesenswert?

1
#include <avr/io.h>          
2
#include <util/delay.h>
3

4
#define F_CPU 1000000UL
5

6
int main (void) 
7
{            
8
   DDRD  = 0xFF;             
9
   PORTD = 0b00000000;
10

11
   while(1) 
12
   {               
13
    PORTD = 0b00000001;
14
    _delay_us(1500);
15

16
    PORTD = 0b00000000;
17
    _delay_ms(20);
18
   }  
19

20
   return 0;          
21
}

Habs jetzt, funktioniert aber immer noch nicht, der Servo dreht nach wie 
vor nur nach rechts. :(
Gast #4295025
Lesenswert?

Tschuldig das ich störe...

aber warum nutzt nicht nen Timer der dir die 1-2ms generiert und mit den 
selben Timer kannst du, nach jeweils 20ms, den neuen Impuls anlegen... 
Warum so kompliziert... Auch wenns nur ein nicht Sinnvolles Program ist 
??
Gerade weils hier auf nix ankommt mal alle Möglichkeiten 
durchspielen....
OP #4295053
Lesenswert?

Also ich habe jetzt, in Assembler, und mit dem Debugger auf genaue 
Taktzahlen geprüft, ein paar Funktionen geschrieben, die einmal 1ms, 
einmal 1.5ms, und einmal 20ms warten.
1
.include "m88def.inc"   
2

3

4
/*
5

6
  Taktfrequenz des MC: 1 MHz
7
*/
8

9
.CSEG 
10

11
// Richtung der IO Ports definieren
12
  LDI R16, 0b11111111    // 1=Output, 0=Input
13
  OUT DDRB, R16
14
  OUT DDRC, R16
15
  OUT DDRD, R16
16

17
// Stackpointer initialisieren
18
  LDI R16, low(RAMEND)
19
  OUT SPL, R16
20
  LDI R16, high(RAMEND)
21
  OUT SPH, R16
22

23
// Timer Einstellung initialisieren
24
  IN R16, TCCR0B
25
  SBR R16, (1<<CS00) | (1<<CS01)  // Prescaler von 64 einstellen
26
  OUT TCCR0B, R16
27

28
// Main Methode
29
  LDI R17, 0x00
30

31
MAIN:
32
  SBI PORTD, PD0  // LED einschalten
33
          // Warten bis 20ms vergangen
34
  RCALL WAIT_1_5_MS  // Braucht 1000 Takte, also 1,000 ms
35

36
  CBI PORTD, PD0  // LED ausschalten
37
          // Warten bis 20ms vergangen
38
  RCALL WAIT_20_MS
39
RJMP MAIN
40

41
WAIT_1_MS:
42
  OUT TCNT0, R17  // Counter resetten
43
  LOOP_1:      // Warten bis Counter abgelaufen
44
    IN R16, TCNT0
45
    CPI R16, 15
46
    BRLO LOOP_1
47

48
  LDI R18, 9
49
  LOOP_2:
50
    DEC R18
51
    CPI R18, 0
52
    BRNE LOOP_2
53

54
  NOP
55
RET
56

57
WAIT_1_5_MS:
58
  OUT TCNT0, R17  // Counter resetten
59
  LOOP_4:      // Warten bis Counter abgelaufen
60
    IN R16, TCNT0
61
    CPI R16, 23
62
    BRLO LOOP_4
63

64
  LDI R18, 6
65
  LOOP_44:
66
    DEC R18
67
    CPI R18, 0
68
    BRNE LOOP_44
69

70
  NOP
71
RET
72

73
WAIT_20_MS:
74
  LDI R19, 20
75
  LOOP_3:
76
    RCALL WAIT_1_MS
77
    DEC R19
78
    CPI R19, 0
79
    BRNE LOOP_3
80
RET

Es funktioniert weiterhin nicht, der Servo dreht nach rechts.

Jetzt muss es definitiv am Servo liegen, denke ich zumindest.

Was meint ihr?
m.f.G.: Developer_X
#4295125
Lesenswert?

A. B. schrieb:

> Was meint ihr?

Nicht so schnell.
Du klingst nicht besonders sicher, was die Taktfrequenz deines µC 
angeht.
Die würde ich mal überprüfen.

Das kannst du ganz einfach machen.
Häng mal eine LED an den Ausgang.

(das F_CPU muss am sinnvollsten VOR die Includes. Du weisst nicht, in 
welcher Form der Wert von dem includierten Teil benutzt wird!)
1
#define F_CPU 1000000UL
2

3
#include <avr/io.h>          
4
#include <util/delay.h>
5

6

7
int main (void) 
8
{            
9
   DDRD  = 0xFF;             
10

11

12
   while(1) 
13
   {               
14
     PORTD = 0b00000001;
15
     _delay_ms( 1000 );
16

17
     PORTD = 0b00000000;
18
     _delay_ms( 1000 );
19
   }  
20
}

LED beobachten.
leuchtet sie 1 Sekunde und ist 1 Sekunde aus?
Die Zeiten brauchst du jetzt nicht mit der Stoppuhr kontrollieren. Denn 
die Alternativen sind nicht so gross. Wenn der µC mit 8Mhz läuft, dann 
leuchtet die LED nur 1/8 Sekunde (und ist 1/8 Sekunden aus). Den 
Unterschied sieht man mit freiem Auge.
#4295531
Lesenswert?

Alternativ den Code aus dem Tutorial stibitzen, der ist zwar nicht 
schön, funktioniert aber. Hab ich auf einem ATmega16 selbst ausprobiert. 
Nur die .include Zeile muß auf den Prozessortyp geändert werden und 
ggfs. der Takt auf 4 MHZ. Für den Funktionstest sollte es reichen.

https://www.mikrocontroller.net/articles/AVR-Tutorial:_Servo#einfache_Servoansteuerung_mittels_Warteschleifen
Gast #4295742
Lesenswert?

Hi,
>Ok. Aber ich glaube der Servo ist trotzdem nicht funktionsfähig, da er
>immerhin auch schon nach Anschluss, sogar wenn Signal ganz auf VCC oder
>ganz auf GND gleich zum Anschlag dreht.

Ist def. weil ein Servo ohne Signal stehen bleibt(sollte).

Viel Erfolg, Uwe

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