fonksiyonlar ve programlama mantığı sorunu

Başlatan mcan, 06 Ocak 2006, 15:28:02

Petek

Kesme tanımlama. Ana programda sonsuz döngü içerisinde tmr0 overflow olup olmadığına bak (flagi set edilir) bu durumu tespit edince, flagi sıfırla, a değerini arttır, abc alt programını çağır. İnterrupt ile ilgili şeyleri de çıkart.
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

mcan

şimdi kafama stack etti   :idea:  benim bazı yazdığım programlar sadece 1 kereliğine güzel çalışıyorlardı, onlarda kesme içine ana program gibi yazıyordum demek stack bitince lcd yada başka bişeyde takılıp kalıyorlardı

mcan

ozaman  ilgilenen olursa PETEK in katkılarıyla ,yazmaya çalıştığım frekans metre ,((değişken lerle pek aram yok onun için bayabi yuvarlıyor olsa gerek
belki ordaki değişken için float gibi bişey kullanılıp noktalı gösterim mümkün olur,vede delay değerini önbölücü değerine göre değiştirmeem gerekiyor))
#include <16F84a.h>
#fuses XT,NOWDT,NOPROTECT,NOPUT,//NOLVP,NOBROWNOUT
#use delay(clock = 4000000)
#define use_portb_lcd
#include <lcd2.c>
#byte  PORTA = 5

int a=0;
int16 b=0;
int c=1;


#INT_TIMER0
arttir()
{a++;
switch(a)
   {
    case 1: setup_timer_0 (RTCC_DIV_2|RTCC_EXT_L_TO_H);c=2;break;
    case 2: setup_timer_0 (RTCC_DIV_4|RTCC_EXT_L_TO_H);c=4;break;
    case 3: setup_timer_0 (RTCC_DIV_4|RTCC_EXT_L_TO_H);c=4;break;
    case 4: setup_timer_0 (RTCC_DIV_8|RTCC_EXT_L_TO_H);c=8;break;
    case 5: setup_timer_0 (RTCC_DIV_16|RTCC_EXT_L_TO_H);c=16;break;
    case 6: setup_timer_0 (RTCC_DIV_32|RTCC_EXT_L_TO_H);c=32;break;
    case 7: setup_timer_0 (RTCC_DIV_64|RTCC_EXT_L_TO_H);c=64;break;
    case 8: setup_timer_0 (RTCC_DIV_128|RTCC_EXT_L_TO_H);c=128;break;
    case 9: setup_timer_0 (RTCC_DIV_256|RTCC_EXT_L_TO_H);c=256;break;
    default :a=0;break;
   }}





void main()
{
       
       lcd_init();
       setup_timer_0 (RTCC_DIV_1|RTCC_EXT_L_TO_H);


       FOR(;;){
       enable_interrupts(INT_TIMER0);
       enable_interrupts(GLOBAL);
       set_timer0(0);
       delay_ms(1000);
       b=get_timer0();
       set_timer0(0);
       disable_interrupts(INT_TIMER0);
       disable_interrupts(GLOBAL);
       set_timer0(0); 
       b=b*c;
   lcd_gotoxy(1,1);
   printf(lcd_putc,"Frekans %6lUHz   ",b);}}


işte baştan beri yapmaya çalıştığım kendi kendine aralık bulma olayını kesmenin içine koyarak çözmüş oldum tabiki PETEK in sayesinde,

3khz den onra benim bilgisayar imule edemiyor belki program hatalıdır belki adece bilgisayarım kaldırmıyordur

Petek

Alıntı yapılan: "encryptedcode"ozaman  ilgilenen olursa PETEK in katkılarıyla ,yazmaya çalıştığım frekans metre ,((değişken lerle pek aram yok onun için bayabi yuvarlıyor olsa gerek
belki ordaki değişken için float gibi bişey kullanılıp noktalı gösterim mümkün olur,vede delay değerini önbölücü değerine göre değiştirmeem gerekiyor))
Frekansmetre işi biraz karışık bir iş. İki farklı algoritma kurman gerekir. Birincisi yüksek frekanslar için, ikincisi düşük frekanslar için. Birincisinde belirli bir delay süresinde (mesela 100 ms) timerin kaç puls saydığına bakacaksın (timer girişi hariçten olacak). İkincisinde ise periyodu belirleyeceksin. Bu durmda timer kaynağın içeriden olacak, hariçteki sinyalin iki yükselen kenarı arasında geçen süreyi timerdan okuyacaksın.

16F84 yerine 16F628i kullan. İçerisinde 3 tane timer var. tmr1 8 bit prescale,  3 bit postscale kullanır. Toplam 8x65536 clock sinyalinde bir overflow alabilirsin.
Alıntı Yap
3khz den onra benim bilgisayar imule edemiyor belki program hatalıdır belki adece bilgisayarım kaldırmıyordur
O tür şeyleri simule etmediğim için bilemiyorum. Simulasyon ayarlarında real time simulation seçeneği var. Onu seçersen ISIS sana gerçek zamanlı simulasyon yapıyor. Yyalnız devren kalabalık ise bu pek mümkün değil. Bu durmda test etmek istediğin kısmı bırak, diğer devre elemanlarını devreden at ve simule et. Programında da aynı şekilde sadece simule edeceğin rutinler kalsın gerisini başka yerde sakla. En son doğruluklarından emin olduğunda tekrar birleştir. Aslında baştan parça parça modülleri geliştirip simule et ve bir kütüphanede topla. Bu daha mantıklı bir yol.
switch(a)
   {
    case 1: setup_timer_0 (RTCC_DIV_2|RTCC_EXT_L_TO_H);c=2;break;
    case 2: setup_timer_0 (RTCC_DIV_4|RTCC_EXT_L_TO_H);c=4;break;
    ......
   }

Bunun yerine (2-3 aynı belki yanlış yazmışsındır diye kabul edersek) aşağıdaki aynı işi görür. Derlenmiş dosyanın listine bakarsanız ne kadar kod alanı kazandığınızı görebilirsiniz.

   setup_timer_0 ((a-1)|RTCC_EXT_L_TO_H); // RTCC_DIV_2 0 tanımlı
   c=1<<a;


Programını hala anlayamadım. Daha doğrusu dikkatli izleyemedim. ölçtüğün frekans düşük ise fazla sorun olmaz ama biraz yüksek ise bu durumda timer değerlerini tespit etmek, ayarlamak, sıfırlamak için harcanan süreler sıfırlanır (yani yeni prescale değerini atadığında mevcut sayılan değer sıfırlanır, timer registerinin ne olduğunu hatırlamıyorum ama prescaler sıfırlanır diye hatırlıyorum). Tam hassas ölçüm alamayabilirsin. İnternette inductance meter diye aratırsan 16F84 ile yapılmış bir tasarım göreceksin. Açık kaynak kodlu. Oradaki mantık çok güzel (yalnız yüksek frekanslar için). Prescaler içerisindeki değeri bile tespit edebiliyor(yanlış hatırlamıyorsam +- 3 clock cycle hata ile frekansı tespit edebiliyordu). Bu frekans değerini kullanarak inductance hesabını yapıyor.  

Son bir şey daha, CCS interrupta girildiğinde 30 ic (instruction cycle) dan fazla context saving işlemi yapıyor. İnterrupttan dönerken de aynı şeklide. O nedenle frekansmetre gibi zaman kritik uygulamalarda CCS nin özel interrupt rutini var. Onu kullanmak gerek. Assemblerda interrupt nasıl yazılıyorsa aynen yazıyorsunuz. Bu size hız kazandırır. Ama dikkatli olmak gerek.
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

mcan

programın şöyle işliyor,ana programda önceden belirlenen ps değeriyle ölçüme gidiyor ( sonsuz for döngüsü) eğer frekans 255hz den fazlaysa mutlaka kesme gerçekleşiyor ve kesme ile ps değeri değiştiriliyor buradan kesmenin geldiği yere yani for döngüsünün içine geri dönen parogram yeni değerlerle kurulan timer0 la tekrar bir ölçüm yapıyor ,zaten ölçüme başlamadan herşey sıfırlanıyor mevcut timer değerinin bi önemi kalmıyor ,çünki o an için aralık değişiyor aralık sabit kaldıkdan sonra for döngüsü içinde sürekli değer ölçülüyor uzun süreceğini düşündüğüm kodlar için kesmeler pasifleştirildiği oluyor vede ölçüme başlamadan önce sürekli timer değeri ıfırlanıyor ayrıca pasifleştirmeye giderkende yüksek frekanslarda imer taşmasındiye habire 0 lanıyor


devrede bir tane lcd ve bir tane pic16f84a var başka hiç birşey yok timer 0 a dışardan sinyal giriyorum ve 1000ms için saydırıyorum ama ps değeri değişince mutlaka bekle süresini değiştirmem lazım yoksa yuvarlama oluyor sadece tam katlarda tam değer gösteriyor,mesela 3600hz de tam değer verirken 3000hz de tam değer vermiyor onu düzeltmeliyim ayrıca çarpma işlemiylede yuvarlama oluyor çünki değişken int

benim mantığıma göre kesme içinde yada başka yerdeki gecikmeden etkilenmemesi gerekiyor çünki değer for döngüsü içindeki delay_ms b=get_timer0 komutları ile oluşuyor bu iki komutun arasında gecikme olmazsa bence bi mahzuru yok çünki her defasında tekrar değper oluşturuluyor kesme gelince kesmeye gidip geliyor ve yeni değerlerle yeni aralıkda yeni bir ölçüm yapıyor ......valla kafamdaki bu ama belki ccs ye doğru akramamış olabilirim

o iki kere tekrarlanma ebebini ben bulamadım çünki program 512 ile 1024 arasında kesmeye gidiyor nedenini araştırıyorum hala

mcan

hocam çok doğru bu mantığı bende düşündüm ama yapamadım
setup_timer_0 ((a-1)|RTCC_EXT_L_TO_H); // RTCC_DIV_2 0 tanımlı 
   c=1<<a;

ayrıca o iki kere yazılan şey yeni kodda gereksizmiş denedim o olmadanda çalışıyor sizinki olması gerekiyor ama olmuyor simüle edince görülüyor

bu ilk kodum ps değerinide yazıyor

#include <16F84a.h>
#fuses XT,NOWDT,NOPROTECT,NOPUT,//NOLVP,NOBROWNOUT
#use delay(clock = 4000000)
#define use_portb_lcd
#include <lcd2.c>
#byte  PORTA = 5

int a=0;
int16 b=0;
int c=1;


#INT_TIMER0
arttir()
{a++;
switch(a)
   {
    case 1: setup_timer_0 (RTCC_DIV_2|RTCC_EXT_L_TO_H);c=2;break;
    case 2: setup_timer_0 (RTCC_DIV_4|RTCC_EXT_L_TO_H);c=4;break;
    case 3: setup_timer_0 (RTCC_DIV_8|RTCC_EXT_L_TO_H);c=8;break;
    case 4: setup_timer_0 (RTCC_DIV_16|RTCC_EXT_L_TO_H);c=16;break;
    case 5: setup_timer_0 (RTCC_DIV_32|RTCC_EXT_L_TO_H);c=32;break;
    case 6: setup_timer_0 (RTCC_DIV_64|RTCC_EXT_L_TO_H);c=64;break;
    case 7: setup_timer_0 (RTCC_DIV_128|RTCC_EXT_L_TO_H);c=128;break;
    case 8: setup_timer_0 (RTCC_DIV_256|RTCC_EXT_L_TO_H);c=256;break;
    
    default :a=0;break;
   }}





void main()
{

       lcd_init();
       setup_timer_0 (RTCC_DIV_1|RTCC_EXT_L_TO_H);


       FOR(;;){
       enable_interrupts(INT_TIMER0);
       enable_interrupts(GLOBAL);
       set_timer0(0);
       delay_ms(1000);
       b=get_timer0();
       set_timer0(0);
       disable_interrupts(INT_TIMER0);
       disable_interrupts(GLOBAL);
       set_timer0(0);
       b=b*c;
   lcd_gotoxy(1,1);
   printf(lcd_putc,"Frekans %6lUHz   ",b);set_timer0(0);printf(lcd_putc,"\nps %U   ",a);set_timer0(0);}}

OG

http://www.ccsinfo.com/exlist.shtml  da ne demiş,

List of complete example programs (in the EXAMPLES directory)
EX_FREQC.C - A 50 mhz frequency counter

Bu örnekler işinize yarayabilir.
FORUMU İLGİLENDİREN KONULARA ÖM İLE CEVAP VERİLMEZ.

Petek

Alıntı yapılan: "encryptedcode"programın şöyle işliyor,ana programda önceden belirlenen ps değeriyle ölçüme gidiyor ( sonsuz for döngüsü) eğer frekans 255hz den fazlaysa mutlaka kesme gerçekleşiyor ve kesme ile ps değeri değiştiriliyor buradan kesmenin geldiği yere yani for döngüsünün içine geri dönen parogram yeni değerlerle kurulan timer0 la tekrar bir ölçüm yapıyor ,zaten ölçüme başlamadan herşey sıfırlanıyor mevcut timer değerinin bi önemi kalmıyor ,çünki o an için aralık değişiyor aralık sabit kaldıkdan sonra for döngüsü içinde sürekli değer ölçülüyor uzun süreceğini düşündüğüm kodlar için kesmeler pasifleştirildiği oluyor vede ölçüme başlamadan önce sürekli timer değeri ıfırlanıyor ayrıca pasifleştirmeye giderkende yüksek frekanslarda imer taşmasındiye habire 0 lanıyor
Anladım :) Ama çok sağlıklı bir yol değil. Yüksek frekans ölçümü için mantıklı sayılır. Ama düşük frekanslarda hata oranı yükselir. 1 sn. bekleme süresinde düzgün sayabilmen için frekans 65kHzden küçük olmak zorunda. 65-128 kHz arası için delay süreni 500 ms. ye indirmen gerekir. Daha yüksek frekanslarda bu delay süresini daha da düşürmen gerekir. 16F628in timer1 ini kullansan işin daha kolay olur. Çünkü ilave olarak 3 bit postscale var :)

Prescale içerisindeki sayımı ölçmek için devrede biraz değişikliğe gitmen gerekir. Sinyal kaynağını seri bağlı iki direnç (1k+1k gibi) üzerinden timera ver. Bu iki direnç arasını başka bir pine bağla. Timer girişini (dirençsiz) de diğer bir pine bağla. Normalde bu pinlerin yönü input olacak. İki direnç arasına bağlı olan kapı görevi görecek. Yani yönü çıkış yapılıp sıfırlandığında sinyal timera ulaşamayacak. Prescale değerini timera doğrudan bağlı pinin yönünü çıkış yaparak ve bu çıkıştan timera sinyal göndererek timeri 1 arttırıncaya kadar prescale kaç puls gönderdiği hesaplanacak ve prescale tam değerinden bu değer çıkartılacak. Bu pinlerin yönünü değiştirmedeki zaman kayıplarını da dikkate alman gerekir (başlangıçta bu pinlere 0 yükle).

Programında interruptları aktiflemeden önce de timerı sıfırla.

Kolay gelsin
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

Petek

Alıntı yapılan: "encryptedcode"hocam çok doğru bu mantığı bende düşündüm ama yapamadım
setup_timer_0 ((a-1)|RTCC_EXT_L_TO_H); // RTCC_DIV_2 0 tanımlı 
   c=1<<a;

ayrıca o iki kere yazılan şey yeni kodda gereksizmiş denedim o olmadanda çalışıyor sizinki olması gerekiyor ama olmuyor simüle edince görülüyor
Kodu ve ISIS dosyasını gönderebilirsen buna bakabilirim.
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

mcan

bayramınız kutlu olsun :!:  el öpmeye çıktım ki malzeme parasını çıkaralım :D

bu kodu cof doyası

buda simülasyonu

sim1.dsn

Petek

Alıntı yapılan: "encryptedcode"bayramınız kutlu olsun :!:  el öpmeye çıktım ki malzeme parasını çıkaralım :D

bu kodu cof doyası

buda simülasyonu

sim1.dsn

Derviş Yunus Anadoluyu gezerken bir gün yolda bir kervana rastlar. Kervandakiler aç. Yunus size bir nefes vereyim der. Kervandaki bir kadın oradan seslenir nefes bizim nemize gerek, vereceksen darı (mısır) ver der. Yunus elinden bir şey gelmez ve oradan ayrılır. Yıllar boyunca Anadolu da pek çok kişi Yunus'un dizeleri ile irşad olur. Yunus'tan darı isteyen kadın da aynı şekilde hakikatı bulur. Karşılaştıklarını irşada başlar. Bir gün O da bir fakire rastgelir. Fakir o kadına der, nefes bizim nemize gerek, vereceksen darı ver. O zaman kadın Yunusla aralarında geçen aynı olayı hatırlar... (gerisini unuttum)..

Hocam bayram harçlığı gönderecektim ama zarfı kapattım artık. Gelecek bayram inşaallah 8)

Programında biraz düzeltme yaptım. Gerisini senin halletmen lazım.
Kolay gelsin.

http://www.hemenpaylas.com/download/77087/A_freakns.zip.html

Ana programda geçen #include <lcd2.c> yi <lcd.c> ye dönüştürerek kullanabilirsiniz.
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein