PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Servo in Mittelstellung Bring



manhunt
29.04.2008, 16:10
Hallo

Ich hätte eine Frage wie schaffe ich es einen Servo der Make HiTec Hs-311 in die Mittelpostition zu bringen.

Ich habe es schon mit Folgendem Code Probiert. Wobei mein Servo auf dem PORT D Pin 3 liegt.


Ist es möglich das Folgender Code mit meinem Atmega8 nicht möglich ist?

Denn code habe ich von https://www.roboternetz.de/wissen/index.php/Servos


#define F_CPU 3686400
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#define SERVOPIN 3
#define SERVOPORT PORTD
#define DDRSERVO DDRD

volatile unsigned char servopos;

void servo_init()
{
TIMSK|=(1<<OCIE2);
TCCR2 |= (1<<WGM21) | (1<<CS20);
OCR2 = F_CPU/100000;
DDRSERVO|=(1<<SERVOPIN);
};

ISR(TIMER2_COMP_vect)
{
static int count;
if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
else SERVOPORT|=(1<<SERVOPIN);
if(count<2000+servopos)count++;
else count=0;
};


int main(void) {

servo_init();
sei();


servopos = 150;
while(1);


cli();

return 0;
}


Hoffe ihr könnt mir helfen.

lg manhunt

radbruch
29.04.2008, 19:43
Hallo

Mein asuro (mit 8MHz-Mega8) kann es mit deinem minimal veränderten Code:


#include <avr/io.h>
//#include <avr/delay.h>
#include <avr/interrupt.h>

#define SERVOPIN 4 // Pin6
#define SERVOPORT PORTD
#define DDRSERVO DDRD

uint8_t servopos=150;
volatile uint16_t p=0;

void pause(uint16_t p_dauer)
{
p=p_dauer;
while(p);
}

int main(void)
{
TIMSK|=(1<<OCIE2);
TCCR2 = (1<<WGM21) | (1<<CS20);
OCR2 = 80; // Für 8MHz-Takt, 37 für 3686400Hz
DDRSERVO|=(1<<SERVOPIN);
sei();

while(1)
{
pause(100);
servopos=100;
pause(50);
servopos=200;
pause(50);
servopos=150;
}
return(0);
}

ISR(TIMER2_COMP_vect)
{
static uint16_t count=1;
if(count>servopos) SERVOPORT&=~(1<<SERVOPIN); else SERVOPORT|=(1<<SERVOPIN);
if(count<2000)count++; else { count=1; if(p) p--; }
}

Das hat bei mir erst funktioniert nachdem ich das TCCR2-Register direkt gesetzt hatte (ohne |) (Es kann aber auch sein, das bei meinen ersten Tests die asuro-Lib störte)

Die Positionen stimmen nicht wirklich, aber immerhin bewegt sich was:

http://i.ytimg.com/vi/VNbpkGiD-YI/2.jpg (http://www.youtube.com/watch?v=VNbpkGiD-YI)
http://www.youtube.com/watch?v=VNbpkGiD-YI

Hinweis für asuro-Besitzer: Der verwendete Pin6 (PORTD4) ist beim orginalen asuro belegt, also nicht ohne Anpassung verwenden!

Gruß

mic

manhunt
29.04.2008, 21:13
Hallo

Danke, dein Programm bewegt meinen Servo.

EDIT:

Ich bin ein id**t, mein Programm funktioniert auch aber, ich habe vergessen Servo_init aufzurufen!!!

irgendwie könnte ich mich dafür selbst eine runter hauen.

Ich habe jetzt herum Probiert und festgestellt das der Servo ab 15 zuckt das heißt 16 ist der Linkeanschlag und Rechts zuckt er ab 79 das heißt dann wohl 78 ist der Rechteanschlag.

Ist nun 48 genau die Mitte des Servos?

Und warum ist es nicht 150 == 1.5ms wie im Wiki zu Servo beschrieben?



lg manhunt

radbruch
01.05.2008, 22:04
irgendwie könnte ich mich dafür selbst eine runter hauen.
*lol* (Das hatte ich auch übersehen weil ich mich gleich auf die Timerinitialisierung gestürzt hatte)


Ist nun 48 genau die Mitte des Servos?
Mit den üblichen Angaben für die Impulslängen komme ich auch nicht zurecht. Das liegt an der Frequenz mit der die ISR aufgerufen wird. Welchen Wert lädst du nun in OCR2?

manhunt
02.05.2008, 09:14
Hallo

Am code selber habe ich nichts verändert. Das heißt "OCR2 = F_CPU/100000;"

lg manhunt

radbruch
02.05.2008, 15:46
Hallo

Möglicherweise ist die ISR zu lang und die Interrupts laufen über. Ich habe die Ausführungszeit noch nicht genau berechnet, aber so grob über den Daumen gepeilt dürfte das knapp werden. Es sind 24 Befehle in der ISR + je 9 fürs sichern und restaurieren der Register. Selbst wenn jeder Befehl nur einen Takt benötigen würde, es würde nicht reichen. Die Interrupts kommen bei prescaler=1 alle 36 Takte:



45 .global __vector_4
47 __vector_4:
48 .LFB3:
49 .LM6:
50 /* prologue: frame size=0 */
51 0014 1F92 push __zero_reg__
52 0016 0F92 push __tmp_reg__
53 0018 0FB6 in __tmp_reg__,__SREG__
54 001a 0F92 push __tmp_reg__
55 001c 1124 clr __zero_reg__
56 001e 2F93 push r18
57 0020 3F93 push r19
58 0022 8F93 push r24
59 0024 9F93 push r25
60 /* prologue end (size=9) */
61 .LM7:
62 0026 8091 0000 lds r24,servopos
63 002a 9927 clr r25
64 002c 2091 0000 lds r18,count.0
65 0030 3091 0000 lds r19,(count.0)+1
66 0034 8217 cp r24,r18
67 0036 9307 cpc r25,r19
68 0038 14F4 brge .L3
69 .LM8:
70 003a 9398 cbi 50-0x20,3
71 003c 01C0 rjmp .L4
72 .L3:
73 .LM9:
74 003e 939A sbi 50-0x20,3
75 .L4:
76 .LM10:
77 0040 8091 0000 lds r24,servopos
78 0044 9927 clr r25
79 0046 8053 subi r24,lo8(-(2000))
80 0048 984F sbci r25,hi8(-(2000))
81 004a 2817 cp r18,r24
82 004c 3907 cpc r19,r25
83 004e 3CF4 brge .L5
84 0050 2F5F subi r18,lo8(-(1))
85 0052 3F4F sbci r19,hi8(-(1))
86 0054 3093 0000 sts (count.0)+1,r19
87 0058 2093 0000 sts count.0,r18
88 005c 04C0 rjmp .L2
89 .L5:
90 .LM11:
91 005e 1092 0000 sts (count.0)+1,__zero_reg__
92 0062 1092 0000 sts count.0,__zero_reg__
93 .L2:
94 /* epilogue: frame size=0 */
95 0066 9F91 pop r25
96 0068 8F91 pop r24
97 006a 3F91 pop r19
98 006c 2F91 pop r18
99 006e 0F90 pop __tmp_reg__
100 0070 0FBE out __SREG__,__tmp_reg__
101 0072 0F90 pop __tmp_reg__
102 0074 1F90 pop __zero_reg__
103 0076 1895 reti
104 /* epilogue end (size=9) */
105 /* function __vector_4 size 50 (32) */


Mögliche Lösungen: Schnellerer Kontrollertakt, ISR in Assembler schreiben oder weniger Interrupts pro Zeit (z.B.: OCR2 = F_CPU/50000;) Dann wird zwar die Auflösung geringer und die Werte für die Positionen müssen halbiert werden, aber dafür stimmen dann die Wiederholungen.

Gruß

mic

manhunt
05.05.2008, 17:07
Hallo

Trotz verringerter OCR2 = F_CPU/50000 verändern sich die Start und END Werte von 16 bis 78 nicht am Servo.

Mittlerweile habe ich einen zweiten Servo der Marke Zebra ZS-S2113 benutzt und dort auch die selben Werte minimal verändert erhalten (17 bis 77)

Gibts noch andere Ideen oder ist das doch normal?

lg manhunt

radbruch
05.05.2008, 18:07
Hallo

Bist du sicher dass dein Mega8 mit 3686400Hz rennt?

Gruß

mic

manhunt
05.05.2008, 18:58
Hallo

Sicher bin ich mir nicht auf jedenfall ist ein Quarz mit der Aufschrift 3.6864 drann.

Allerdings weiß ich net ob der Aktiv ist.

gibts da irgend nen Test?

lg manhunt

radbruch
05.05.2008, 20:51
Hallo

Mit den externen Takten habe ich noch keine Erfahrungen gemacht. Im Datenblatt des Mega8 steht:

The device is
shipped with CKSEL = “0001” and SUT = “10” (1 MHz Internal RC Oscillator, slowly rising
power).
Also taktet er defaultmässig mit 1MHz. Wenn er nicht den "Quarz" beachtet müsste der Teiler für OCR2 10 sein (1000000/100000). Dann wären die Servo-Werte im Bereich von ca. 50-200, aber nur 10 Takte Zeit für die ISR. Bei OCR2=100 (10kHz) müssten die Werte von ca. 5-20 sein mit 100 Takten für die ISR. Das könnte funktionieren, wenigsten testweise um festzustellen, welcher Takt verwendet wird. Man könnte natürlich auch die Parametrierung des Takts überprüfen wenn man das kann. btw. muss der Überlauf für count bei 10kHz auf 200 geändert werden.

Gruß

mic

manhunt
05.05.2008, 21:32
Hallo

leider ob OCR2 auf 10 oder 100 ist macht keinen Unterschied. Immer bin ich im Bereich von 16 - 78 servo pos.
lg

radbruch
05.05.2008, 22:20
Weches Verhalten hat meine Programmversion wenn du dort OCR2 änderst? Wie sieht denn dein aktuelles Programm aus? Fehler beim Kompilieren/Übertragen ausgeschlossen? Verify?

Noch was ist mir aufgefallen: In delay.h steht folgendes:

/** \defgroup util_delay <util/delay.h>: Busy-wait delay loops
\code
//#define F_CPU 1000000UL // 1 MHz
//#define F_CPU 14.7456E6
#define F_CPU 8000000UL // 8 MHz
#include <util/delay.h>
\endcode

Keine Ahnung was das genau bedeutet, aber meine Version läuft ohne delay.h!

pongi
06.05.2008, 08:00
Welche Takte verwendet werden könnte auch durch das Auslesen der Fusebits festgestellt werden. Näheres dazu hier: http://www.mikrocontroller.net/articles/AVR_Fuses#Taktquellen_Fuse_Einstellung

Damit delay.h ordentlich funktioniert, muss die Taktrate mit #define F_CPU definiert werden. Bei 1Mhz ist die max Verzögerung was man mit _delay_ms() erreichen kann 255ms, bei höheren Frequenzen entsprechend weniger, da immer der gleiche Zähler verwendet wird.

Also für kritische delays lieber Timer nehmen, oder selber eine Rutine schreiben...

manhunt
06.05.2008, 16:37
Hallo

Ich benutze auch keine Delay funktionen, nur die Header-Dateien sind eingebunden haben damit aber überhaupt nichts zutun.

Den Quellcode den ich verwende findet ihr ganz oben.

lg manhunt

manhunt
08.05.2008, 20:26
Hallo

Ich habe jetzt den Quarz ausgetauscht und einen 16mhz verbaut. Nun hat der Interrupt genug Zeit um abgearbeitet zu werden. Jetzt stimmen auch die Timerzeiten und die daraus resultierenden, servopos werte.

Danke an alle für die Hilfe.

lg manhunt