Step motorda hız kontrol sorunu

Başlatan berkay_91, 20 Ağustos 2014, 21:10:32

berkay_91

  mrb arkadaşlar, bir tane step motor hız ve yön kontrol devresi yaptım ve karta bastım ancak motor sağa ve sola aynı hızda dönmüyor, hız kontrolünü 20k lık bir potansiyometreden aldığım analog veriyi ile ADC den sağlıyorum, yön kontrolünü ise pinb4 ve pinb5 e bağladığım 2 tane butonla sağlıyorum. Microişlemci olarak atmega8 kullandım, aşağıdaki kodda motor, saga_don ve sola_don fonksiyonlarından temp=Read_adc(5); kodunu sildiğim zaman her iki yondede aynı hızda aynı akımı çekerek dönüyor tabi kodu sildiğim için dönüş esnasında hız kontrolü yapamıyorum. durdurduktan sonra değiştirebiliyorum. temp=Read_adc(5); kodu dönme fonksiyonlarının içindeyken dönüş esnasında hızı değiştirebiliyorum ama motor dönerken fazla titriyo sanki rezonansa giricekmiş gibi oluyor ve her iki yönde aynı hızda dönmüyor, yani sorun bu kodun dönme fonksiyonlarının içinde olması sağlıklı bir şekilde dönerken ADC ile hız kontrolünü nasıl sağlayabilirim bi türlü bulamadım lütfen yardımcı olun... 

/*
 * kucuk_step_mega8.c
 *
 * Created: 22.06.2014 20:14:19
 *  Author: BERKAY
 */ 

#include <avr/io.h>
#define F_CPU 1000000
#include <util/delay.h>

volatile int v[4]={3,6,12,9},temp,i,j,k;

int Read_adc(int);
int saga_don(int);
int sola_don(int);

int Read_adc(int x){
	
	ADMUX= x | 0x40;
	ADCSRA |= 0x40;			// start the adc conversion on AN0
	while((ADCSRA & 0x10)==0);
	ADCSRA|=0x10;
	return ADCW;  // ADCW = adc low bits + adc high bits
	
}

int saga_don(int temp){
	
	while(bit_is_clear(PINB,4)){
		
		temp=Read_adc(5);
		
		for (i=0; i<=3; i++){
		PORTB=v[i];
		gecikme(temp);
		_delay_ms(1);
	}
	
	}
	
	 PORTB=0x00;
	
	_delay_ms(800);
	
}

int sola_don(int temp){
	
	while(bit_is_clear(PINB,5)){
		
		temp=Read_adc(5);
		
	for (j=3; j>=0; j--){
		PORTB=v[j];
		gecikme(temp);
		_delay_ms(1);
	}
	
	}
	
	 PORTB=0x00;
		
	_delay_ms(800);
}

void adc_init(){
	
	ADCSRA = 0x83;  // prescalar is used 8	
}

  void gecikme(int z){
	  
	  for(k=0; k<=z; k++)
	  _delay_us(30);
	  
  }

int step_kontrol(){
	
	while(1){
		
		 if(bit_is_set(PINB,5)){ // SAĞA DÖN
		 
		 saga_don(temp);
		 
	 }
	 
	 else if(bit_is_set(PINB,4)){ // SOLA DÖN
	 
	 sola_don(temp);
	 
	 
 }
 
 else{
	 
	 while( (PINB & 0X30)==0X00 ){
		 
		 PORTB=0x00;
		 
		 temp=Read_adc(5);
		 
	 }
	 
 }
		
	}		
	
}

int main(){
	
	DDRB= 0x0f;
	
	adc_init();

	while(1){
		
	   step_kontrol();
		
	}
	return 0;
}

XX_CİHAN_XX

Sorunuzun cevabı yazınızın içinde. Motor hız kontrolünü adc ile ölçüyorum demişsiniz. Bildiğiniz üzere ADC modülü çok hassastır ve mV lar mertebesindeki değişimleri algılayabilir. Motorunuzun titremesi doğru bir sürme ortamı oluşturamadığınızla alakalı bir durum gerek donanımsal gerekse yazılımsal sebepler mevcut. Motorunuzun titrek çalışması ve yön değiştirme durumlarında besleme voltajınızda dalgalanmalar olur bu da mV hassasiyetinde çalışabilen adc voltajınızın gözünden kaçmaz. Bu nedenle sistemi gözden geçirip önce sürücünüzün sabit hızla titremeden çalışabilmesini sağlayın daha sonra adc üzerinden hız kontrolünü yapmayı denersiniz. Bir diğer hususta eski motorlarda bir yöne dönerken diğerine göre sıkışmalar, sürtünmeler olabiliyor adc aralığınızı geniş ve toleranslı tutun. Sağ ve Sol taraf için ayrı paremetreler girmeniz gerekebilir dediğim durum sebebiyle.
Yirmi yaşındaki bir insan, dünyayı değiştirmek ister . Yetmiş yaşına gelince , yine dünyayı değiştirmek ister, ama yapamayacağını bilir.

Kabil ATICI

#2
ADC okuma fonksiyonunu bu kadar sık kullanmana gerek yok. En basitinden timer1 kullanarak 200ms'lik ve 500ms'lik bir gecikme aralığında kesme ayarlarsın.Bu kesme geldiğinde adc okuma verirsin.
"ADC Conversion Complete" gibi bir kesme kullanaraktan kesme sonucunu beklemezsin. Kesme gelince kendiliğinden değer güncellenmiş olur.

Bu şekilde kullanırsan adc oku yerine bir gecikme eklemen gerekir.

Gördüğüm kadarı ile tek kutuplu motor sürmek üzere hazırlanmış program gibi duruyor. Sanırım tork artırmak için iki bağlantı birden sürülüyor.
ambar7

berkay_91

farklı yönlerde motorun hızını pottan değiştirdikten sonra multimetreyle potun orta bacağını ölçtüm, gerilim 1 mv bile değişmezken sola dön butonuna bastığımda motor çok daha yavaş dönüyor ve 2 katı akım çekiyor, kodlar simetrikken ve ADC hassasiyetinde her iki yöndede potun orta bacağında çıkan gerilimde değişiklik olmazken bunların olması çok saçma ama oluyor, belliki sorun donanımsal değil ADC okuma fonksiyonunda. zaten yukarda dediğim gibi temp=Read_adc(5); adc okuma komutunu ordan çıkarınca her şey düzeliyor motor çok temiz dönüyor ve artık hızı motor dönmüyorken pottan değiştirdiğimde her iki yönde aynı hızda dönüyor ve aynı akımı çekiyor, ambar7' nin dediği gibi hız farkının ve bozuk dönüşün adc nin çok sık kullanımından olabileceğini düşünüp her iki for döngüsündeki  for (i=0; i<=3; i++){ komutunda i<=3 ü 200 e kadar yükselttim ancak düzelmediği gibi bu seferde her 200 adımdan sonra geçiş darbelerini çok net bir şekilde hissetmeye başladım, ambar7 nin dediğini deniycem fikirleriniz için teşekkür ederim başka bir fikir gelirse aklınıza yazabilirsiniz. 

berkay_91

dediğini yaptım ambar7, motor dönerken potu oynasamda hız değişmiyor, dönmeyi durdurunca değiştirip tekrar yeni hızda döndürebiliyorum bi yardımcı olursan sevinirim... yeni kodlar aşağıda.

/*
 * kucuk_step_mega8.c
 *
 * Created: 22.06.2014 20:14:19
 *  Author: BERKAY
 */ 


#include <avr/io.h>
#define F_CPU 1000000
#include <util/delay.h>
#include <avr/interrupt.h>

volatile int v[8]={3,6,12,9},temp,i,j,k;

int Read_adc(int);
int saga_don(int);
int sola_don(int);

void timer1_init(){
	
	TCCR1B=0X05; // prescalar 1024
	TCNT1=65035;
	TIMSK=(1<<TOIE1);
	sei();
	
}

// (1024/10^6)*500=0.512 sn

ISR(TIMER1_OVF_vect){
	
	TCNT1=65035;
	temp=Read_adc(5);
		
}


int Read_adc(int x){
	
	ADMUX= x | 0x40;           // detect adc channel and referance voltage
	ADCSRA |= 0x40;			   // start the adc conversion  
	while((ADCSRA & 0x10)==0); // wait until conversion finishing
	ADCSRA|=0x10;
	return ADCW;
	
}


int saga_don(int temp){
	
	timer1_init();
	
    while(bit_is_clear(PINB,5)){
		
		for (j=3; j>=0; j--){
			PORTB=v[j];
			_delay_ms(1);
			gecikme(temp);
			
		}
		
	}
	
	PORTB=0x00;
	
	_delay_ms(800);
	
}




int sola_don(int temp){
	
	timer1_init();
	
	while(bit_is_clear(PINB,4)){
		 
	   for (i=0; i<=3; i++){
		PORTB=v[i];
		_delay_ms(1);
		gecikme(temp);
	}
	
	}
	
	 PORTB=0x00;
		
	_delay_ms(800);
}


void adc_init(){
	
	ADCSRA = 0x83;  // prescalar is used 8	
}

  void gecikme(int z){
	  
	  for(k=0; k<=z; k++)
	  _delay_us(30);
	  
  }

int step_kontrol(){
	
	while(1){
		
		 if(bit_is_set(PINB,4)){ // SAĞA DÖN
		 
		 saga_don(temp);
		 
		 
	 }
	 
	 else if(bit_is_set(PINB,5)){ // SOLA DÖN
	 
	 sola_don(temp);
	 
	 
}
 
 else{
	 
	 timer1_init();
	 
	  while( (PINB & 0X30)==0X00 ){
		 
		 PORTB=0x00;
		 
		 
	 }
	 
 }
		
	}		
	
}

int main(){
	
	DDRB= 0x0f;
	
	adc_init();
	
    while(1){
		
	   step_kontrol();
		
	}
	return 0;
}

engerex

ADC değerini bir defa oluyorsun.  MOTOR dönerken okumuyorsun.

berkay_91

motor dönerken, kod her 512 ms de bir timer interrupt döngüsüne giriyor ve ordan analog veriyi okuyor

Kabil ATICI

normalde  derleyicinin kafası karışması gerekir. temp olayı bana baya karışık geldi.
Sanırım derleme esnasında kimbilir hangi registerelere yükleniyor. Bu işlemci içinde 32 tane register var (hadi her işte kullanılana 16 tane) ve bunları senin verdiğin değişkenler atanıyor.
Genel olarak bir tane temp kullandın, peki bir döngü içinde kullandığın  temp ile aynı registere atanır mı? hayır. Atansa bile genel temp  yığına gömülür. Dolayısı ile senin okudun değer program çalışırken işleme alınmaz. onun için genel olarak kullandığın registerlere öze bir isim ver.

volatile int v[8]={3,6,12,9},temp,i,j,k; buradaki temp olayına başka bir isim ver ve programını ona göre düzenle.


int main() ;altında
adc_init(); altında
timer1_init(); yerleştirmen yeterlidir. Eğer ayarları düzgün yaptıysan timer kesmesi sürekli çalışır.

int sola_don(){
    while(bit_is_clear(PINB,4)){
       for (i=0; i<=3; i++){
        PORTB=v;
        _delay_ms(1);<<<<bu gereksiz.
        gecikme(temp);
    }
    }
     PORTB=0x00;
    _delay_ms(800);  <<<bu yaklaşık 0.8 saniye yapmıyor mu?
}
ambar7

berkay_91

#8
_delay_ms(1); koymayınca küçük motorlar yüksek hızda sapıtıyor onun için koydum.  _delay_ms(800);  komutunu ise döngüden çıkar çıkmaz diğer yöne dönme fonksiyonuna girmesin diye kullandım. bunu koymadan önce butona basınca birinden çıkıp hemen diğerine giriyordu.

volatile int v[8]={3,6,12,9},temp,i,j,k;  satırında temp değişkenini temp_hiz olarak değiştirdim peki alttaki fonksiyonda temp için nasıl bi düzenleme yapabilirim?

int saga_don(int temp){
   
   timer1_init();
   
    while(bit_is_clear(PINB,5)){
      
      for (j=3; j>=0; j--){
         PORTB=v[j];
         _delay_ms(1);
         gecikme(temp);
         
      }
      
   }
   
   PORTB=0x00;
   
   _delay_ms(800);
   
}

Kabil ATICI

gecikme(temp); sanırım bu satırdaki.  çünkü bu satır dönme hızını ayarlıyor.
gecikme(temp_hiz); şeklinde olabilir.

"int saga_don(int temp)" bu satır  " int saga_don()"  şekline dönüşebilir. Böyle yaparsan  bu fonksiyonu çağırdığın zaman parametre vermene gerek kalmaz.
ambar7

berkay_91

mrb, kodları uzun uğraşlardan sonra alttaki gibi değiştirdim ve ADC conversion complete kesmesini timer0 overflow ile aktive ettim
yeni kodları atmega328 de kullanıyorum. Şimdide motor aynı yönde dönerken bile potansiyometreye dokunmadığım halde hız kendi kendine değişiyor bi yerde hata yaptım galiba yardımcı olur musunuz?

#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>
#include <avr/interrupt.h>

volatile int v[4]={3,6,12,9},temp,i,j,k;

int Read_adc(int);
int saga_don();
int sola_don();

void timer0_init(){
	
	TCNT0=0;
	TIMSK0=(1<<TOIE0);
	TCCR0B=0X05; // prescalar 1024
	sei();
	
}

// (1024/8*10^6)*255=32.6 mSn


ISR(ADC_vect){
	
	temp=ADCW;
	
}

ISR(TIMER0_OVF_vect){
	
	TCNT0=0;
	
}

int saga_don(){
	
	while(bit_is_clear(PINB,4)){
		
		for (i=0; i<=3; i++){
		PORTB=v[i];
		gecikme(temp);
		_delay_us(125);
	}
	
	}
	
	 PORTB=0x00;
	
	_delay_ms(50);
	
}

int sola_don(){
	
	while(bit_is_clear(PINB,5)){
		
		for (j=3; j>=0; j--){
		PORTB=v[j];
		gecikme(temp);
		_delay_us(125);
	}
	
	}
	
	 PORTB=0x00;
		
	_delay_ms(50);
}

void adc_init(){
	
	ADMUX= 0x45; // referance voltage is Avcc, ADC pin is selected 5
	ADCSRA = 0xAE;  // prescalar is used 64, ADEN,ADATE,ADIE,ADPS1,ADPS2 bits are set
	ADCSRB |=(1<<ADTS2); // trigger source is timer0 overflow
}

  void gecikme(int z){
	  
	  for(k=0; k<=z; k++)
	  _delay_us(5);
	  
  }

void step_kontrol(){
	
	while(1){
		
		 if(bit_is_set(PINB,5)){ // SAĞA DÖN
		 
		 saga_don();
		 
	 }
	 
	 else if(bit_is_set(PINB,4)){ // SOLA DÖN
	 
	 sola_don();
	 
	 
 }
 
 else{
	 
	 while( (PINB & 0X30)==0X00 ){
		 
		 PORTB=0x00;
		 
	 }
	 
 }
		
	}		
	
}

int main(){
	
	DDRB= 0x0f;
	
	adc_init();
	timer0_init();

	while(1){
		
	   step_kontrol();
		
	}
	return 0;
}