Start Elkretssimulator


Stegmotor

Lite stegmotorteori

Först lite stegmotorteori. En stegmotor består enkelt uttryckt av en snurrande magnet. Runt om sitter elektromagneter vilka magnetiseras enligt ett mönster som driver runt axeln med magneten. (Det kan såklart vara tvärtom också; dvs elektromagneterna sitter i mitten med en snurrande magnet runtomkring. Det är ofta så en bortslös motor brukar byggas. Skillnaden mellan en stegmotor och en borstlös motor är sublim)



Det finns olika komplicerade stegmotorer med olika många elektromagneter. Ju fler lindningar desto fler faser och desto jämnare och kontrollerad rörelse. Ju färre lindningar desto färre faser och "hackigare" rörelse - men billigare stegmotor. Elektromagneterna jobbar både attraherande (drar till sig) och repellerande (stöter ifrån). För att åstadkomma detta kan man antingen vända på polariteten på en lindning eller så kan man när man bygger motorn lägga in dubbla lindningar som går åt motsatt håll. Skillnaden som uppstår; mellan unipolär och bipolär är att när man driver unipolära behöver man aldrig vända på polariteten för en elektromagnet och drivelektroniken blir därför enklare. Med bipolär blir stegmotorn enklare men drivelektroniken mer komplicerad.

Stegsekvensen

Arbetet att driva runt stegmotorn handlar alltså om att aktivera elektromagneterna i stegmotorn enligt ett mönster som driver runt axeln. Jag har en stegmotor här (en 5-trådars unipolär stegmotor dock inte med samma färger på trådarna som ovanstående skiss) som enligt dokumenteringen kan drivas runt med hjälp av nedanstående sekvens. Detta kallas fullsteg.

Fullsteg



Man ska alltså upprepande mata ut mönstret 1000, 0100, 0010, 0001, ... (eller i omvänd ordning beroende på riktning) med lämplig hastighet på de digitala portar som matchar stegmotorns 4 lindningar.

Det finns också något som heter halvsteg och det innebär att man lägger in ett steg mitt-i-mellan två elektromagneter i motorn genom att magnetisera båda elektromagneterna samtidigt.

Halvsteg


Man ska alltså upprepande mata ut mönstret 1000, 1100, 0100, 0110, 0010, 0011, 0001, 1001, ... (eller i omvänd ordning beroende på riktning) med lämplig hastighet på de digitala portar som matchar stegmotorns 4 lindningar.

Halvsteg ger en jämnare gång på stegmotorn men till priset att vridmomentet blir lägre. Det finns fler sätt att köra en stegmotor som ger andra egenskaper men jag hoppar över det här och nu, t.ex. mikrosteg eller fullsteg med 2 faser aktiva.

Vilken riktning stegmotorn snurrar beror helt på i vilken ordning dessa sekvenser matas ut till stegmotorn.

Driva stegmotorn

Strömmen på utgångarna på en mikrokontroller räcker inte för att driva en stegmotor så det behövs någon form av effektsteg här. Typiskt är det någon krets t.ex. ULN2803 eller ULN2003 som ligger mellan mikrokontrollern och stegmotorn enligt nedan.





Men det går även att konstruera detta effektsteg med t.ex. BC547 transistorer t.ex. enligt nedan.


När man tittar på ovanstående schema och även det med ULN2803, så kan man få intrycket att signalen inverteras och att man därför måste skicka in en inverterad signal för att det skall bli "rätt". Att signalen inverteras stämmer, men det blir rätt ändå. Lindningarnas gemensamma anslutning på stegmotorn går till 5 eller 12 volt, så det är just när lindningens andra anslutning "nollas" (sänks) som den blir aktiv (flyter en ström). Så en hög signal in betyder fortfarande att elektromageten i stegmotorn är aktiv och vice versa.

Programmet - med riktning och fartreglering

Uppkoppling

Först kanske ska sägas att eftersom stegmotorn 28BYJ48 har en växellåda så snurrar axeln ut ganska långsamt. Detta är därför kanske inte den mest visuella stegmotorn för att se vad som händer. Men strunt i den detaljen nu! (Men det är bra att veta att det existerar en växellåda annars kanske du undrar varför det går så långsamt)

Koden nedan bör fungera för vilken stegmotor som helst som är unipolär med 4 magneter (5 trådar).

Nedan kod kan ställas in så att den antingen kör fullsteg (FULLSTEP) eller halvsteg (HALFSTEP). De digitala utgångarna 8-9-10-11 kopplas till IN1-IN2-IN3-IN4. För att reglera hastigheten kopplas en potentiometers mittenutgång till pinne 1 och de andra pinnarna på potentiometern till GND resp. 5V (det blir en spänningsdelare som kan regleras från 0-5V).



28BYJ48

Observera att stegmotorn använd här ser ut som nedan. Vi avfyrar sedan elektromagneterna i denna enligt följande för fullsteg; 1000, 0100, 0010, 0001 där lindningarna är BRGO (Blå-Rosa-Gul-Orange) och 1000, 1100, 0100, 0110, 0010, 0011, 0001, 1001 för halvsteg.



Användning

Funktionen är sådan att när potentiometern står i mitten så står stegmotorn stilla. Vrider man åt ena eller andra hållet snurrar stegmotorn medurs eller moturs och hastigheten beror på hur mycket man vrider åt ena eller andra håller.

Funktion

En timer-interrupt sätts med en väntetid som beror på vad potentiometer står på. Beroende på om potentiometern befinner sig på vänster eller höger halva (dvs utsignalen blir mer eller mindre än 512 (alltså halva 1024 som är full signal på analog ingång)) så sätts även rotate till +1 eller -1.

För varje steg (interrupt-avbrott) räknas fasen upp eller ner och börjar om i andre änden. Dvs 0-1-2-3-0-1-2-3-0-1-2 osv. eller vice versa och vi skriver sedan ut värdet på stegmotorns lindningar enligt tabellerna halfStep eller fullStep beroende på vad som är önskvärt.

Vi ändrar enbart interruptet om vi har vridit lite på potentiometern, därför sparar jag lastPotValue (senaste värdet). Värdet från A/D -omvandlaren rör sig alltid lite så därför jämför jag med en viss tröskel (3).

#define HALFSTEP 1
#define FULLSTEP 2

int stepMode = HALFSTEP;

int POT = 1;    // Potentiometer (fart)
int IN1 = 8;    // Blå - 28BYJ48 pin 1
int IN2 = 9;    // Rosa - 28BYJ48 pin 2
int IN3 = 10;   // Gul - 28BYJ48 pin 3
int IN4 = 11;   // Orange - 28BYJ48 pin 4

int halfStep[8] = {
	B01000, 
	B01100, 
	B00100, 
	B00110, 
	B00010, 
	B00011, 
	B00001, 
	B01001};

int fullStep[4] = {
	B01000, 
	B00100, 
	B00010, 
	B00001};

int phase = 0;
int rotate = 1;
int potValue;
int lastPotValue;

void setup() 
{
  Serial.begin(9600); 
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  
  potValue = analogRead(POT);
  setupInterrupt(potValue);
}

void setupInterrupt(int potValue)
{
  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A =  16000 - abs(potValue-512)*30; 
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS12) | (1 << CS10); // 1024 prescaler
  TIMSK1 |= (1 << OCIE1A);
  sei();      
}

ISR(TIMER1_COMPA_vect)
{
  setOutput(phase);
  phase += rotate;

  if(stepMode == HALFSTEP)
  {
    phase%=8;
    if(phase<0)
    phase = 7;
  }
  if(stepMode == FULLSTEP)
  {
    phase%=4;
    if(phase<0)
    phase = 3;
  }

  potValue = analogRead(POT);
  if(abs(potValue - lastPotValue) > 3)
  {
    Serial.println(potValue);    
    if(potValue>512)
      rotate = 1;
    else
      rotate = -1;
    lastPotValue = potValue;    
    setupInterrupt(potValue);
  }  
}

void setOutput(int out)
{
  if(stepMode == HALFSTEP)
  {
    digitalWrite(IN1, bitRead(halfStep[out], 0));
    digitalWrite(IN2, bitRead(halfStep[out], 1));
    digitalWrite(IN3, bitRead(halfStep[out], 2));
    digitalWrite(IN4, bitRead(halfStep[out], 3));
  }
  if(stepMode == FULLSTEP)
  {
    digitalWrite(IN1, bitRead(fullStep[out], 0));
    digitalWrite(IN2, bitRead(fullStep[out], 1));
    digitalWrite(IN3, bitRead(fullStep[out], 2));
    digitalWrite(IN4, bitRead(fullStep[out], 3));
  }  
}

void loop()
{

}