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;
}
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..
İş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?
Motor hesabına göre evet.20000 Adım=100 tur
teşekkür ederim
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;
}
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.
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;
}
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....
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();
}
ö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.
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;
}
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.