• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Enkoder na silniku
#1
Witam, mam problem ze zliczaniem impulsów z enkodera w celu określenia liczby obrotów walu silnika.  Do zliczania impulsów używam przerwania RISING. Enkoder ma rozdzielczość 16 impulsów na obrót. Niestety moje Arduino uno nie nadąża z liczeniem impulsów. Dla różnych prędkości jest różna liczba impulsów na obrót. Ktos wie jak sobie z tym poradzić czy jest to nie do pokonania I wynika np. z maksymalnej częstotliwości sygnału zegarowego? Dzięki za pomoc
 
Odpowiedź
#2
Witam. Pokaż szkic. A tak w skrócie, dla różnych prędkości ma być różna liczba impulsów.
 
Odpowiedź
#3
Kod:
int impulsy=0;
int obroty =0;



void setup() {
 // put your setup code here, to run once:
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(5,OUTPUT);
analogWrite(5,100);


digitalWrite(6,HIGH);
digitalWrite(7,LOW);

attachInterrupt(1,Odleglosc,RISING);
Serial.begin(9600);
}

void loop() {
 // put your main code here, to run repeatedly:
 
 


}

void Odleglosc ()
{
 
impulsy = impulsy +1;

if(impulsy == 1920){
obroty = obroty +1;
Serial.println(obroty);

impulsy=0;

}
}

Z jakiej racji ma tak byc? Uzywam enkodera to zliczania obrotow, rozdzielczosc sie nie zmienia.
 
Odpowiedź
#4
Źle zrozumiałem, przepraszam. Dla każdego obrotu ma być taka sama liczba impulsów, różna jest w sensie na sekundę.
Zapewne procek się nie wyrabia. W przerwaniu powinno być tylko zliczanie impulsów, a w szczególności nie może być tam Serial.println(obroty);

Kod:
volatile int impulsy=0;
int obroty =0;



void setup() {
// put your setup code here, to run once:
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(5,OUTPUT);
analogWrite(5,100);


digitalWrite(6,HIGH);
digitalWrite(7,LOW);

attachInterrupt(1,Odleglosc,RISING);
Serial.begin(9600);
}

void loop() {
// put your main code here, to run repeatedly:

if(impulsy >= 1920){
[size=small][font=Monaco, Consolas, Courier, monospace]obroty = obroty +1;[/font][/size]
[size=small][font=Monaco, Consolas, Courier, monospace]Serial.println(obroty);[/font][/size]

impulsy=0;
}

}

void Odleglosc ()
{

impulsy++;

}
Wchodząc w obsługę przerwania procek staje się głuchy i ślepy, tylko inne przerwanie o wyższym priorytecie może je przerwać, a w Arduino chyba po prostu są wyłączane. Musi być dopisane volatile by można było zmieniać zmienną impulsy zarówno w przerwaniu jak i w pętli głównej. impulsy >= 1920 raczej teraz tak, bo może się zdarzyć, że moment == zostanie przegapiony. Samo  drukowanie obrotów również uzależniłbym od stałego interwału czasowego, nie samych obrotów, ale to już mniej istotne. Ewentualnie wywalić tylko drukowanie z przerwania, nie wiem co to ma robić i po co, ile może być maks takich impulsów/s, także sam zdecyduj jak skrócić czas przerwania, musi być minimum. Samo przerwanie zajmuje około 15 cykli zegarowych (skok programu, odkładanie aktualnej pracy na bok, powrót do pracy) + cykle zegara wymagane na obsługę samych instrukcji napisanych w funkcji przerwania, teocentrycznie jest możliwe zliczenie 1mln na procku AVR 16MHz. Praktycznie już przy zmiennej int jest trzy-cztery razy mniej przy 100% czasu działania tylko i wyłączenie przerwania, jeśli pętla ma zająć kolejne cykle zegarowe, bo po coś te dane w przerwaniu są zbierane, to już się robią tylko tysiące możliwe do zliczania. No przynajmniej stale. Jak coś się kręci 15kHz to można to odpalać na ułamek sekundy, zliczać i wracać do normalnej pracy.
 
Odpowiedź
#5
Zrobilem jak powiedziales, w przerwaniu jest tylko dodawanie impulsow. Wszystko dziala poprawie dla pelnego zakresu predkosci, jest tylko jeden mankament. Uklad dziala poprawnie jesli na obrot przypisze nie 1920 ale 1920/2 impulsow
 
Odpowiedź
#6
Witam,
A jaki jest zakres prędkości obrotowych tego silnika?
Pozdrawiam,
Tomek.
 
Odpowiedź
#7
Niestety sam nic tak nie liczyłem mikroprockiem, dla mnie też zagadka. Może powinieneś odpalić jakiś oscyloskop i popatrzeć jak jest generowany sygnał z tego enkodera, może ta rozdzielczość 16 oznacza zliczanie impulsów dla sygnału narastającego i opadającego? Jeśli tak to trzeba dzielić przez 2, bo narastających ma być 8.
 
Odpowiedź
#8
Może się mylę, ale może mikrokontroler pracuje zbyt szybko i zbiera impulsy wielokrotnie, bo po prostu zdąży Smile
Spróbuj dopisać do funkcji Odleglosc() blokadę, która zatrzymuje działanie programu tak długo, jak wartość z enkodera się nie zmienia. Możesz to zrobić za pomocą while:
Kod:
while(digitalRead(1)==HIGH){}
Wtedy taka funcja miałaby postać:
Kod:
void Odleglosc ()
{
impulsy++;
while(digitalRead(1)==HIGH){}
}
W takim wypadku program wyjdzie z tej pętli tylko w przypadku, kiedy sygnał na pinie 1 przestanie mieć wartość 1.
 
Odpowiedź
#9
Raczej nie o to chodzi, przy rising jest dokładnie jeden punkt na wykresie napięcie/czas wyzwalający przerwanie. Inne opcje to:
"
LOW to trigger the interrupt whenever the pin is low,
CHANGE to trigger the interrupt whenever the pin changes value
RISING to trigger when the pin goes from low to high,
FALLING for when the pin goes from high to low.
The Due, Zero and MKR1000 boards allows also:
HIGH to trigger the interrupt whenever the pin is high.
".
Inna sprawa, że impuls może mieć drgania jak styki klawiszy, by to ocenić potrzebny jest właśnie oscyloskop. Ja wyobrażam sobie enkoder jako okrągłą tarcze, na której są wycięte prostokąty o takiej samej szerokości jak pełne przestrzenie, światło przechodzi przez puste pola (od LED do PHOTOLED), a przez pełne nie, przy tej samej prędkości stan wysoki trwa tyle samo co niski, można łapać zmiany na stan niski i zmiany na stan wysoki, 16 na obrót w sumie. A drgania cechowałaby pewna losowość. Można by je wyeliminować jakimś filtrem, ale taki powinien być już w enkoderze.
 
Odpowiedź
#10
Witam,
Dyskusja już chyba toczy się bez udziału założyciela wątku :-)
Jeśli występowałby drgania (czyli coś niestabilnego i losowego) to wątpię, żeby ilość impulsów była dokładnie dwa razy większa od spodziewanej. Można przetestować jakie ilości otrzyma się dla innych "zdarzeń" wywołujących przerwania (podanych powyżej przez kolegę @kaczakata) i w ten sposób spróbować zdjagnozować przyczynę. Kompletnie nie wiadomo jaki enkoder został zastosowany i czy posiada on komparator. Poza tym, przy nie rozumie dlaczego enkoder ma rozdzielczość 16, a w programie obrót zwiększa się przy stanie licznika 1920?
@krn78- najprawdopodobniej dawanie pętli while() w funkcji obsługującej przerwanie nie jest dobrym rozwiązaniem.
Pozdrawiam,
Tomek.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości