Forum: Mikrocontroller und Digitale Elektronik Motor steuern mit DDS Prinzip (direct digital synthesis)


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Fabian (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebe Gemeinde,

Ich lerne momentan DDS principle (direct digital synthesis).

Ich möchte das Prinzip benutzen um einen Motor zu steuern.

Auf der Texas Instrument Seite habe ich einen Code gefunden, der DDS 
Prinzip benutzt hat. Der Code läuft Supper und werden zwei PWM Signale 
erzeugt und um 90° von einander verschoben und das sind die 
Voraussetzungen um den Motor drehen zu können.

Ich habe der Code verstanden aber nur bis der Timer Interrupt, da 
verstehe ich leider nicht mehr, was da passiert. Die Datei ist 
eingefügt. siehe Bitte (stepper.c)

Könnte jemand mir bitte das erklären, wie das wirklich funktioniert? wie 
geschieht die 90° Verschiebung? . Oder was tut genau die Funktion im 
Interrupt? wird der DAC des µC benutzt? ich benutze msp430g2553
der Code:

/*
 * stepper.c
 *
 *
 */

#include <msp430.h>
#include "stepper.h"

/* Bit number of PORT2 where APH pin is connected*/
#define STEPPER_APH    (1)
/* Bit number of PORT2 where BPH pin is connected*/
#define STEPPER_BPH    (4)
/* Bit number of PORT2 where AEN pin is connected*/
#define STEPPER_AEN    (0)
/* Bit number of PORT2 where BEN pin is connected*/
#define STEPPER_BEN    (3)




/* graycode pattern to drive the stepper motor */
static const uint8_t s_step_pattern[4] = {  (1<<STEPPER_APH) | 
(0<<STEPPER_BPH),
                      (1<<STEPPER_APH) | (1<<STEPPER_BPH),
                      (0<<STEPPER_APH) | (1<<STEPPER_BPH),
                      (0<<STEPPER_APH) | (0<<STEPPER_BPH)   };

static volatile uint16_t s_stepper_phaseaccumulator = 0;
static volatile uint16_t s_stepper_phaseadder       = 0;
static volatile uint32_t s_stepper_position         = 0;
static            int8_t s_stepper_direction        = 1; /* +1 = CW, -1 
= CCW*/
static volatile uint32_t s_stepper_count            = 0;





void stepper_init(void)
{
  TACTL = TASSEL_2 + MC_1 + TAIE;           // SMCLK, contmode, 
interrupt
  TACCR0 = 100-1;                  // setup timer overflow every 100us
    _BIS_SR(GIE);                             // Enter LPM0 w/ interrupt

    /* set all stepper control pins to output and low*/
    P2OUT = P2OUT & ~((1<<STEPPER_AEN) | (1<<STEPPER_BEN) | 
(1<<STEPPER_APH) | (1<<STEPPER_BPH));
  P2DIR |= (1<<STEPPER_AEN) | (1<<STEPPER_BEN) | (1<<STEPPER_APH) | 
(1<<STEPPER_BPH);
}


void stepper_driver_off(void)
{
    P2OUT = P2OUT & ~((1<<STEPPER_AEN) | (1<<STEPPER_BEN));
}


void stepper_driver_on(void)
{
    P2OUT = P2OUT | ((1<<STEPPER_AEN) | (1<<STEPPER_BEN));
}


void stepper_rotate(int32_t count, uint16_t speed)
{
  stepper_driver_on();

  if (count > 0)
    s_stepper_direction =  1;
  else
  {
    s_stepper_direction = -1;
    count = -count;
  }

  s_stepper_count      = count;
  s_stepper_phaseadder = speed;

  TACTL |= TAIE;           // turn timer ISR on to rotate the motor
}

bool stepper_is_rotating(void)
{
  return (TACTL & TAIE) != 0;
}




// Timer_A3 Interrupt Vector (TA0IV) handler
// This ISR is called every 1ms and will drive the stepper motor
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A(void)
{
  static uint16_t old_phaseacc;

  old_phaseacc = s_stepper_phaseaccumulator;
  TA0IV;
  s_stepper_phaseaccumulator += s_stepper_phaseadder;

  if ( (old_phaseacc ^ s_stepper_phaseaccumulator) & 0x8000 ) // check 
if highest bit has overflown
  {
    s_stepper_position += s_stepper_direction;
    P2OUT = (P2OUT & (~((1<<STEPPER_APH) | (1<<STEPPER_BPH)))) | 
s_step_pattern[s_stepper_position & 0x03];
    s_stepper_count--;
    if (s_stepper_count == 0)
    {
      TACTL &= ~TAIE;           // turn timer ISR off, because motor is 
not rotated anymore
    }
  }
}





Vielen Dank im Voraus

Lg
Fabian

von aSma>> (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Servus,
generell sind Einheiten pflicht.

Was soll hier speed sein?

Ein paar Diskrepanzen gibt es auch:

- TACCR0 = 100-1;   // setup timer overflow every 100us

// Timer_A3 Interrupt Vector (TA0IV) handler
// This ISR is called every 1ms and will drive the stepper motor
__interrupt void Timer_A(void)

Was stimmt jetzt?

Zum Ablauf der ISR:
Eine Variable "old_phaseacc" und "s_stepper_phaseadder" wird durch einen 
xor logisch geprüft. Bei "Überlauf" mit 0x8000 geprüft. Eine If 
Anweisung ist bei c immer wahr, wenn der Ausdruck größer 0 ist. Die xor 
Geschichte könnte man mittels Tabelle oder Debugger genauer untersuchen.

Die Ansteuerung wird wohl für eine H-Brücke gemacht sein. Die 
Pin-Ansteuerung (kein PWM) wird durch eine ausgeklügelten Tabelle 
gemacht:
1
P2OUT =  s_step_schritte[ s_stepper_position &0x03];

Was noch anzumerken ist, dass Schrittmotoren normalerweise mittels 
Rampen angesteuert werden. Hier hat man nur eine konstante 
Geschwindigkeit.

Hier dazu etwas zum Lesen:
http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Fabian schrieb:
> wie geschieht die 90° Verschiebung?

Die ist hart in s_step_pattern[] kodiert.

von eProfi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Die letzte Frage wurde hier beantwortet:
https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/596805

Ich mache es so, dass der PWM-Wert aus einer LUT (look up table) kommt 
und somit echte Microstep-Sinussteuerung erfolgt.

Eine lineare Rampe lässt sich leicht in die DDS implementieren:
accu  += speed;
if(speed<soll) += accel; else
if(speed>soll) += accel;


Der Code stammt von hier (das hättest Du angeben sollen):
http://processors.wiki.ti.com/index.php/


> Eine If Anweisung ist bei c immer wahr, wenn der Ausdruck größer 0 ist.
??? Das gilt nur bei unsigned, besser:   wenn der Ausdruck ungleich 0 
ist.

Ein Schritt wird ausgeführt, wenn der Phasenakku die Schwelle 32768 
unter- oder überschreitet.

von eProfi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Ein Schritt wird ausgeführt, wenn der Phasenakku die Schwelle
> 32768 unter- oder überschreitet.

Genauer: die Schwellen 0 oder 32768
Also, wenn das Bit15 sich ändert.

// Timer_A3 Interrupt Vector (TA0IV) handler
// This ISR is called every 1ms and will drive the stepper motor
__interrupt void Timer_A(void)

Was stimmt jetzt?

Der Code steht genau so bei TI, nicht gerade vorbildlich.

Da die eMail des Programmierers angegeben ist, kann man ihn darauf 
hinweisen.

von eProfi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Und hier:
if(speed<soll) += accel; else
if(speed>soll) += accel;

-->
if(speed<soll) += accel; else
if(speed>soll) -= accel;

von eProfi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
AArgh
> Der Code stammt von hier (das hättest Du angeben sollen):
> http://processors.wiki.ti.com/index.php/

http://processors.wiki.ti.com/index.php/MSP430StepperMotor

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.