Arduino Polska Forum

Pełna wersja: Silnik krokowy, enkoder i przerwania
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Cześć,

chciałem sterować silnikiem krokowym (step/dir) za pomocą enkodera. Kręcę enkoderem a silnik ma nadążać za nim. Licznik enkodera jest inkrementowany/dekrementowany w przerwaniu. Pozycja silnika jest zadawana z przerwania timera 0. No i udało mi się gdy kręcę enkoderem silnik nadąża za nim nawet jak obracam nim bardzo szybko (timer sterowania silnikiem plse/dir ustawiony na 10kHz).

Problem pojawia się jak pozycję silnika zadaję ze zmiennej - przy częstotliwości 10kHz silnik gubi około 90% kroków. Jak zmniejszę częstotliwość timera do 5kHz to program działa jak trzeba - ale silnik obraca się za wolno.

Nie rozumiem dlaczego tak się dzieje. Właściwie w kodzie nic nie zmieniam tylko zamiast patrzeć na zmienną enkodera EncoderPos patrzę na inną zmienną StepperPosDem.

Nie chcę korzystać z pętli głównej - w niej chcę zrobić komunikację z PC.
Korzystam z Arduino Mega 2560

Może ktoś miał już taki problem albo doświadczenie w sterowaniu krokowców (pulse/dir) z przerwania?


Kod:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>

#include "digitalWriteFast.h"
#define StepperPulse 12
#define StepperDir 13

#define EncoderPinA 2   // Encoder Pin A pin 2 and pin 3 are inturrpt pins
#define EncoderPinB 3   // Encoder Pin B

float EncoderPos = 0;
float StepperPos = 0;
float StepperPosDem = 0;

void readEncoder()
{
  if(digitalRead(EncoderPinB) == digitalRead(EncoderPinA) )
  {
    EncoderPos = EncoderPos + 1;
  }
  else
  {
    EncoderPos = EncoderPos - 1;
  }
}

void setup() {
 
  // TIMER 0 for interrupt frequency 10000 Hz:
  cli(); // stop interrupts
  TCCR0A = 0; // set entire TCCR0A register to 0
  TCCR0B = 0; // same for TCCR0B
  TCNT0  = 0; // initialize counter value to 0
  // set compare match register for 10000 Hz increments
  OCR0A = 199; // = 16000000 / (8 * 10000) - 1 (must be <256)
  // turn on CTC mode
  TCCR0B |= (1 << WGM01);
  // Set CS02, CS01 and CS00 bits for 8 prescaler
  TCCR0B |= (0 << CS02) | (1 << CS01) | (0 << CS00);
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);
  sei(); // allow interrupts

  pinMode(StepperDir, OUTPUT);
  pinMode(StepperPulse, OUTPUT);

  pinMode(EncoderPinA, INPUT);
  pinMode(EncoderPinB, INPUT); 
  digitalWrite(EncoderPinA, LOW);
  digitalWrite(EncoderPinB, LOW);

  attachInterrupt(0, readEncoder, CHANGE);
}

boolean toggle = false;

ISR(TIMER0_COMPA_vect){
/*
  //OPCJA 1 - sterowanie silnikiem krokowym zmieniając zmienną StepperPosDem - nie działa
 
  if(StepperPosDem - StepperPos > 3 || StepperPosDem - StepperPos < -3)
  {
    if(StepperPosDem - StepperPos < 0)
    {
      StepperPos = StepperPos - 4.52;
      digitalWriteFast(StepperDir, 0);
    }
    else
    {
      StepperPos = StepperPos + 4.52;
      digitalWriteFast(StepperDir, 1);
    }
   
    toggle = !toggle;
    if(toggle)
    {
      digitalWriteFast(StepperPulse, HIGH);
    }
    else
    {
      digitalWriteFast(StepperPulse, LOW);  
    }
   
  }*/

  //OPCJA 2 - sterowanie silnikiem krokowym nadążając za EncoderPos
  //zmienianą w przerwaniu enkodera - działa
 
  if(EncoderPos - StepperPos > 3 || EncoderPos - StepperPos < -3)
  {
    if(EncoderPos - StepperPos < 0)
    {
      StepperPos = StepperPos - 4.52;
      digitalWriteFast(StepperDir, 0);
    }
    else
    {
      StepperPos = StepperPos + 4.52;
      digitalWriteFast(StepperDir, 1);
    }
   
    toggle = !toggle;
    if(toggle)
    {
      digitalWriteFast(StepperPulse, HIGH);
    }
    else
    {
      digitalWriteFast(StepperPulse, LOW);  
    }
  }
}


void loop() {

  StepperPosDem = 1000; //Gdy używam OPCJI 1 w przerwaniu ISR(TIMER0_COMPA_vect)  - silnik gubi kroki

}
Jak zmiennej używa się w przerwaniu i poza, bezpieczniej użyć jej z volatile. Raczej tak samo powinno być gdy jest użyta w kilku przerwaniach. Druga sprawa to używanie float, należy ich unikać, potrzebujesz liczyć z dokładnością do 0.01 to użyj liczb większych x100.
(17-01-2021, 23:50)kaczakat napisał(a): [ -> ]Jak zmiennej używa się w przerwaniu i poza, bezpieczniej użyć jej z volatile. Raczej tak samo powinno być gdy jest użyta w kilku przerwaniach.  Druga sprawa to używanie float, należy ich unikać, potrzebujesz liczyć z dokładnością do  0.01 to użyj liczb większych x100.
Spoko, sprawdzę jutro, zmienię zmienne na volatile i wyrzucę float. Nie widziałem w tym problemu dlatego, że zmienna enkodera (EncoderPos) i ta którą zadaję pozycję z pętli głównej  (StepperPosDem) są zdefiniowane tak samo (float). Z jedną program działa z drógą nie - ale może to coś pomoże lub naprowadzi na inny trop.

Dzięki 
Hej, po zmianie definicji zmiennych na volatile i z float na long nic się nie zmieniło. Kombinuje dalej.
Nie uwzględniłeś szpilek...