Servo ansteuern mit ATMega16

Gast #709066
Lesenswert?

Hallo Leute!
Ich würde gerne einen/mehrere Servo(s) ansteuern. Also habe ich mir 
einen kleinen Code zusammengebastelt:
1
#define F_CPU 16000000L
2

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

6
unsigned char i;
7

8
int main()
9
{
10
  DDRA = 0xFF;
11
  PORTA = 0x00;
12
  while(1)
13
  {
14
    for(i=0; i<150; i++)
15
    {
16
      PORTA = 0xFF;
17
      _delay_us(2000);
18
      PORTA = 0x00;
19
      _delay_ms(18);
20
    }
21
    for(i=0; i<150; i++)
22
    {
23
      PORTA = 0xFF;
24
      _delay_us(1000);
25
      PORTA = 0x00;
26
      _delay_ms(19);
27
    }
28
  }
29

30
  while(1);
31
  return 0;
32
}
Dazu habe ich den Servo dann angeschlossen, also das schwarze Kabel an 
Minus, das Rote an Plus und das letzte an irgendeinen Pin von Port A.

Eigentlich sollte das Servovieh immer schön hin und her drehen, oder?

Und wie ihr euch schon denken könnt: Es funktioniert nicht. Ein Servo 
dreht sturr nach links und ein anderes Modell tut garnichts. Ich habe 
absolut keine Ahnung, wo der Fehler liegt? Ist was in meinem Code 
falsch?

Also mit der Frequenz sollte eigentlich alles stimmen...
Habt ihr eine Antwort?
Vielen Dank schonmal, PowerProgrammer
Gast #709094
Lesenswert?

Oh, vielen Dank!
Vorher hatte ich das aber auch mit _delay_ms(1); und _delay_ms(2); 
gemacht, es hatte trotzdem nicht geklappt. Naja, das wäre hier jetzt ein 
zusätzlicher Bug, danke für den Hinweis!

Weiß denn jemand, was noch falsch sein könnte?
Gast #709100
Lesenswert?

Hi PowerProgrammer,

die Servos erwarten folgendes "Protokoll":
 [Stellimpuls][Warteimpuls]

 Von Impuls zu Impuls 22,5ms
 Stellimpuls + Warteimpuls = 22,5ms
 Für die Position 0 ist der Stellimpuls 0,7ms
 für die Position voll Ausschlag 2ms


1
    while(1)
2
    {
3
      PORTA = 0xFF;
4
      _delay_us(2000);
5
      PORTA = 0x00;
6
      _delay_ms(20);
7
      PORTA = 0xFF;
8
      _delay_us(700);
9
      PORTA = 0x00;
10
      _delay_ms(21);
11

12
    }

Der Code hat zumindest bei mir funktioniert.
Habs nacher mit einem Timer gelöst. Das ist nicht ganz so CPU lastig

Gruß Marcus
Gast #709108
Lesenswert?

Hmm, ich hatte gelesen, dass die Summe aus Stellimpuls und Wartezeit 
nicht exakt sein muss und zwischen 10 und 20 ms liegen soll.
Jedenfalls kann dein Code nach der Anmerkung thorstens nicht 
funktinieren, wenn er das bei dir dennoch tat, dann ist das höchst 
seltsam. Nach deinem Code wechselt das Teil ja alle 22,5 ms die 
Stellung, das schafft kein Servo, also, ich werde den Code bei 
gelegenheit mal ausprobieren, wenn er klappt, fresse ich nen Besen. 
Danke.
Gast #709123
Lesenswert?

Hallo PowerProgrammer,

ups, da ist mir wirklich ein kleiner Fehler unterlaufen. Hab aus meinem 
Code das ein oder andere rausgeschnippelt und leider auch eine falsche 
Zeile!
1
    while(1)
2
    {
3
      int i = 0;
4
      while (i < 200) {
5
         PORTA = 0xFF;
6
         _delay_us(2000);
7
         PORTA = 0x00;
8
         _delay_ms(20);
9
         i++;
10
      }    
11
      while (i < 200) {
12
         PORTA = 0xFF;
13
         _delay_us(700);
14
         PORTA = 0x00;
15
         _delay_ms(21);
16
      }
17

18
    }

Das Servo sollte so alle 4 Sekunden einal von ganz rechts nach ganz 
links wandern. Die Standartservos brauchen da so ihre Zeit.

Gruß Marcus
Gast #709124
Lesenswert?

Hallo PowerProgrammer,

ups, da ist mir wirklich ein kleiner Fehler unterlaufen. Hab aus meinem
Code das ein oder andere rausgeschnippelt und leider auch eine falsche
Zeile!

    while(1)
    {
      int i = 0;
      while (i < 200) {
         PORTA = 0xFF;
         _delay_us(2000);
         PORTA = 0x00;
         _delay_ms(20);
         i++;
      }
      i = 0;
      while (i < 200) {
         PORTA = 0xFF;
         _delay_us(700);
         PORTA = 0x00;
         _delay_ms(21);
         i++
      }
      i = 0;
    }

Das Servo sollte so alle 4 Sekunden einal von ganz rechts nach ganz
links wandern. Die Standartservos brauchen da so ihre Zeit.

Gruß Marcus
Gast #710263
Lesenswert?

Danke, es geht mir halt drum, erstmal einen verfluchten Servo irgendwie 
zu bewegen, egal wie dreckig der Code ist;) Ich bin halt neu in der 
Branche und habe so Sachen wie Timer und Interrupts und alles beim AVR 
noch nie genutzt, ich kenne bis jetzt halt nur die Intel-x86-Prozessoren 
genauer...
Ich verzweifel an diesen Teilen sowieso, ich weiß nicht, wieso die Teile 
mich nicht mögen. Wüsste nur zu gerne, wie ich am besten mal die Signale 
meines AVRs unter die Lupe nehmen könnte...

PowerProgrammer
#710355
Lesenswert?

>wie ich am besten mal die Signale meines AVRs unter die Lupe nehmen >könnte...

Für sowas benutzt man in der Regel ein Oszilloskop.

Würdestr du die Suche des Forums bemühen, würdest du auch diverse 
Lösungen mit Timern finden.

Fluchen bringt übrigens bei Servos (und anderen Dingen) überhaupt 
nichts, sowas hilft höchstens bei anderen Menschen...
Gast #710968
Lesenswert?

Ein wirklich gut gemeinter Ratschlag, allerdings doch etwas 
unverständlich für einen Anfänger, der schon bei 2 Delay-Anweisungen 
verzweifelt;) Ich dachte mir halt wirklich, Timer erst einzubauen, wenn 
der Servo überhaupt erstmal irgendiwie funktioniert!
Trotzdem nochmal vielen Dank an all die Leute, die mir geholfen haben!
PowerProgrammer
Gast #710979
Lesenswert?

ok Jungs, jetzt sag ich euch mal wie das geht! mit folgender methode 
kannst du ganz elegeant 2 servos ansteuern!
du benutzt fast PWM und setzt ICR als TOP! das machst du so WGM1n=1110, 
siehe dazu datenblatt S.112! den timer musst du noch ein wenig 
prescalen, damit du genau nach 22.5ms den wert in ICR erreichst! nun 
stellst du noch OCR1n so ein dass bei einem compare match das pwm signal 
gelöscht wird! jetzt gibt es ja aber ein minimum und  maximum deines pwm 
signals, d.h das minimum ist ja glaub ich bei 1ms und das maximum bei 
2ms oder so! dazu berechnest du einfach den zählerstand des timers der 
bei diesen werten! um OCR1n zu setzen nimmst du dann 
OCR1n=Minimum+(Maximum-Minimum)/Auflösung*Wert
alles klar?
Gast #710982
Lesenswert?

hier noch der code (für einen ATmega128),hoffe der stimmt so noch, aber 
sonst werden es nur kleinigkeiten sein:

#include <stdlib.h>
#include <avr/io.h>

#define F_CPU 14745600 // clock
#define PRESCALE_FACTOR 8 // prescale factor 8
#define PRESCALE_FACT (1<<CS11)
#define PULSE_PERIOD 50 //50Hz->20ms
#define MAXPULS_FREQ 500 // 500Hz -> 2ms
#define MINPULS_PRESC 2 //MinPuls ist 2 mal kleiner als MaxPuls
#define MAXTIMER_VALUE F_CPU/(MAXPULS_FREQ*PRESCALE_FACTOR)
#define MINTIMER_VALUE 
F_CPU/(MAXPULS_FREQ*MINPULS_PRESC*PRESCALE_FACTOR)
#define TIMER_VALUE  F_CPU/(PRESCALE_FACTOR*PULSE_PERIOD)

void init(){
DDRB|=(1<<PB5); // set PB5 (OC1A) to output
/***fast pwm mode***/
TCCR1A|=(1<<COM1A1); // clear OCnx on compare match
TCCR1A|=(1<<WGM11);
TCCR1B|=((1<<WGM13)|(1<<WGM12));
ICR1H|=TIMER_VALUE;
TCCR1B|= PRESCALE_FACT;// timer prescaling
}

//speed Werte 0-255 erlaubt
void setMotorSpeed(unsigned char speed){
OCR1A=MINTIMER_VALUE+(MAXTIMER_VALUE-MINTIMER_VALUE)/255*speed;
}

int main(void){
init();
setMotorSpeed(128);
while(1);
return 0;
}
Gast #2048112
Lesenswert?

Hi,

ich werd den alten Thread ma vorkramen, da ich ein ähnliches bzw. das 
gleiche problem hab. Ich hab hier zwei Servos, der eine ohne 
Potirückmeldung und der andere mit Rückmeldung.

Dazu hab ich den folgenden Quellcode, denn ich aus dem Tutorial von hier 
habe. Allerdings laufen beide servos immer nur nach links, auch wenn ich 
die Delay-Zeit ändere!

Kann mir jemand helfen!!
Danke!
1
#include <avr/io.h>
2
#define F_CPU 1000000L
3
#include <util/delay.h>
4

5

6
int main (void)
7
{
8

9
  DDRB |= (1<<PB2);
10
  
11

12
    while(1)
13
    {
14
  PORTB |= (1<<PB2);
15
    _delay_ms(2);
16
    PORTB &= ~(1<<PB2);
17
    _delay_ms(18);
18
    }
19
    
20

21

22
return 0;
23
}

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