A4988 ile adım kontrolü

Başlatan berkay_91, 01 Ocak 2015, 10:51:42

berkay_91

Mrb,yazdığım bu kodlarla A4988 sürücüsü aracılığıyla step motoru mikro step sürebiliyorum ve pottan hız kontrolü sağlayabiliyorum, şimdiki amacım frekans değerini 256 Hz e getirdikten sonra step motoru 100 adım sağa döndürmek. adım kontrolünü pwm ile nasıl yapıcağımı bilmiyorum motorun step açısı 1.8 derece, kod üzerinde yazarak yardımcı olur musunuz?

#define F_CPU 1000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd.h"

volatile unsigned long F_PWM;

#define PWM_RESOLUTION (unsigned char)(F_CPU / (F_PWM*256UL))

void pwm_init();
void frequency_kont();
int Read_adc();
void adc_init();
void start();


FILE lcd_str = FDEV_SETUP_STREAM(lcd_putc, NULL, _FDEV_SETUP_WRITE);

void pwm_init(){ // MODE 14, prescalar is 256
	 
	 TCCR1A=(1<<WGM11)|(1<<COM1B1);
	 TCCR1B=(1<<CS12)|(1<<WGM12)|(1<<WGM13);
		 	
}

void adc_init(){
	
  ADMUX=(1<<ADLAR)|(1<<REFS0)|(1<<MUX0)|(1<<MUX2);// adc pin is selected ADC5 and referrance voltage is VCC
  ADCSRA = 0x83;  // prescalar is used 8
  
}

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



void start(){
	
	pwm_init();
	
	while(bit_is_clear(PIND,7)){
		
		F_PWM=Read_adc();
		
		ICR1=PWM_RESOLUTION - 1;
		OCR1B=PWM_RESOLUTION/2-1; // % 50 duty sycle
		
		lcd_gotoxy(11,1);
		printf("%d ",F_PWM);
		
	}
	
	_delay_ms(200);
	
}

void frequency_cont(){
	
	while(1){
		
		if(bit_is_set(PIND,6)){
			
			start();
			
		}
		
		
		else{
		
		     while((PIND & 0X40)==0X00){
			 
			 TCCR1A=0X00;
			 TCCR1B=0X00;
			
		     }
		
	    }			
		
		
		
	}
	
}

int main(){
	
	DDRD|=(1<<0)|(1<<1)|(1<<2); // these are for LCD pins
	DDRB|=(1<<2)|(1<<4)|(1<<5)|(1<<6)|(1<<7); // these are for LCD data pins and PİNB2 is for OC1B
	
	adc_init();
	
	lcd_init(LCD_DISP_ON); 
	
	_delay_us(5);

	stdout = stdin = &lcd_str;
	
	lcd_clrscr();
	
	lcd_gotoxy(0,0);
	lcd_puts("FREQUENCY CONT.");
	
	lcd_gotoxy(0,1);
	lcd_puts("Frequency:");

    frequency_cont();
		
	return 0;
			
	}

Kabil ATICI

#1
Genellikle şema koymadan, işlemci ismi bile eklemedan bu tür isteklerde genel olarak cevap vermek gerekiyor...
gördüğüm kadarı ile timer1 ile alet için gereken adım frekansı üretiliyor.

timer1 her darbesinin motor için 1 adım olduğunu kabul ederek,
motor her adımının 1.8 derece olmasından motor tam dönüşü için 200 adım gerekiyor.
100 adım gitmesi için 100x200=20000 adım olması gerektiğini görüyoruz.
Artık motor yönünü de sen ayarla.
Zaten timer1'i motor hız ayarı olarak kullanıyorsun, biz sadece hız 256 olduğunda timer1 içindeki sayacın aktif olmasını sağladık.Sadece düştüğü zaman durdurmadık.
timer 1 içindeki sayaç 20000 ve üzeri olduğuna bakan bir kod ekledik sen sadece bu kodun içine motoru durduracak bir kod ekleyeceksin...

#define F_CPU 1000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd.h"

volatile unsigned long F_PWM;

#define PWM_RESOLUTION (unsigned char)(F_CPU / (F_PWM*256UL))

ISR(TIMER1_COMPA_vect);
void pwm_init();
void frequency_kont();
int Read_adc();
void adc_init();
void start();

int sayici;      //genel sayıcı
int bayrak=0;
int hiz=0;

FILE lcd_str = FDEV_SETUP_STREAM(lcd_putc, NULL, _FDEV_SETUP_WRITE);

void pwm_init(){ // MODE 14, prescalar is 256
	
	TCCR1A=(1<<WGM11)|(1<<COM1B1);
	TCCR1B=(1<<CS12)|(1<<WGM12)|(1<<WGM13);
	
	//bu bölüme timer1 kesmesi aktif olacak şekilde ekleme yap...
	
}
ISR(TIMER1_COMPA_vect){            //This is an interrupt service routine for the TIMER0 COMPA vector
	if (bayrak==1)
	sayici++;
}



void adc_init(){
	
	ADMUX=(1<<ADLAR)|(1<<REFS0)|(1<<MUX0)|(1<<MUX2);// adc pin is selected ADC5 and referrance voltage is VCC
	ADCSRA = 0x83;  // prescalar is used 8
	
}

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



void start(){
	
	pwm_init();
	
	while(bit_is_clear(PIND,7)){
		
		F_PWM=Read_adc();
		
		ICR1=PWM_RESOLUTION - 1;
		OCR1B=PWM_RESOLUTION/2-1; // % 50 duty sycle
		
		lcd_gotoxy(11,1);
		printf("%d ",F_PWM);
		hiz=F_PWM;
		
	}
	
	_delay_ms(200);
	
}

void frequency_cont(){
	
	while(1){
		if(hiz==256)
		bayrak=1;
		if (sayici=>20000)
		{
			//buraya istediğin kodları yaz....
		}
		
		if(bit_is_set(PIND,6)){
			
			start();
			
		}
		
		
		else{
			
			while((PIND & 0X40)==0X00){
				
				TCCR1A=0X00;
				TCCR1B=0X00;
				
			}
			
		}
		
		
		
	}
	
}

int main(){
	
	DDRD|=(1<<0)|(1<<1)|(1<<2); // these are for LCD pins
	DDRB|=(1<<2)|(1<<4)|(1<<5)|(1<<6)|(1<<7); // these are for LCD data pins and PİNB2 is for OC1B
	
	adc_init();
	
	lcd_init(LCD_DISP_ON);
	
	_delay_us(5);

	stdout = stdin = &lcd_str;
	
	lcd_clrscr();
	
	lcd_gotoxy(0,0);
	lcd_puts("FREQUENCY CONT.");
	
	lcd_gotoxy(0,1);
	lcd_puts("Frequency:");

	frequency_cont();
	
	
	
	
	return 0;
	
}

işleri iyi karıştırmışsın.

benim bildiğim
int main(void)
{
..
 while(1)
{
...
}
}

şeklinde olur..
ambar7

berkay_91

#2
İşlemci olarak Atmega8 kullanıyorum, tam dönüş için 360/1.8 = 200 adım demişsin ama sonrada motorun 100 adım atması için 200x100=20000 adım demişsin söylediğine göre 20000 adım attığında 100 tur atmış olmuyor mu?

Kabil ATICI

Motor hesabına göre evet.20000 Adım=100 tur
ambar7


berkay_91

kodları şu şekilde değiştirdim ama bazı frekanslarda nerdeyse 35-40 adım fazladan dönüyor

#define F_CPU 1000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd.h"

volatile unsigned long F_PWM,i,sayac;

#define PWM_RESOLUTION (unsigned char)(F_CPU / (F_PWM*256UL))

ISR(TIMER1_COMPA_vect);
void pwm_init();
void saga_don();
void sola_don();
void mikro_step_kont();
int Read_adc();
void adc_init();


FILE lcd_str = FDEV_SETUP_STREAM(lcd_putc, NULL, _FDEV_SETUP_WRITE);

void pwm_init(){ // MODE 15, prescalar is 256
	 
	 TCCR1A=(1<<WGM11)|(1<<WGM10)|(1<<COM1B1);
	 TCCR1B=(1<<CS12)|(1<<WGM12)|(1<<WGM13);
	 
	 TCNT1=0;
	 OCR1A=PWM_RESOLUTION - 1;
	 TIMSK=(1<<OCIE1A);
	 sei();
	 sayac=0;
	 
}

ISR(TIMER1_COMPA_vect){
	
	sayac++;
	
}

void adc_init(){
	
  ADMUX=(1<<ADLAR)|(1<<REFS0)|(1<<MUX0)|(1<<MUX2);// adc pin is selected ADC5 and referrance voltage is VCC
  ADCSRA = 0x83;  // prescalar is used 8
  
}

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

void saga_don(){
	
	PORTC|=(1<<1); // exit sleep mode
	PORTC|=(1<<0); //direction control
	pwm_init();
	
	while(sayac<=199){
		
		F_PWM=Read_adc();
		
		OCR1A=PWM_RESOLUTION - 1;
		OCR1B=PWM_RESOLUTION/2-1; // % 50 duty sycle
		
		lcd_gotoxy(11,1);
		printf("%d ",F_PWM);
		
	}
	
	_delay_ms(200);
	
}

void sola_don(){
	
	PORTC|=(1<<1);  // exit sleep mode
	PORTC&=~(1<<0); // direction control
	pwm_init();
	
	while(sayac<=199){
		
		F_PWM=Read_adc();
		
		OCR1A=PWM_RESOLUTION - 1;
		OCR1B=PWM_RESOLUTION/2-1; // % 50 duty sycle
		
		lcd_gotoxy(11,1);
		printf("%d ",F_PWM);
		
	}
	
	_delay_ms(200);
	
}



int main(){
	
	DDRD|=(1<<0)|(1<<1)|(1<<2);
	DDRB|=(1<<2)|(1<<4)|(1<<5)|(1<<6)|(1<<7);
	DDRC|=(1<<0)|(1<<1); // pinc0 is for direction, pinc1 is for sleep mode 
	
	adc_init();
	
	lcd_init(LCD_DISP_ON); 
	
	_delay_us(5);

	stdout = stdin = &lcd_str;
	
	lcd_clrscr();
	
	lcd_gotoxy(3,0);
	lcd_puts("MIKROSTEP");
	
	lcd_gotoxy(0,1);
	lcd_puts("Frequency:");


    while(1){
	
	if(bit_is_set(PIND,6)){
		
		saga_don();
		
	}
	
	else if(bit_is_set(PIND,7)){
		
		sola_don();
		
	}
	
	else {
		
		cli();
		TCCR1A=0X00;
		TCCR1B=0X00;
		
		PORTC&=~(1<<1); // for entering sleep mode
		
		while((PIND & 0XC0)==0X00){
			
			F_PWM=Read_adc();
			
			lcd_gotoxy(11,1);
			printf("%d ",F_PWM);
			
		}
		
	}	
	
		
	}		
		
	return 0;
			
	}

Kabil ATICI

  while(sayac<=199){
F_PWM=Read_adc();<----olay burada.
Tamam işlem esnasında timer1 değeri gelirse,saymaya devam eder, ama adc değeri okuması esnasında özellikle yüksek hızlarda buradaki işlemi tamamlanana kadar timer1 içindeki sayaç alır başını gider...
adc okuma işlemini
if(sayac<=100) ise olacak şekilde ayarlarsan, daha uygun olur.
Kontrol hızın düşer ama adım saymada sıkıntı olmaz.
ambar7

berkay_91

analog okumaları kaldırdım yinede fayda etmiyor 30 Hz de nerdeyse mükkemmel çalışıyor tam 1 tur dönüyor ama frekansı arttırdıkça daha çok adım kaçırıyor 256 ya getirince çeyrek tur fazla dönüyor

#define F_CPU 1000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd.h"

volatile unsigned long F_PWM,i,sayac;

#define PWM_RESOLUTION (unsigned char)(F_CPU / (F_PWM*256UL))

ISR(TIMER1_COMPA_vect);
void pwm_init();
void saga_don();
void sola_don();
void mikro_step_kont();
int Read_adc();
void adc_init();


FILE lcd_str = FDEV_SETUP_STREAM(lcd_putc, NULL, _FDEV_SETUP_WRITE);

void pwm_init(){ // MODE 15, prescalar is 256

TCCR1A=(1<<WGM11)|(1<<WGM10)|(1<<COM1B1);
TCCR1B=(1<<CS12)|(1<<WGM12)|(1<<WGM13);

TCNT1=0;
OCR1A=PWM_RESOLUTION - 1;
TIMSK=(1<<OCIE1A);
sei();
sayac=0;

}

ISR(TIMER1_COMPA_vect){
    
    sayac++;
    
}

void adc_init(){
    
  ADMUX=(1<<ADLAR)|(1<<REFS0)|(1<<MUX0)|(1<<MUX2);// adc pin is selected ADC5 and referrance voltage is VCC
  ADCSRA = 0x83;  // prescalar is used 8
  
}

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

void saga_don(){
    
    PORTC|=(1<<1); // exit sleep mode
    PORTC|=(1<<0); //direction control
    pwm_init();
    
    while(sayac<=199){
        
        OCR1A=PWM_RESOLUTION - 1;
        OCR1B=PWM_RESOLUTION/2-1; // % 50 duty sycle
        
        lcd_gotoxy(11,1);
        printf("%d ",F_PWM);
        
    }
    
    _delay_ms(200);
    
}

void sola_don(){
    
    PORTC|=(1<<1);  // exit sleep mode
    PORTC&=~(1<<0); // direction control
    pwm_init();
    
    while(sayac<=199){
        
        OCR1A=PWM_RESOLUTION - 1;
        OCR1B=PWM_RESOLUTION/2-1; // % 50 duty sycle
        
        lcd_gotoxy(11,1);
        printf("%d ",F_PWM);
        
    }
    
    _delay_ms(200);
    
}



int main(){
    
    DDRD|=(1<<0)|(1<<1)|(1<<2);
    DDRB|=(1<<2)|(1<<4)|(1<<5)|(1<<6)|(1<<7);
    DDRC|=(1<<0)|(1<<1); // pinc0 is for direction, pinc1 is for sleep mode 
    
    adc_init();
    
    lcd_init(LCD_DISP_ON); 
    
    _delay_us(5);

    stdout = stdin = &lcd_str;
    
    lcd_clrscr();
    
    lcd_gotoxy(3,0);
    lcd_puts("MIKROSTEP");
    
    lcd_gotoxy(0,1);
    lcd_puts("Frequency:");


    while(1){
    
    if(bit_is_set(PIND,6)){
        
        saga_don();
        
    }
    
    else if(bit_is_set(PIND,7)){
        
        sola_don();
        
    }
    
    else {
        
        cli();
        TCCR1A=0X00;
        TCCR1B=0X00;
        
        PORTC&=~(1<<1); // for entering sleep mode
        
        while((PIND & 0XC0)==0X00){
            
            F_PWM=Read_adc();
            
            lcd_gotoxy(11,1);
            printf("%d ",F_PWM);
            
        }
        
    }	
    
        
    }		
        
    return 0;
            
    }

Kabil ATICI

while içide
OCR1A=PWM_RESOLUTION - 1;
        OCR1B=PWM_RESOLUTION/2-1; // % 50 duty sycle
       
        lcd_gotoxy(11,1);
        printf("%d ",F_PWM);
olmasına da gerek yok... Bunlarda zaman harcar...

while(sayac<=199){
;
}

şeklinde kullanabilirsin....
ambar7

berkay_91

 faydası olmadı, hatta KESMENİN içinde bile değişiklik yaptım yine olmadı 30 Hz de iyi ama frekans yükseldikçe adım kaçırıyor

ISR(TIMER1_COMPA_vect){
   
    sayac++;

    if(sayaç>=199)
    main();
   
}

Kabil ATICI

öyle olur mu?

Kesme rutinini çağırıyorsun sonra kesme rutini içinde birde ana döngüyü çağırıyorsun. Bu kesinlikle bir hata olur ve yığın taşması meydana gelir...
Bence sıkıntı derleyicinin bu işlemleri yaparken araya bir sürü kod gömmesinden kaynaklanıyor. Bu derleyici çokça  ram bölgesini kullanıyor o yüzden hız arttıkça timer1 kesmesi arasındaki işlemlere yetişilemiyor.
Ne yapabilirim diyorsan  bir şey diyemem, çünkü ben olsam aynı şeyi asm ile yazardım. (bunu yapabilirmisiniz bilemem)
Derleyici 32 tane registerin çoğunu kullanmıyor çünkü.

İkinci alternatif sayma işini donanım ile 74HC590 gibi bir entegre ile saymak sadece çıkışlarını 200 olduğunda bir sinyal üretecek şekilde bir bağlantı oluşturmak ve bununda harici giriş olarak işlemciye girmek.
ambar7

berkay_91

asm ile kod yazmayı bilmiyorum, kodları pwm siz olarak yazdım şimdi daha iyi yüksek hızlarda 1 yada 2 step kaçırıyor oda galiba rampa koymadığım için siz rampa yazarmısınız? bide geçen gün sevo motorla ilgili bi başlık açtım ona kimse cevap vermedi onada bakarbilir misiniz?

#define F_CPU 1000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd.h"

volatile unsigned long frequency,i,sayac=0;

void gecikme(int);
void saga_don();
void sola_don();
void mikro_step_kont();
int Read_adc();
void adc_init();


FILE lcd_str = FDEV_SETUP_STREAM(lcd_putc, NULL, _FDEV_SETUP_WRITE);


void adc_init(){
    
  ADMUX=(1<<ADLAR)|(1<<REFS0)|(1<<MUX0)|(1<<MUX2);// adc pin is selected ADC5 and referrance voltage is VCC
  ADCSRA = (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1);  // prescalar is used 8
  
}

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

void saga_don(){
    
    PORTC|=(1<<1); // exit sleep mode
    PORTC|=(1<<0); //direction control
    PORTB&=~(1<<2);
	
    while(sayac<=400){
        
        PORTB|=(1<<2);
		_delay_us(50);
		PORTB&=~(1<<2);
		
		gecikme(frequency);
		sayac++;
		   
    }
    
}

void sola_don(){
    
    PORTC|=(1<<1);  // exit sleep mode
    PORTC&=~(1<<0); // direction control
	PORTB|=(1<<2);
    
    while(sayac<=400){
        
        PORTB&=~(1<<2);
		_delay_us(50);
		PORTB|=(1<<2);
        
        gecikme(frequency);
		sayac++;
        
    }
    
}

void gecikme(int x){
	
	for(int i=0; i<=x; i++)
	_delay_us(10);
	
}


int main(){
    
    DDRD|=(1<<0)|(1<<1)|(1<<2); // LCD (RS,RW,E)
    DDRB|=(1<<2)|(1<<4)|(1<<5)|(1<<6)|(1<<7); // STEP AND LCD DATA
    DDRC|=(1<<0)|(1<<1); // pinc0 is for direction, pinc1 is for sleep mode 
    
    adc_init();
    
    lcd_init(LCD_DISP_ON); 
    
    _delay_us(5);

    stdout = stdin = &lcd_str;
    
    lcd_clrscr();
    
    lcd_gotoxy(3,0);
    lcd_puts("MIKROSTEP");
    
    lcd_gotoxy(0,1);
    lcd_puts("Frequency:");


    while(1){
    
    if(bit_is_set(PIND,6)){
        
        saga_don();
        
    }
    
    else if(bit_is_set(PIND,7)){
        
        sola_don();
        
    }
    
    else {
		
	   sayac=0;
       
	   PORTB&=~(1<<2); // for closing step pin 
       PORTC&=~(1<<1); // for entering sleep mode
        
        while((PIND & 0XC0)==0X00){
            
            frequency=Read_adc();
            
            lcd_gotoxy(11,1);
            printf("%d ",frequency);
            
        }
        
    }	
    
        
    }		
        
    return 0;
            
    }

Kabil ATICI

    while(sayac<=400){
       
        PORTB&=~(1<<2);
        _delay_us(50);
        PORTB|=(1<<2);
        if (sayac>380)
       frequency++;// (veya  frequency--; programın o bölümünü fazla incelemedim.)
        gecikme(frequency);
        sayac++;
       
    }


volatile unsigned long frequency,i,sayac=0;
long yerine int kullanmak yeterli olması gerekir. Long çok büyük sayılar için kullanılır.

long ; -2,147,483,648 ile 2,147,483,647.
işaretsiz; 2,147,483,647x2 olur...

int ; -32,768 ile  32,767   
işaretsiz;  32,767x2 olur.
ambar7