CCS-C Encoder okuma ve seri iletişim

seri porttan okuttuğunuz şey nedir? Ya da seri porta ne gönderiyorsunuz? Sayı ise kaç baytlık sayı?

Hocam benim değer aralığım 0-900 arası olacak ve bunu aslında VisualBasic ile basit bir arayüzle pic'e göndereceğim.

Ama şu an henüz sistem ve devreyi kurmadığımdan isis'te virtual terminali kullanıyorum.

Burada gönderdiğim sayı en fazla üç basamaklı olacağından değişkenim 16 bit, çünkü 100 de girilebilir 500 de 900 de. Rakam aralığım 0-900 arası hocam.

KbHit() ile bir denemeyi hemen yapacağım.
 
Evet hocam, kod söylediğiniz şekilde doğru sonuçlar veriyor.

Bu durumda ben sizin öneriniz gereği seri porttan gelecek veriyi kesme içinde değil bu şekilde alacağım.

Yardımlarınız için teşekkür ediyorum sağolunuz.

Proje tamamlandığında meydana gelen koduda inşallah burada paylaşacağım, yarın öbür gün bir öğrenci böyle bir şeyle uğraşırsa istifade etsin, üstelik sizin gibi salih hocam gibi yardım sefer arkadaşların da olduğu bir forumda bunun olması o öğrenci için çok faydalı olacaktır.

Takıldığımız yeni bir nokta olursa tekrar yazar başınızı ağırtırız hocam :)

Tekrar teşekkürler.
 
pic_loader arkadaşım halletmişsin tebrikler fakat ben halen uğraşmaktayım :D. Ayrıca bende referans verilerini seri porttan göndereceğim için kodları koyman benim için de çok faydalı olacaktır, teşekkürler.

ze_tr hocam,

Sürekli bacak durumunu okuyup ona göre işlem yapmayacaksınız. while döngüsünde rbif 1 oldu mu diye bakacaksınız.
Bu RB flag change interrupt flag'i ni hangi komutla kontrol ediyoruz,bir türlü bunu bulamadım. ("if (interrrupt_active(int_RB))" 'yi denedim ama olmadı. )

Ayrıca PWM için bana 3 PWM portu (3 dc motor için ayrı ayrı) gerekiyordu, 2 tanesi PIC16F877'de mevcut ,ama eksik kalan 1 port için normal pwm olmayan portlardan , ( herhangi bir output ) pwm uygulayabilir miyim ?

teşekkürler
 
Son düzenleme:
JüKusura bakmayın,
datasheet'e bakmadan bazı şeyleri hatalı vermişim. Özür.

Seri porttan bilgi geldiği zaman rcif bayrağı aktif olur. KbHit() fonksiyonu bu bayrağın değerini geri gönderir.

Portb durum değişimi bayrağı rbif dir. Portb <4:7> arası bacakların durumu değiştiğinde 1 olur.

seri porttan bilgi geldimi diye sorgulamak için: if(KbHit()){...geldiğinde yapılacak işler...}

portb durum değişikliği için doğrudan flagi sorgulayabilirsiniz. if(rbif) {...durum değiştiğinde yapılacak işler...dummy=input_b();... rbif=0;}

rbif tanımı: #bit rbif=GETENV( biti....); // GETENV için help menüsünden bit tanımı için kullanılan şekline bakın).

Hangi registerin hangi biti olduğunu biliyorsanız doğrudan #bit rbif=reg.bit şeklinde de tanımlayabilirsiniz. GETENV kullanmanız kodun taşınabilirliği açısından daha uygun.

emulasyonlu pwmi sağlıklı çalıştıramayabilirsiniz. Diğer iki pwm modülünde de periyodlar aynı kalır. 18F serisi yeni mcularda pwm modüllerin timerları ayrılmış olduğundan onlarda farklı periyot kullanabilirsiniz.
 
pic_loader arkadaşım halletmişsin tebrikler fakat ben halen uğraşmaktayım :D. Ayrıca bende referans verilerini seri porttan göndereceğim için kodları koyman benim için de çok faydalı olacaktır, teşekkürler.

Ne demek kardeşim, tabiki paylaşacağım burada bana çok yardımcı olundu.

Aslında henüz başardığım bir şey yok, inşallah başaracağım.

Bu arada ze_tr hocama bir şey daha sormak istiyorum, set_pwm1_duty'ye float bir değer atayabiliyorum isiste bir hata almıyorum ama acaba fonksiyon bu değişkeni tamsayıya mı çeviriyor bunu bilmiyorum.

Bu konuda beni aydınlatabilir misin hocam?

Birde hocam ben setup_timer_2'ye nasıl bir değer atamalıyım ki frekansın 500 hz olmasını sağlayayım.

Mesela setup_timer_2(T2_DIV_BY_16,124,1);

dediğimde bunu garantiler miyim hocam?
 
set_pwm1_duty argüman tanımı integer olduğundan float sayı integera dönüştürülür ve fonksiyona gönderilir.

CCS nin kurulduğu klasörde örnekler var. ex_pwm e bakarsanız, 10 MHz kristal için 1.2 kHz lik ayar aşağıdadır. bu ayar 4 Mhzlik kristalde yaklaşık 500 Hz e karşılık gelir. Aşağıdaki commentlere göre hesaplayın. 127 değil belki 125 vs. rakamı kullanmanız gerekebilir. ISIS'te pwm çıkışına osiloskop bağlayıp periyodu ölçün.

Kod:
   char selection;
   unsigned int8 value;

   printf("\r\nFrequency:\r\n");
   printf("    1) 19.5 khz\r\n");
   printf("    2) 4.9 khz\r\n");
   printf("    3) 1.2 khz\r\n");

   do {
     selection=getc();
   } while((selection<'1')||(selection>'3'));

   setup_ccp1(CCP_PWM);   // Configure CCP1 as a PWM

          //   The cycle time will be (1/clock)*4*t2div*(period+1)
          //   In this program clock=10000000 and period=127 (below)
          //   For the three possible selections the cycle time is:
          //     (1/10000000)*4*1*128 =  51.2 us or 19.5 khz
          //     (1/10000000)*4*4*128 = 204.8 us or 4.9 khz
          //     (1/10000000)*4*16*128= 819.2 us or 1.2 khz

   switch(selection) {
     case '1' : setup_timer_2(T2_DIV_BY_1, 127, 1);
                break;
     case '2' : setup_timer_2(T2_DIV_BY_4, 127, 1);
                break;
     case '3' : setup_timer_2(T2_DIV_BY_16, 127, 1);
                break;
   }
 
Anladım hocam, frekans değerini 4.000.000 kabul edersem setup_timer_2(T2_DIV_BY_16,124,1); satırı işimizi görüyor, belki dediğiniz gibi 125 yada artı eksi bir bir değer olacak bu, artık hassasiyete göre.

Teşekkür ederim.
 
Yeniden selamlar,

Sayın ze_tr ,

Biraz çok zaman oldu ama söylediğiniz gibi rbif komutunu kullandım ve o kısmı hallettim çok teşekkürler ediyorum.

Şimdiki sorunum ise seri port iletişimi ile ilgili. Benim yapmak istediğim pic'in donanımsal uçları ( c6 ve c7 ) kullanarak 3 adet sayı değerini bilgisayardan göndermek ve program içinde bir değişkene aktarmak . Ancak bu üç değişkenin girişleri tamamlandıktan programım çalışmaya başlamalı ve sayı değerleri int32 olmalı.

Biraz araştırdım ve gönderilen verilerin kesme içerisinde sadece bir değişkene atıldığı uygulamalar gördüm. int32 olarak ve üçünü birden nasıl gönderebilirim? Örnek,benzer kod varsa verebilir misiniz ?

Teşekkürler .
 
PC den sayıyı nasıl gönderdiğiniz önemli. Text box tan alıp doğrudan gönderirseniz ascii karşılığı gider. Yani sayınız 123456 gibi bir şey ise, text boxtan alıp, integera dönüştürmediğinizde seri porttan sırasıyla '1', '2','3','4','5','6' karakterleri gider (6 bayt). Sayıya dönüştürdüğünüzde ise 4 baytlık hex karşılığı gider.

mcu da sayıyı okutmanın bir kaç değişik yöntemi var. Yalnız seri port little endian haberleşme yapıyordu diye hatırlıyorum ve ona göre bilgi vereceğim.

union say1 {int32 a, char b[4]} ;
union say2 {int32 a, char b[4]} ;
union say3 {int32 a, char b[4]} ;
...
say1.b[0]=getch();
say1.b[1]=getch();
say1.b[2]=getch();
say1.b[3]=getch();

say2.b[0]=getch();
say2.b[1]=getch();
say2.b[2]=getch();
say2.b[3]=getch();

say3.b[0]=getch();
say3.b[1]=getch();
say3.b[2]=getch();
say3.b[3]=getch();

MCU da kullanacağınız 32 bitlik sayılar say1.a, say2.a, say3.a dır.

başka bir yol:
int32 a,b,c;
*(&a ) = getch();
*(&a+1) = getch();
*(&a+2) = getch();
*(&a+3) = getch();

*(&b ) = getch();
*(&b+1) = getch();
*(&b+2) = getch();
*(&b+3) = getch();

*(&c ) = getch();
*(&c+1) = getch();
*(&c+2) = getch();
*(&c+3) = getch();

Bu ikincisi standart değil. ama CCS de kullanılıyor.

Aslında hatalı veri gidip gitmediğini kontrol etmeniz de fayda var. Her dört baytın arkasından bir checksum gönderebilirseniz, mcu tarafında da checksum tutuyor ise ok geri bildirimi gönderirseniz daha gğvenli bir haberleşme yapmış olursunuz.
 
Arkadaşlar merhabalar.

Nihayet projemizi tamamladık ve başarıyla çalıştırdık, söz verdiğim gibi kodu burada paylaşacağım ve bana fikirleri ile yol gösteren yardımcı olan herkese tekrar teşekkür edeceğim.

Paylaşacağım kod chili arkadaşım gibi arkadaşlara da yardımcı olacaktır.

Seri haberleşme uçlarına hyper terminalden girilen 4 parametreye göre sistem setpoint değerine kol gelene dek pwm sinyalleri üretiyor ve sonrasında kullanıcıdan değer beklemeye devam ediyor.

Kod:
#include <16f877.h>

#device adc=8
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                      //Low power osc < 200khz
#FUSES NOPUT                    //No Power Up Timer
#FUSES PROTECT                  //Code protected from reads
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD

#use delay(clock=20000000)
#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7,stop=1,parity=n) // RS232 protokolu 9600 bit/sn baud hizyida
                                                             // TX pin C6, RX pin C7 uclari
                                                             // parity biti yok, stop biti 1

#use fast_io(b)

#include <stdlib.h>
#include <math.h>
#include <string.h>

signed int16 pwmoutput=0;
float32 Dt,apoint,pwmfloat,izin,referans_deger,Kp,Ki,Kd,onceki_hata,error,integral,derivative;

int8 s1[4],s2[4],s3[4],s4[4];
int8 girdi_say=0;
int8 girdi;
int16 Bekleme;

#int_ext                   // Dis kesme
void rbo_kesmesi () {
   
   if(input(pin_b5))
      apoint=apoint-0.1;
   else
      apoint=apoint+0.1;
  
      
}

void temizle(){

s1[0]="";
s1[1]="";
s1[2]="";
s1[3]="";
s2[0]="";
s2[1]="";
s2[2]="";
s2[3]="";
s3[0]="";
s3[1]="";
s3[2]="";
s3[3]="";
s4[0]="";
s4[1]="";
s4[2]="";
s4[3]="";
}

void oku(){
 
 girdi=getch();
  
 if(strlen(s1)==0)
  s1[0]=girdi;
 else if(strlen(s2)==0)
  s2[0]=girdi;
 else if(strlen(s3)==0)
  s3[0]=girdi;
 else if(strlen(s4)==0)
  s4[0]=girdi;
 
 if(girdi==13){
   
   girdi_say++;
    
    if(girdi_say>5){
   
      printf("\r\n");
      printf("\r\n");
      printf("\r");
      printf("\r  Kontrol Parametrelerini tekrar girmek icin Enter`a basiniz...");
      girdi_say=0;
   }
  
   
   strcat(s1,s2);
   strcat(s1,s3);
   strcat(s1,s4);
           
   if(girdi_say==1){
      izin=atof(s1);
      temizle();
      printf("\r  Referans Aci Degeri  :\n");   
            
   } else if(girdi_say==2){
      referans_deger=atof(s1);
      temizle();
      printf("\r  Kp: \n");
      
   } else if(girdi_say==3){
      
      Kp=atof(s1);
      temizle();
      
      printf("\r  Ki: \n");
      
   } else if(girdi_say==4){
      
      Ki=atof(s1);
      temizle();
      
      printf("\r  Kd: \n");

   } else if(girdi_say==5){
      
      Kd=atof(s1);
      temizle();
      
       
      printf("\r  Girilen Degerler \n");
      printf("\r  **************** \n");
      printf("\r  Referans Aci Degeri  : %f \n", referans_deger);
      printf("\r  Kp Giriniz           : %f \n", Kp);
      printf("\r  Ki Giriniz           : %f \n", Ki);
      printf("\r  Kd Giriniz           : %f \n", Kd);
     
         }
        
 }
    
delay_ms(100);
}

/********* ANA PROGRAM FONKSYYONU********/
void main (){
   setup_psp(PSP_DISABLED);        
   setup_timer_1(T1_DISABLED);     
   setup_timer_2(T2_DISABLED,0,1); 
   setup_adc_ports(NO_ANALOGS);    
   setup_adc(ADC_OFF);             
   setup_CCP2(CCP_OFF);            
   
   setup_ccp1(CCP_PWM);                // CCP1 birimi PWM cikis icin ayarlandi
   setup_timer_2(T2_DIV_BY_16,255,1);  // Timer2 ayarlari yapiliyor
   set_pwm1_duty(pwmoutput);                   //Saykil set ediliyor
   
   set_tris_b(0b00110001); //RB0 Encoder A
                                    //RB5 Encoder B  
                                     
   output_b(0x00);
      
   printf("\r  Bitirme Projesi \n");
   printf("\r  Propeller Kumandali PID Sistem Kontrolu \n");
   printf("\r  Ocak 2010 \n");
   printf("\r");
   printf("\r  Kontrol Parametrelerini girmek icin Enter`a basiniz...");
   
   
   ext_int_edge(H_TO_L); //Kesme yukselen kenarda olacak
   enable_interrupts(int_ext);
   enable_interrupts(GLOBAL);  // Aktif edilen tum kesmelere izin veriliyor
   
   /****BASLANGIC DEGERLERINI ATA****/
   onceki_hata=0;
   integral=0;
   /****BASLANGIC DEGERLERINI ATA****/
     
     
     Dt=0.25; // ms degeri
     Bekleme=(Dt*1000);
     
     
  while(1) {
   
    if(KbHit()) 
       oku();
      
      if(girdi_say==5){
                 
         error=(referans_deger-apoint);
         integral=integral+(error*Dt);
         derivative=(error-onceki_hata)/Dt;
         pwmfloat=(kp*error)+(Ki*integral)+(Kd*derivative);

         pwmoutput=pwmfloat+450;
         onceki_hata=error;
         
         if (pwmoutput>1023)
             pwmoutput =1023;
             
             if (pwmoutput<0)
             pwmoutput =0;
         
         set_pwm1_duty(pwmoutput);
         
         delay_ms(Bekleme);
         
         printf("\r  PWM Duty ( 0 - 1023 ) : %Ld          Guncel Konum: %f \n", pwmoutput, apoint);
      }
      
      
    }
 }
 

Forum istatistikleri

Konular
130,047
Mesajlar
932,506
Kullanıcılar
453,022
Son üye
nibil

Yeni konular

Geri
Üst