Picproje Elektronik Sitesi

MİKRODENETLEYİCİLER => Atmel => Konuyu başlatan: berkay_91 - 01 Ocak 2015, 10:51:42

Başlık: A4988 ile adım kontrolü
Gönderen: berkay_91 - 01 Ocak 2015, 10:51:42
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;

}

Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: Kabil ATICI - 01 Ocak 2015, 11:54:09
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..
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: berkay_91 - 01 Ocak 2015, 12:34:43
İş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?
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: Kabil ATICI - 01 Ocak 2015, 12:42:13
Motor hesabına göre evet.20000 Adım=100 tur
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: berkay_91 - 01 Ocak 2015, 12:45:31
teşekkür ederim
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: berkay_91 - 02 Ocak 2015, 13:18:31
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;

}

Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: Kabil ATICI - 02 Ocak 2015, 13:34:27
  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.
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: berkay_91 - 02 Ocak 2015, 21:42:49
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;
           
    }
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: Kabil ATICI - 02 Ocak 2015, 23:01:52
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....
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: berkay_91 - 03 Ocak 2015, 11:43:34
 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();
   
}
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: Kabil ATICI - 03 Ocak 2015, 13:34:25
ö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.
Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: berkay_91 - 03 Ocak 2015, 14:04:04
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;
           
    }

Başlık: Ynt: A4988 ile adım kontrolü
Gönderen: Kabil ATICI - 03 Ocak 2015, 14:33:32
    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.