Forum: Mikrocontroller und Digitale Elektronik Atmega8 L293D Schrittmotor Code Problem


von Digit-22 N. (digit-22)


Lesenswert?

Hallo und einen schönen Sonttag euch allen.

Bin hier ein bissel am Basteln und möchte mit meinem Atmega8 und einem 
L293D einen Schrittmotor ansteuern.
Hab bei den  ersten tests einfach die Ausgänge des Atmega8 (die an den 
richtigen Eingängen des L293Ds angeschlossen sind) nach folgenden Schema 
geschaltet was auch wunderbar funktioniert hat.
1
      
2
PORTB |= 1<<PB2; PORTB &= ~(1<<PB3); PORTB |= 1<<PB4; PORTB &= ~(1<<PB5);
3
_delay_ms(100);
4
       
5
PORTB &= ~(1<<PB2); PORTB |= 1<<PB3; PORTB |= 1<<PB4; PORTB &= ~(1<<PB5);
6
_delay_ms(100);
7
      
8
PORTB &= ~(1<<PB2); PORTB |= 1<<PB3; PORTB &= ~(1<<PB4); PORTB |= 1<<PB5;
9
_delay_ms(100);
10
      
11
PORTB |= 1<<PB2; PORTB &= ~(1<<PB3); PORTB &= ~(1<<PB4); PORTB |= 1<<PB5;
12
_delay_ms(100);

Nach dem ich mich ein bissel ausgetobt habe, hab ich mich dran gemacht 
und versucht mit einem Rechteck Signal (Takte) den Schrittmotor zum 
laufen zu bringen. Das Problem ist das der Motor total unrund läuft und 
auch keine Power hat wie bei den ersten versuchen. Hier ist mein Ansatz 
vielleicht nicht die eleganteste weise aber bin ja noch am lernen.
1
int takt1 ();
2
int takt2 ();
3
int takt3 ();
4
int takt4 ();
5
6
int main(void)
7
{
8
  DDRB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2) ;
9
  DDRC =  (0<<PC0);
10
11
  takt1();    
12
}
13
14
int takt1(void)
15
{
16
  // PB2        // PB3        // PB4        // PB5
17
PORTB |= 1<<PB2; PORTB &= ~(1<<PB3);  PORTB |= 1<<PB4;  PORTB &= ~(1<<PB5);
18
  while (1)
19
  {  
20
    if (!(PINC & (1<<PINC0)))
21
    {
22
      takt2();
23
    }  
24
  }  
25
}
26
27
int takt2(void)
28
{
29
PORTB &= ~(1<<PB2); PORTB |= 1<<PB3;  PORTB |= 1<<PB4;  PORTB &= ~(1<<PB5);
30
  
31
  while (2)
32
  {
33
    if (!(PINC & (1<<PINC0)))
34
    {
35
      takt3();
36
    }  
37
  }  
38
}
39
40
int takt3(void)
41
{
42
PORTB &= ~(1<<PB2);  PORTB |= 1<<PB3; PORTB &= ~(1<<PB4);  PORTB |= 1<<PB5;
43
  while (3)
44
  {
45
    if (!(PINC & (1<<PINC0)))
46
    {
47
      takt4();
48
    }  
49
  }  
50
}
51
52
int takt4(void)
53
{
54
PORTB |= 1<<PB2; PORTB &= ~(1<<PB3); PORTB &= ~(1<<PB4); PORTB |= 1<<PB5;
55
   while (4)
56
   { 
57
    if (!(PINC & (1<<PINC0)))
58
    {
59
      takt1();
60
    }    
61
   }  
62
}


Über Tipps und eventuelle Vorschläge würde ich mich sehr freuen.

LG

von m.n. (Gast)


Lesenswert?

Wenn ich Dein µC wäre, würde ich mich vermutlich mit Stacküberlauf 
verabschieden.

Mach die Sache doch nicht so kompliziert!
Nimm ein Feld (Tabelle) mit den vier möglichen Zuständen an PortB und 
gib diese Muster nacheinander an PortB aus. Dann dreht sich der Motor je 
nach Takt der Impulsausgabe vor oder zurück.
Den Takt erzeugt man am besten mit einem Timer und die Taktausgabe im 
Timer-Interrupt, wenn Du es verbessern willst.
Fertig.

von Thomas (kosmos)


Lesenswert?

Und vielleicht noch ein Bitmuster für Halbschritte mit reinnehmem.

von cw (Gast)


Lesenswert?

Hallo Shabi N.
schau mal hier http://www.tschallener.net/AVR/schrittmotor.pdf dort ist 
sehr schön erklärt, was die Vorredner meinen.
cw

von Karl H. (kbuchegg)


Lesenswert?

cw schrieb:
> Hallo Shabi N.
> schau mal hier http://www.tschallener.net/AVR/schrittmotor.pdf dort ist
> sehr schön erklärt, was die Vorredner meinen.

Aber bitte nicht so
1
uint8_t vs[4]={9,5,6,10}, //Tabelle Vollschritt Rechtslauf

schreiben.
Man darf das ruhig hier in Bit oder Bitmaskenschreibweise schreiben
1
uint8_t vs[4]={
2
   1 << PB2 | 0 << PB3 | 1 << PB4 | 0 << PB5,
3
   0 << PB2 | 1 << PB3 | 1 << PB4 | 0 << PB5,
4
   0 << PB2 | 1 << PB3 | 0 << PB4 | 1 << PB5,
5
   1 << PB2 | 0 << PB3 | 0 << PB4 | 1 << PB5,
6
};

(die 0 << xx sind natürlich im Grunde sinnlos und dienen nur als 
Platzhalter, dass dieses Bit eben nicht zu setzen ist und um eine schöne 
Tabellenstruktur erhalten zu können)

und natürlich bei der Ausgabe aufs Port entsprechend anpassen.

: Bearbeitet durch User
von Digit-22 N. (digit-22)


Lesenswert?

Hallo

super danke für die Tipps. Ich schau mir mal den Link an und versuche 
mich rein zudenken.

LG
Shabi

von Digit-22 N. (digit-22)


Lesenswert?

so hab mal zum testen etwas geschrieben aber es fuktioniert noch nicht 
so richtig. Hier mal der Code.
1
int main(void)
2
{  
3
  DDRB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2) ;
4
  
5
  int i=0;
6
  uint8_t vs[4]={
7
     (PORTB |= 1<<PB2) | (PORTB &= ~(1<<PB3)) | (PORTB |= 1<<PB4) | (PORTB &= ~(1<<PB5)),
8
     (PORTB &= ~(1<<PB2)) |  (PORTB |= 1<<PB3) |  (PORTB |= 1<<PB4) |  (PORTB &= ~(1<<PB5)),
9
     (PORTB &= ~(1<<PB2)) |  (PORTB |= 1<<PB3) | (PORTB &= ~(1<<PB4)) |  (PORTB |= 1<<PB5),
10
     (PORTB |= 1<<PB2) |  (PORTB &= ~(1<<PB3)) | (PORTB &= ~(1<<PB4)) | (PORTB |= 1<<PB5)
11
  };
12
  
13
    while(i<4)
14
    {
15
    vs[i];
16
    _delay_ms(100);
17
    i++;
18
    if (i==3)
19
    i=0;
20
    }
21
}

irgendwie bleibt der an der 4. stelle (0110) stehen und das wars.
Kann den so ein Feld überhaupt so einen großen wert in einem Feldelement 
speichern?
Sieht jemand einen Denkfehler? Hoffe ich hab es auch richtig verstanden.


lg
shabi

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Shabi N. schrieb:

>   uint8_t vs[4]={
>      (PORTB |= 1<<PB2) | (PORTB &= ~(1<<PB3)) | (PORTB |= 1<<PB4) |

Du kannst doch hier keine Zuweisungen machen!

Da wird eine Variable in Form eines Arrays definiert! EIne Variable hält 
Daten. Zum Beispiel Daten, die man an einen Port ausgeben kann. Aber 
eine Variable enthält keine ausführbare Anweisungen.

Vielleicht doch mal ein C-Buch konsultieren und grundlegende 
Programmkonzepte erst mal erlernen?
1
...
2
3
4
uint8_t vs[4]={
5
   1 << PB2 | 0 << PB3 | 1 << PB4 | 0 << PB5,
6
   0 << PB2 | 1 << PB3 | 1 << PB4 | 0 << PB5,
7
   0 << PB2 | 1 << PB3 | 0 << PB4 | 1 << PB5,
8
   1 << PB2 | 0 << PB3 | 0 << PB4 | 1 << PB5,
9
};
10
11
12
...
13
14
15
   PORTB = vs[i];
16
   i++;
17
   if( i == 4 )
18
     i = 0;
19
20
   _delay_ms( 500 );
21
22
   ....

: Bearbeitet durch User
von Digit-22 N. (digit-22)


Lesenswert?

Achssooooooo  jetzt verstehe ich das.

Ich kann ja gar kein Array ausführen sondern wie du ober geschrieben 
hast mein Datenfeld dem Port zuweisen...

Mann mann bin ich blöd.

Super danke jetzt hab ich es gerafft.



LG
Shabi

von Digit-22 N. (digit-22)


Lesenswert?

So es hat geklappt wenn ich delays reinbaue läuft der Motor perfekt.
Ich hab den Code auch mal auf die Halbschritte erweitert funktioniert 
auch einwandfrei.

Und jetzt kommt das nächste Problem :-).
Ich möchte ja das ganze richtung und Taktgesteuert machen.
Hab jetzt mal etwas rum probiert und bekomme mit dem neuen Code auch das 
gleiche Problem das der Motor unrund läuft und keine Power hat. Der 
läuft noch nicht mal in einer Richtung sondern macht was er will.

Das ist mein aktueller Code:
1
int main(void)
2
{ int i=0;
3
  DDRB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2) ;
4
  DDRC =  (0<<PC0);
5
  uint8_t vs[8]=
6
  {
7
    1 << PB2 | 0 << PB3 | 0 << PB4 | 1 << PB5,
8
    0 << PB2 | 0 << PB3 | 0 << PB4 | 1 << PB5,
9
    0 << PB2 | 1 << PB3 | 0 << PB4 | 1 << PB5,
10
    0 << PB2 | 1 << PB3 | 0 << PB4 | 0 << PB5,
11
    0 << PB2 | 1 << PB3 | 1 << PB4 | 0 << PB5,
12
    0 << PB2 | 0 << PB3 | 1 << PB4 | 0 << PB5,    
13
    1 << PB2 | 0 << PB3 | 1 << PB4 | 0 << PB5,
14
    1 << PB2 | 0 << PB3 | 0 << PB4 | 0 << PB5,  
15
  };
16
  
17
    while(1)
18
    {  PORTB = vs[i];
19
     if (PINC & (1<<PINC0))
20
        {
21
          i++;  
22
  }    
23
    if( i == 8 )
24
    i = 0;
25
    }
26
}


Hier "if (PINC & (1<<PINC0))" möchte ich sagen wenn PC0 == 1 dann i++.
Und irgendwie scheint das Problem genau da zu liegen.

Hab schon alles was mir so einfällt probiert komme aber nicht drauf was 
das Problem sein könnte.


LG

von Karl H. (kbuchegg)


Lesenswert?

Shabi N. schrieb:

>     while(1)
>     {  PORTB = vs[i];
>      if (PINC & (1<<PINC0))
>         {
>           i++;
>   }
>     if( i == 8 )
>     i = 0;
>     }

zu schnell.
Viel zu schnell!
Da kommt kein Motor mehr mit.

> Hier "if (PINC & (1<<PINC0))" möchte ich sagen wenn PC0 == 1 dann i++.
> Und irgendwie scheint das Problem genau da zu liegen.

Nein.
Dein Problem ist, dass dein Motor nicht alle 0.0000001 Sekunden einen 
Schritt machen kann. Schon gar nicht aus dem Stand heraus. Ein bischen 
mehr Realismus!

: Bearbeitet durch User
von Digit-22 N. (digit-22)


Lesenswert?

AAAh das heißt ich müsste noch ein kleines päusschen einbauen?
Mom teste es gerade.

von Bernhard S. (b_spitzer)


Lesenswert?

PC0 soll hier wohl ein Takt_EINGANG_ darstellen. Dann mach Dich mal zum 
Thema Flankenerkennung schlau. Bei Dir rauscht die if-Abfrage nur so 
durch, weil der Takt ja längere Zeit (für den Controller eine gefühlte 
Ewigkeit) auf 1 sein wird.

von Digit-22 N. (digit-22)


Lesenswert?

hallo

Ja genau das Problem habe ich gerade. ich hab mal ein delay eingebaut. 
Der Motor dreht wunderbar und mit dem delay wert kann ich die Drehzahl 
festlegen. Allerdings möchte ich ja wie du schon bemerkt hast das ganze 
Taktgesteuert machen.
So wie es aktuell ist, dreht der Motor sich so lange ich den taster 
gedrückt halte.

Flanken auswerten   dann brauch ich bestimt timer.
Ich muss noch hinzu sagen das ich das ganze auch gern erweitern würde 
und eine kleine 3Achs steuerung basteln will.

Ich brauch in prinziep pro achse 2 Eingänge und 4 Ausgänge.
Rein rechnerich gesehen würde der  Atmega ja reichen. Ist nur die Frage 
ob ich die Ports so nutzen kann.

von Wolfgang (Gast)


Lesenswert?

Karl Heinz schrieb:
> und natürlich bei der Ausgabe aufs Port entsprechend anpassen.

Ob in den über Oder-Verknüpfungen erzeugten Bitmustern nun PBx, PCx oder 
sonst irgendein Portname auftaucht, ist doch völlig Schnuppe. 
Entscheidend ist einzig und alleine die Bitnummer.

von Karl H. (kbuchegg)


Lesenswert?

Wolfgang schrieb:
> Karl Heinz schrieb:
>> und natürlich bei der Ausgabe aufs Port entsprechend anpassen.
>
> Ob in den über Oder-Verknüpfungen erzeugten Bitmustern nun PBx, PCx oder
> sonst irgendein Portname auftaucht, ist doch völlig Schnuppe.
> Entscheidend ist einzig und alleine die Bitnummer.

Ja.
Trotzdem verändert man keine Bits, an denen nichts hängt.
1
  PORTB = vs[i];

ist ein Rundumschlag an allen Port-Bits.
Ich weiß nicht, wie du das siehst. Aber für mich ist das nicht 
akzeptabel.

von Karl H. (kbuchegg)


Lesenswert?

Shabi N. schrieb:

> festlegen. Allerdings möchte ich ja wie du schon bemerkt hast das ganze
> Taktgesteuert machen.

Saublöde Frage.
Waru verwendest du dann nicht gleich einen Schrittmotorcontroller?
Der kann das alles perfekt.

> So wie es aktuell ist, dreht der Motor sich so lange ich den taster
> gedrückt halte.
>
> Flanken auswerten   dann brauch ich bestimt timer.

Kommt drauf an. Wenn das EIngangssignal nicht prellt brauchst du keinen 
Timer. Du brauchst nur eine Flankenerkennung.

von Digit-22 N. (digit-22)


Lesenswert?

@ Karl Heinz

Weil die Schrittmotorcontroller z.b. L297  nur einen Schrittmotor 
betreiben können. Mein Ziel ist es einen Atmega und 3 L293D  um eine 
kleine 3achs Steuerung zu bauen.

Das Signal was dann rein kommt (Also die Flanken) ist ein reines 
Rechtecksignal was z.b. in der CNC (EMC² oder Mach3...) verwendet wird.

Die Frequenz des taktes bestimmt die drehzahl des Motors.
Und Richtungswechsel wird dann mit H oder L  realisiert.
Das ist aber erstmal nicht wichtig. zuerst muss die Steuerung einfach 
nur laufen.

von Karl H. (kbuchegg)


Lesenswert?

Shabi N. schrieb:

> Weil die Schrittmotorcontroller z.b. L297  nur einen Schrittmotor
> betreiben können.

Hätte halt den Vorteil, dass es schon längst laufen würde.
Aber ok. Wer weiß wozu es gut ist.

> Das Signal was dann rein kommt (Also die Flanken) ist ein reines
> Rechtecksignal was z.b. in der CNC (EMC² oder Mach3...) verwendet wird.

Na dann.
Flanken erkennung und die Chose ist gegessen.

Eine Flanke liegt dann vor, wenn in der while Schleife der aktuell 
festgestellte Pegel sich vom Pegel im letzten Durchlauf der while 
Schleife unterscheidet.
(Ist um Grunde ganz einfach. Wenn du alle 10 Sekunden beim Fenster 
raussiehst und im Nachbarhaus brennt kein Licht, dann hat sich nichts 
getan. Siehst du aber raus und plötzlich brennt das Licht, welches 10 
Sekunden zuvor noch nicht gebrannt hat, dann hat offenbar in der 
Zwischenzeit wer eingeschaltet. Siehst du 10 Sekunden später wieder raus 
und das Licht brennt noch immer, dann hat sich offenbar wieder nichts 
getan. Du vergleichst also einfach: brennt das Licht jetzt und wie war 
das vor 10 Sekunden? Immer schön vergleichen - dich interessiert nur, ob 
alles gleich bleibt oder ob sich was verändert hat)
1
...
2
3
uint8_t Pegel, PegelAlt;
4
5
...
6
7
8
  PegelAlt = ( PIND & ( 1 << PD1 ) );
9
10
  while( 1 )
11
  {
12
    Pegel = ( PIND & ( 1 << PD1 ) );
13
14
    if( Pegel != PegelAlt )     // Hoppla, da hat sich was getan
15
                                // der Pin hat nicht mehr den Zustand von
16
                                // vorher
17
    {
18
      if( Pegel )               // wie hat er sich denn verändert? Wenn er jetzt
19
                                // auf High ist, dann wars eine steigende Flanke
20
      {
21
        if( PIND & ( 1 << PD0 ) )   // welche Drehrichtung?
22
        {
23
          StepNr++;                 // ein Schritt vorwärts
24
          if( StepNr == 8 )
25
            StepNr = 0;
26
        }
27
        else
28
        {
29
          StepNr--;                 // ein Schritt zurück
30
          if( StepNr == -1 )
31
            StepNr = 7;
32
        }
33
34
        PORTB = vs[StepNr];         // uuuuund .... machen!
35
      }
36
37
      PegelAlt = Pegel;
38
    }
39
  }
40
}

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

HI

>Weil die Schrittmotorcontroller z.b. L297  nur einen Schrittmotor
>betreiben können. Mein Ziel ist es einen Atmega und 3 L293D  um eine
>kleine 3achs Steuerung zu bauen.

Mit einem L293 kannst du aber nicht annähernd die Leistung aus deinen 
Schrittmotoren herausholen, die möglich ist. Dazu muss der Motor im 
Chopperbetrieb gefahren werden. Also mit konstantem Strom und nicht mit 
konstanter Spannung. Und dazu ist z.B. ein L297 da.

MfG Spess

von m.n. (Gast)


Lesenswert?

spess53 schrieb:
> Und dazu ist z.B. ein L297 da.

Nur treibt dieser keine Motore direkt an. Man müßte schon mindestens 
einen L293D dahinterschalten :-)

Zum Lernen ist die Kombination ATmega+L283 doch gut geeignet und reicht 
für niedrige Drehzahlen und Kräfte auch aus. Außerdem weiß man später 
ganz genau, warum man es nicht mehr machen wird/will/sollte.

von spess53 (Gast)


Lesenswert?

Hi

>Nur treibt dieser keine Motore direkt an.

Ist mir schon längere Zeit bekannt.

>Man müßte schon mindestens einen L293D dahinterschalten :-)

Wenn schon, dann einen L293E. Der hat als einziger L293 
Sense-Anschlüsse.

Für halbwegs ernsthafte Schrittmotoransteuerung ist der L293 die denkbar 
ungünstigste Wahl.

Für kleinere Schrittmotoren (bis 750mA) würde ich den L6219 empfehlen. 
Der hat die Choppersteuerung schon on Board und ist auch für Halbschritt 
geeignet.

MfG Spess

von m.n. (Gast)


Lesenswert?

Du weißt aber auch, dass hier Sparfüchse unterwegs sind und sich dann 
ggf. für solch einen Motor entscheiden: 
http://www.pollin.de/shop/dt/NjQ1OTg2OTk-/Motoren/Schrittmotoren/Schrittmotor_PSM42BYGHW603_1_8_.html

Da nutzt kein so so ausgefeilter Mikroschritt-Treiber, um ihn auf Trab 
zu bringen.

spess53 schrieb:
> Für kleinere Schrittmotoren (bis 750mA) würde ich den L6219 empfehlen.

Da stimme ich zu, wenn der Motor einen kleinen Wicklungswiderstand hat 
und mit Konstantstrom betrieben wird!

von Digit-22 N. (digit-22)


Lesenswert?

Hallo leute

@Karl Heinz

Super danke dir für die Hilfe. Hab deinen Code mal getestet. Der Motor 
dreht sich und wenn ich PD1 an meinem Frequenzgenerator anschließe läuft 
der Motor, aber noch niht ganz sauber. Under der Eingang ist extrem 
empfindlich. Das heißt wenn der eingang z.b. offen ist und ich komme mit 
den fingern nur in die nähe des Einganges, spielt der Motor verrückt. 
:-)
Werde noch ein bissel rum probieren...


@ spess53

Ja das weiß ich. Ich benutze ja auch nur mini Schrittmotoren aus DVD 
Laufwerken. Daher reicht die Leistung vollkommen aus.



Danke an alle.

LG

von m.n. (Gast)


Lesenswert?

Shabi N. schrieb:
> Under der Eingang ist extrem
> empfindlich.

Bei potentiell offenen Eingängen immer die Pullup-Widerstände 
aktivieren!

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.