pic 18f452 Kodlarda Hata mı Var?

Başlatan mrtkn, 02 Mayıs 2015, 01:24:01

mrtkn

Merhabalar,
Pic 18f 452 kullanarak uzaklık sensoru ile motor sürme devresi yapmaya calısıyorum.
Yani uzaklık azaldıkca motor yavaslıcak arttıkca hızlanıcak. Ve lcd de mesafeyi yazdırmaya calısıyorum.
Gelin görün ki devre proteusta simulasyonda doğru çalışırken boardda çalıştıramıyorum. Elimde 3 tane pic var 3 üyle de denedim.Bi göz atabilir misiniz?
Not. Proteus 8 kullanıyorum, Kodlar CCS C kodları.
Gerekli tüm dosyalar ektedir.

Teşekkürler

rodyum

#1
proteus CONFIG ayarlarına bakmaz. buna dikkat et.
yazılımda ise timer0 ADC kesmesini aktif etmişin ama kesme fonksiyonunu eklememişsin. madem kullanmayacaksın ozaman neden açık bıraktın?
dahası, ADC dönüşümünü 8 bit olarak belirlemişsin ama hesapları 10 bite göre yapmışın.
birde, her "if" komutunun başına neden sürekli "else" ekledin? bunu bilerek mi yaptın?

mrtkn

#2
Merhabalar rodyum,
Öncelikle ilgin için teşekkürler.
CCS C kullanmaya yeni başladım,bu projeyi yapmak için Altaş Yayınları'nın kitabından bulduğum 4-5 projeyi birleştirdim ancak bu çıktı;)
Timer0 için bişey yazmadım aslında ama aktif olup olmadığını bilmiyordum nereden kapatabilirim?
ADC için de örneklerde 8 kullanılmıştı ben de öyle denemeye karar verdim.Hatayı nasıl düzeltebilirim?
Else yapısı hatalı mı olmuş?
Teşekkürler.

rodyum

pardon, gece dalgınlığıma geldi. timer0 değilde ADC kesmesini aktif etmişin.
şu kodları kaldır:
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);


ADC 10bit yapmak için şöyle yaz:
#device ADC=10


else komutlarını gerekmediği sürece çok kullanma yoksa diğer komutları atlayabilir.

mrtkn

Dediklerinizi yaptım.Bu else olayını nasıl ayarlayabilirim?Else kısımlarını sileyim mi?
Bir de kod genel olarak mantıklı görünüyor mu?Config ayarlarında bir hata var mı?
Teşekkürler.

rodyum

#5
program genelinde başka sorun göremedim ama benim bilgisayardan dolayı sağlıklı simülasyon yapamıyorum.

else komutlarını sürekli arka arkaya kullanınca koşullardan biri doğru ise sadece onu işler ve diğerlerini atlar ama fazla kullanırsan Stack taşmasına neden olabilir yada komutlardan birini görmezden gelir.
eğer if koşullarını arka arkaya yazarsan buseferde hepsini sırayla kontrol eder ve gecikmeye neden olur. bunların yerine bir kontrol ana döngü yapıp doğru koşul işlemesinden sonra "break" ile bu ana döngüden direk çıkabilirsin.

mrtkn

Hocam else if olan yerleri swich case lerle yazarak gecikmeyi gidercm, peki config ayarları dogru mu???

rodyum

swich case'gerek yok. else'lerin hepsini kaldır sonra bütün if'leri tek bir woid döngüsüne yerleştir ve her if koşul parantezlerinin sonuna break ekle.
örnek:
while(TRUE)
   {           
         while(TRUE)
      {
        if(input(PIN_C1)){output_high(PIN_B1);break;}
        if(input(PIN_C2)){output_high(PIN_B2);break;}
        if(input(PIN_C3)){output_high(PIN_B3);break;}
        if(input(PIN_C4)){output_high(PIN_B4);break;}
      }     
      if(input(PIN_C7)){output_b(0x00);}
   }

Config ayarları doğru gibi sadece LVP yi NOLVP yaparsan daha iyi olur.ayrıca programlama sırasında bu ayarları doğru aktarılmasıda önemlidir. bazı programlayıcılar sorun çıkarabiliyor.

mrtkn

dediğiniz gibi sadece if ile döngü oluşturarak kodu düzenledim. aşağıda yazdığım kısma kadar işi getirdim ancak bi sorun var , motor istikrarlı çalışmıyor bi göz atabilir misiniz ?
teşekkürler


#include <18F452.h>
#device ADC=10
#include<math.h>
/*#FUSES NOWDT
#FUSES WDT128
#FUSES NOBROWNOUT
#FUSES NOLVP   */
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT1                     //Watch Dog Timer uses 1:1 Postscale
#FUSES HS                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOOSCSEN                 //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOCPD                    //No EE protection
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB
#use delay(crystal=20000000)
/*#use fast_io(a)*/
#use fast_io(c)
#use fast_io(d)
#define LED PIN_A1
#define DELAY 100
#define dist_10cm 2.30
#define dist_12cm 1.87
#define dist_14cm 1.66
#define dist_16cm 1.49
#define dist_18cm 1.36
#define dist_20cm 1.25
#define dist_22cm 1.16
#define dist_24cm 1.08
#define dist_26cm 1.02
/*#define use_portb_lcd TRUE
#include<lcd.c>*/

unsigned long int bilgi, i;
double voltaj, uzaklik;
float y=-1.267, x=26.707;
     
void main()
{
setup_psp(PSP_DISABLED);
setup_timer_1(T1_DISABLED);
setup_CCP2(CCP_OFF);
set_tris_a(0x01);
set_tris_c(0x00);
set_tris_d(0x00);
output_d(0x00);
setup_CCP1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1,128,1);

set_pwm1_duty(i);
setup_adc(adc_clock_div_32);
setup_adc_ports(AN0);   
set_adc_channel(0);
delay_us(20);
   while(true)
   {
   kopek:
   output_low(LED);
   delay_ms(DELAY);
   output_high(LED);
   delay_ms(DELAY);
   
   bilgi=read_adc();
   voltaj=(0.0048828125*bilgi);
   uzaklik=x*pow((voltaj),(y))*10;
   delay_ms(100);
   
   i=uzaklik*4.92;
   set_pwm1_duty(i);
         
         while(TRUE)
      {
        if(voltaj >dist_10cm)
        {
        break;}
        if(voltaj < dist_10cm && voltaj > dist_12cm)
        { output_d(0x01);;break;}
        if(voltaj < dist_12cm && voltaj > dist_14cm)
        { output_d(0x03);;break;}
        if(voltaj < dist_14cm && voltaj > dist_16cm)
        { output_d(0x07);;break;}
        if(voltaj < dist_16cm && voltaj > dist_18cm)
        { output_d(0x0F);;break;}
        if(voltaj < dist_18cm && voltaj > dist_20cm)
        { output_d(0x1F);;break;}
        if(voltaj < dist_20cm && voltaj > dist_22cm)
        { output_d(0x3F);;break;}
        if(voltaj < dist_22cm && voltaj > dist_24cm)
        { output_d(0x7F);;break;}
        if(voltaj < dist_24cm && voltaj > dist_26cm)
         { output_d(0xFF);;break;}
        if(voltaj <dist_26cm)
         {
         break;}
      }
       

      goto kopek; 
     
   }

}

rodyum

PWM frekansını yüksek tutmuşun. bunu biraz düşürüp dene bakalım.
setup_timer_2(T2_DIV_BY_16,77,1);


bu arada, diğer hesaplamarı doğru yaptığına eminmisin?

mrtkn

rodyum, dediğiniz gibi timer ayarıda yaptım ancak şöyle bir sorun var motor aşağıdaki link teki gibi çalışıyor.
birde hesaplamayı Calculated_Range (cm) = 26.707 x Analogue_Voltage ^-1.267 matematiksel formülüne göre yaptım. bu hesalama Sharp IR Distance Sensor (GP2Y0A21YK0F) sensörünün matematiksel hesabı.

View My Video

son durumda kod ları şöyle yaptım

#include <18F452.h>
#device ADC=10
#include<math.h>
/*#FUSES NOWDT
#FUSES WDT128
#FUSES NOBROWNOUT
#FUSES NOLVP   */
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT1                     //Watch Dog Timer uses 1:1 Postscale
#FUSES HS                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOOSCSEN                 //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOCPD                    //No EE protection
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB
#use delay(crystal=20000000)
#use fast_io(a0)
#use fast_io(c)
#use fast_io(d)
#define LED PIN_A1
#define DELAY 100
#define dist_10cm 2.30
#define dist_12cm 1.87
#define dist_14cm 1.66
#define dist_16cm 1.49
#define dist_18cm 1.36
#define dist_20cm 1.25
#define dist_22cm 1.16
#define dist_24cm 1.08
#define dist_26cm 1.02

/*#define use_portb_lcd TRUE
#include<lcd.c>*/

unsigned long int bilgi, i;
double voltaj, uzaklik;
float y=-1.267, x=26.707;
     
void main()
{
setup_psp(PSP_DISABLED);
setup_timer_1(T1_DISABLED);
setup_CCP2(CCP_OFF);
set_tris_a(0x01);
set_tris_c(0x00);
set_tris_d(0x00);
output_d(0x00);
setup_CCP1(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,77,1);

set_pwm1_duty(i);
setup_adc(adc_clock_div_32);
setup_adc_ports(AN0);   
set_adc_channel(0);
delay_us(20);
   while(true)
   {
   basa:
   output_low(LED);
   delay_us(20);
   output_high(LED);
   delay_us(20);
   bilgi=read_adc();
   voltaj=(0.0048828125*bilgi);
   uzaklik=x*pow((voltaj),(y));
   
        if(voltaj >dist_10cm)
        {
        i=0;
        set_pwm1_duty(i);
        break;}
        if(voltaj < dist_10cm && voltaj > dist_26cm)
        {
        i=uzaklik*2.96;
        set_pwm1_duty(i);
        break;}
        if(voltaj <dist_26cm)
        {
        i=0;
        set_pwm1_duty(i);
        break;}
   goto basa; 
     
   }

}

rodyum

#11
Arkadaşım, kodlarını şuanda test edemiyorum ama her düzenlemede yeni hatalar yapıyorsun.
bence aşama aşama gidersen daha sağlıklı sonuç alırsın. hepsini aynı anda çalıştırmaya çalışma.

1- öncelikle sensörden okuduğun değeri sadece LCD ekrana yazdır ve doğru sonuç çıkıyor mu ona bak.
2- ADC değeri direk pwm çıkışına vererek pwm kontrolünü yap.
3- herşey yolunda ise "if" kontrollerini en sona eklersin.

şuanki gördüğüm hata, "if" komutlarının sonuna "break" eklemişin ama hepsini toplu halde bir döngüye sokman gerekir aksi halde program ana döngüden çıkar. yukarıda verdiğim örneği dikkatli incele. eğer bu döngü içindeki koşulların hiç biri doğru değilse sürekli o döngüde kalır. bunu önlemek için döngü sonuna birtane "break" ekleyebilirsin.
dahası C dilinde "goto" komutunu kullanmak sakıncalıdır. bunun yerine "while(true)" veya "for(;;)" döngüsü eklersen daha iyi olur.

mrtkn

rodyum dediğim gibi öncelik olarak uzaklığı ölçüp lcd ye yazdırmaya çalıştım. çok iyi çalışıyor aşağıdaki kodu yazdım

#include <18F452.h>
#device ADC=10
#include<math.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT1                     //Watch Dog Timer uses 1:1 Postscale
#FUSES HS                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOOSCSEN                 //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOCPD                    //No EE protection
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB
#use delay(crystal=20000000)

#define LED PIN_A1
#define DELAY 100

#use fast_io(a)

#define use_portb_lcd TRUE
#include<lcd.c>

unsigned long int bilgi;
double voltaj, uzaklik;
float y=-1.267, x=26.707;
     
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(0x01);
setup_adc(adc_clock_div_32);
setup_adc_ports(AN0);
lcd_init();
set_adc_channel(0);
delay_us(20);
printf(lcd_putc,"Uzaklik=");
   
   while(true)
   {
   output_low(LED);
   delay_ms(DELAY);
   output_high(LED);
   delay_ms(DELAY);
   
   bilgi=read_adc();
   voltaj=(0.0048828125*bilgi);
   uzaklik=x*pow((voltaj),(y));
   lcd_gotoxy(10,1);
   printf(lcd_putc,"%5.1fcm",uzaklik);
   delay_ms(100);
   }

}



daha sonrasındaki adımda uzaklık sensörüyle pwm kontrolü ayarlamaya çalıştım aşağıdaki kodu yazdım ama sonuç alamıyorum, yani lcd çalışıyor ama uzaklık yazısı haricinde başka bişey görünmüyor bide motor hep aynı hızda dönüyor ayrıca 7805 entegresi ısınıyor. sizin yorumunuz nedir. teşekkürler...

#include <18F452.h>
#device ADC=10
#include<math.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT1                     //Watch Dog Timer uses 1:1 Postscale
#FUSES HS                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOOSCSEN                 //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOCPD                    //No EE protection
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB
#use delay(crystal=20000000)

#define LED PIN_A1
#define DELAY 100

#define dist_10cm 2.30
#define dist_26cm 1.02

#use fast_io(a)
#use fast_io(c)
#define use_portb_lcd TRUE
#include<lcd.c>

unsigned long int bilgi;
double voltaj, uzaklik, i;
float y=-1.267, x=26.707;
     
void main()
{
setup_psp(PSP_DISABLED);
setup_timer_1(T1_DISABLED);
setup_CCP2(CCP_OFF);

set_tris_a(0x01);
set_tris_c(0x00);

setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,77,1);
set_pwm1_duty(i);

setup_adc(adc_clock_div_32);
setup_adc_ports(AN0);
lcd_init();
set_adc_channel(0);
delay_us(20);
printf(lcd_putc,"Uzaklik=");
   
   while(true)
   {
   output_low(LED);
   delay_ms(DELAY);
   output_high(LED);
   delay_ms(DELAY);
   
   bilgi=read_adc();
   voltaj=(0.0048828125*bilgi);
   uzaklik=x*pow((voltaj),(y));
   lcd_gotoxy(10,1);
   printf(lcd_putc,"%5.1fcm",uzaklik);
   delay_ms(100);
   
   
        if(voltaj >dist_10cm)
        {
        set_pwm1_duty(0);
        }
        if(voltaj < dist_10cm && voltaj > dist_26cm)
        {
        i=uzaklik*2.96;
        set_pwm1_duty(i);
        }
        if(voltaj <dist_26cm)
        {
        set_pwm1_duty(77);
        }
   
   }

}

rodyum

7805 ısınması, giriş voltajını yüksek verip 5v çıkışa LCD aydınlatmasını bağladıysan yada motor beslemesini 7805 üzerinden aldıysan meydana gelir. onun için LCD aydınlatmasına 47 ohm seri bir direnç bağla. motor beslemesini ise girişten al ve ayrıca motora paralel bir hızlı diyot ve 100n kondansatör atmayı unutma. aksi halde parazit sorunları yaşarsın.

son verdiğin yazılımda görebildiğim kusur "set_pwm1_duty();" fonsiyonu içine vereceğin değerin kaç bit olduğunu belirtmen gerekir. örneğin "set_pwm1_duty((int16)77);" gibi. nedeni ise, piclerin bazılarında 8 bit ve 10bit pwm bulunur. bu fonksiyon içeriğine vereceğin değer kadar pwm çözünürlüğünü otomatik ayarlar. "set_pwm1_duty(i);" buradaki "i" değişkenini "double" olarak belirtmişin. bu sayı değeri 8bit yada 10bit olmalıdır ve ondalıklı değer giremezsin. onun için "i" değişkenini "int8" yada "int16" olarak belirt. ayrıca hesaplama yaparken o hesaplamanın türünü işlem üzerinde belirtmen gerekir.
senin yaptığın şu işlemde "i=uzaklik*2.96;" sonucu ondalıklı olarak kaydeder çünkü "i" değişkeni "double" türünde. bu işlem sonucunu pwmde kullanmak için 0...1023 arası ondalıksız hale getirmelisin.

Powered by EzPortal