PIC16F877A ile servo motor sürme

Başlatan puremonday, 15 Aralık 2010, 17:18:50

puremonday

herkese iyi çalışmalar;
pic16f877A ile bir servo motor sürme devresi kurdum. devrenin çalışması şu şekilde;
potansiyometre ile analog giriş alıyorum bu girişin değişimine göre servo motorun konumu değişiyor.  0V  da -90 derecede  5V da +90 derecede duruyor.

proteusta devreyi oluşturdum CCS C de de kodları yazdım gayet istediğim gibi çalışıyor, fakat gerçekte kurdum aynı kodları yükledim istediğim gibi çalışmadı, tek bir pulse değeri görünüyor potansiyometrenin değişimine cevap vermiyor. sorun ne olabilir kodlarda yada donanımda eksik olan ne olabilir. devre ve kodlar aşağıda bulunmaktadır. yardımcı olabilicek arkadaşlara şimdiden teşekkür ederim ...


devre;
[IMG]http://i1012.hizliresim.com/2010/12/15/3365.jpg[/img]

kodlar;
#include <16f877.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)
#use fast_io(a)
#use fast_io(c)
#define use_portb_lcd TRUE
#include <lcd.c>

#byte ADRESH = 0x1E
#byte ADRESL = 0x9E
#byte ADCON0 = 0x1F
#byte ADCON1 = 0x9F

   unsigned long int digdata;
   int pwm=0;
   int duty=0;
   
#int_timer0
   void kesme()
   {
      set_timer0(227);
        
      if (pwm==0) output_high(pin_c3);
      
      if (pwm>=duty) output_low(pin_c3);
      
      pwm++;
      output_high(pin_c2);
      if (pwm>=140) pwm=0;
   }
#int_AD
   void ADC_kesme()
   {
   output_high(pin_c1);
   }
   
   //****MAIN PROGRAM******
   
   void main()
   {
      setup_psp(PSP_DISABLED);
      setup_timer_1(T1_DISABLED);
      setup_timer_2(T2_DISABLED,0,1);
      setup_CCP1(CCP_OFF);
      setup_CCP2(CCP_OFF);
      
      set_tris_a(0b11111111);
      set_tris_c(0b00000000);
      
      ADCON0=0b00001101;
      ADCON1=0b00000000;
      
      setup_adc(ADC_CLOCK_INTERNAL);
      setup_adc_ports(ALL_ANALOG);
      
      setup_timer_0(RTCC_INTERNAL | RTCC_DIV_4);
      set_timer0(227);
      
      enable_interrupts(int_timer0);
      enable_interrupts(int_AD);
      enable_interrupts(global);
      
      output_c(0b00000000);
      
      lcd_init();
      
      
      while(1)
      {
         set_adc_channel(1);
         delay_us(20);
         digdata=read_adc();
         
        if ((digdata>=0) && (digdata<=93)) duty=5;
        if ((digdata>=94) && (digdata<=187)) duty=6;
        if ((digdata>=188) && (digdata<=281)) duty=7;
        if ((digdata>=282) && (digdata<=375)) duty=8;
        if ((digdata>=376) && (digdata<=469)) duty=9;
        if ((digdata>=470) && (digdata<=563)) duty=10;
        if ((digdata>=564) && (digdata<=657)) duty=11;
        if ((digdata>=658) && (digdata<=752)) duty=12;
        if ((digdata>=753) && (digdata<=846)) duty=13;
        if ((digdata>=847) && (digdata<=940)) duty=14;
        if ((digdata>=941) && (digdata<=1023)) duty=15;
         
         printf(lcd_putc,"\fDigData=%lu",digdata);
         delay_ms(50);
        
       
         
      }
   }
     

JKramer

Tam inceleyemedim ama gözüme çarpan:

setup_adc(ADC_CLOCK_INTERNAL); yerine

setup_adc(ADC_CLOCK_DIV_8); // Bu 16F877'e göre, 16F877A'nın kataloğunu indirmedim "Selecting the A/D Conversion Clock" bölümünü kontrol edersiniz.

Bir de ya doğrudan ADCONX kullanın ya da setup_adc_.... fonksiyonlarını.

Tagli

#2
setup_adc(ADC_CLOCK_INTERNAL);

JKramer, merak ettim, bu satırın nasıl bir sakıncası var ki? Belki dönüşüm işleminin mümkün olandan biraz daha yavaş yapılmasına sebep olabilir ama başka bir etkisi olmaz diye düşünüyorum.

Simulasyon çalıştığına göre sorunu donanımda aramak lazım. Fiziksel olarak kurduğun devrenin şemasını, fotoğrafını falan eklersen yorum yapılabilir belki.
Gökçe Tağlıoğlu

puremonday

devru budur;
devredeki ledlerden sağdaki timer kesmesi gerçekleştiğinde soldakide adc çevirimi yapıldığında yanıyor. yani kesme ve adc çevirim oluşuyor fakat direnci değiştirdiğimde üretilen pwm de bi değişme olmuyor ...



ipek

877A olarak belirtmişsin simulasyonda 877 gözüküyor analog ve komparator olarak bu iki entegre

arasında minik farklar var bu yüzden olabilir.....nasıl derledinse öyle olsun
birde isiste hata mesajı alıyormusun yani renk yeşilmi yoksa sarımı burada komparator uyarısı alıyormusun.????

Everlast

Timer kesmen kaç ms lik?

lcd de yazdırdıgın değerler pot la oynayınca güncelleniyor mu?

bu sorulara cevap verebilirsen daha rahat yardımcı olabiliriz...
- - - Check it Out - - -

muhittin_kaplan

RC servolar için frekansın 50Hz peryod 20ms olamalı.(proteus gözardı ediyor) -90 için 0,5ms duty,+90 için 2,5ms duty gerekli. merkez için 1,5ms.

puremonday

Alıntı yapılan: ipek - 16 Aralık 2010, 04:13:57
877A olarak belirtmişsin simulasyonda 877 gözüküyor analog ve komparator olarak bu iki entegre

arasında minik farklar var bu yüzden olabilir.....nasıl derledinse öyle olsun
birde isiste hata mesajı alıyormusun yani renk yeşilmi yoksa sarımı burada komparator uyarısı alıyormusun.????

evet isisdeki 877 ama derlerken 877A ya göre derliyorum simulasyonu çalıştırdığımda hta mesajı almıyorum bütün mesajlar yeşil

puremonday

Alıntı yapılan: Everlast - 16 Aralık 2010, 08:59:51
Timer kesmen kaç ms lik?

lcd de yazdırdıgın değerler pot la oynayınca güncelleniyor mu?

bu sorulara cevap verebilirsen daha rahat yardımcı olabiliriz...

evet analog girişlerin dijital değerlerine göre (0 ile 1023 değerleri arasında)  11 tane duty değeri tanımladım yani motoru potu değiştirerek 11 farklı açıya getirebiliyorum simulasyonda bunu net bir şekilde yapıyorum

puremonday

Alıntı yapılan: muhittin_kaplan - 16 Aralık 2010, 09:26:41
RC servolar için frekansın 50Hz peryod 20ms olamalı.(proteus gözardı ediyor) -90 için 0,5ms duty,+90 için 2,5ms duty gerekli. merkez için 1,5ms.
(Resim gizlendi görmek için tıklayın.)

evet ürttiğim pwm değerleri bu şelikde isis da bunlar net bi şekilde görülüyor fakat gerçek devrede gördüğüm tek bir pwm değeri var o da şu ;


logic 1 seviyesini pot u değiştirerek değiştirmek istiyorum fakat değişmiyor.

iyildirim

#10
PIC16  serisi mcu ları bilmem ama gördüğüm kadarı ile ;
kristal vs. hız gibi değerlere göre doğru yazıldı ise main deki sonsuz döngüde  ki delay_ms(50);  den dolayı max 20Hz liK bir PWM frekansı üretiliyor. Servonun doğru çalışması için en az 50Hz gerekir.
delay_ms(50);  satırı  delay_ms(20);   olmalı.

PWM duty si %4-5 ile %10-12 civarında olmalı.  Duty değişkenine atanan 5 ile 15 arasındaki değerler değişkenin kesme içerisindeki kullanım şekline göre yüzde olarak duty ifade ediyor. Bu durumda  set_timer0(227);  satırının dutynin max değeri de gözönüne alınınca 143 us ye karşılık geldiğinden emin olunmalı. 

Diğer yol da bu kadar uğraşmayıp CCP modülünü kullanmak. Timerı 20ms ye ayarlayıp,  timer değeri = 20 ms hesabından ADC max değerini 2 ms olacak şekilde bir çarpan/bölen hesaplayıp ADC den okunan değerleri bu değer ile çarpıp/bölüp CCP modülünde kullanmak yeterli. 


Edit
logic 1 seviyesi değişmeyecek, logic 1 'in genişliği-süresi değişecek. İki logic bir'in yükselen kenarları arasında 20ms olacak, darbe genişlikleri 1-2 ms olacak.


Everlast

Alıntı yapılan: puremonday - 16 Aralık 2010, 14:10:27
Alıntı yapılan: Everlast - 16 Aralık 2010, 08:59:51
Timer kesmen kaç ms lik?

lcd de yazdırdıgın değerler pot la oynayınca güncelleniyor mu?

bu sorulara cevap verebilirsen daha rahat yardımcı olabiliriz...

evet analog girişlerin dijital değerlerine göre (0 ile 1023 değerleri arasında)  11 tane duty değeri tanımladım yani motoru potu değiştirerek 11 farklı açıya getirebiliyorum simulasyonda bunu net bir şekilde yapıyorum

ISIS seni yanıltır neden ISI i baz alıyorsun demek istediğim pratik devrende pot değişince lcd ye değer yazdırıyorsun pot değeri değişin ce LCD de neler görüyorsun?
ADC den okudugun değeri art arda 10 kere okuyup bu 10 değerin ortalamasını alırsan daha kesin bir değer görebilirsin potu çevirirken oluşabilcek gerilim dalgalanmalarına karşı daha düzgün sonuç alırsın.


Skoptaki görüntüden 20 ms lik peryot tutuyor gibi.   
delay_ms(50);   yerine for( i = 0; i < 10000; i++){ for( j = 0; j < 10000; j++) } gibi bir döngü koyar mısın CCS delay fonksiyonlarında diğer interruptları görmüyor.  bunları dikkate alıp denemisin?
- - - Check it Out - - -

acocrw

arkdaslar merhaba ben servo motoru inverter olmadan 1'er derecelik açılarla nasıl çevirebilirim bilenimiz varsa lütfen yardımcı olsun.

teşekkürler:)

34sileli

Merhaba
acaba servo motorlar şu şekilde mi çalışıyor

servoya mesela 40 derecelik açı için 1ms lik bi değer gönderdik 40 dereceye geldi ee sonra bu sinyali tekrar tekrar göndermemiz gerekiyor mu yoksa açıyı değiştirmek istediğimzde mi tekrar sinyal göndermemiz gerekiyor

sefa23

arkadaşlar devre şemeasını göremiyorum yardımcı olabilmek isterim ama göremşyorum pic devresini