Picproje Elektronik Sitesi

DERLEYİCİLER => CCS C => Konuyu başlatan: mcan - 06 Ocak 2006, 15:28:02

Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 06 Ocak 2006, 15:28:02
#include <16F84a.h>
#fuses XT
    .
    .
    .
int a=0;
int16 b=0;...


aaa(){
...............
xyz();}


xyz(){
..........
enable_interrupts(GLOBAL);
........
disable_interrupts(GLOBAL);
aaa();}


abc()
{disable_interrupts(GLOBAL);
xyz();}



#INT_TIMER0
arttir()
{......
abc();}






void main()
{
      enable_interrupts(INT_TIMER0);
      enable_interrupts(GLOBAL);
      lcd_init();
      abc();
      xyz();

}


fonksiyonların birbirini çağırmasını istiyorum bu mümkünmü?
bunları sonsuz döngü içine sokarak halladebildim istemeyerekde olsa,birde şu sorunum var kesmeyi aktiflediğim anda timer 0 taşmadığı halde kesmeye gidiyor bunun nedeni nedir
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 06 Ocak 2006, 16:01:43
birde şu sorunum var,bir kesme alt programı içinden örnekdeki gibi başka bir fonksiyon çağırırsak,çağırılan program çalışırken sanki kesme bitmemiş gibimi çalışır?kesme gelince bi takım işlemler ve sonunda bir yere dallanacak dallandığı yerde artık kesmeyle alakası kalmamış olacak bunun için dallandığı yere hemen disable_interrupt global vede hangi kesmeyse onu pasif yapan dizeyi yazıyorum, bu doğru bir çözüm mü?
Başlık: Re: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 06 Ocak 2006, 16:10:30
Alıntı yapılan: "encryptedcode"fonksiyonların birbirini çağırmasını istiyorum bu mümkünmü? bunları sonsuz döngü içine sokarak halladebildim istemeyerekde olsa,
Recursive calling CCS tarafından desteklenmiyor. C18 18F için destekliyor ama o da sonsuz sayıda değil
Alıntı Yapbirde şu sorunum var kesmeyi aktiflediğim anda timer 0 taşmadığı halde kesmeye gidiyor bunun nedeni nedir
Timer 0 interrupt flagini resetle, timer0 i sıfırla ve interruptını öyle aktifle.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 06 Ocak 2006, 19:03:14
şimdilik beceremedim o işi şunu ekledim fayda etmedi#ASM bcf 0X0B,0B00000000 #ENDASM
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 06 Ocak 2006, 19:15:21
Alıntı yapılan: "encryptedcode"birde şu sorunum var,bir kesme alt programı içinden örnekdeki gibi başka bir fonksiyon çağırırsak,çağırılan program çalışırken sanki kesme bitmemiş gibimi çalışır?
Evet. Kesme ancak kesme rutininin son komutu da işlendikten sonra biter (yani retie komutu ile kesme olmadan önceki yere geri döner)
Alıntı Yapkesme gelince bi takım işlemler ve sonunda bir yere dallanacak dallandığı yerde artık kesmeyle alakası kalmamış olacak
İnterrupt işlemi gerçekleştiğinde programın icraası 0x04 adresine gider. Orada işlemler yapılır ve retie ile geri döner. Dallandığı yerin kesmeyle alakası kalmayacak ne demek?

Alıntı Yap
bunun için dallandığı yere hemen disable_interrupt global vede hangi kesmeyse onu pasif yapan dizeyi yazıyorum, bu doğru bir çözüm mü?
Hocam kesme geldimi zaten gie biti 0 olur. Başka interrupt almaz. 0x04 adresinden sonra yapılan işlemlerle  işini bitirip retie komutu ile geri döndüğünde gie biti otomatik set edilir.

Sana bir tavsiye. Mümkün olduğunca interrupt rutininde başka bir alt program çağırmamaya çalış. Mümkünse bit yada bayt tanımlı değişkenleri set reset et ve kesmeden geri dön. Döndüğünde bu flagleri kontrol edecek if blokların yada alt programların olsun.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 07 Ocak 2006, 14:04:49
Alıntı YapEvet. Kesme ancak kesme rutininin son komutu da işlendikten sonra biter,(yani retie komutu ile kesme olmadan önceki yere geri döner)
yani ben kesme içinde bir alt programn çağırırsam,kesme onuda işler hatta içinde sonsuz döngü varsa orada takılabilir,tüm bunları bitirirse birde sonuna retie ekleyerek nereden geldiyse oraya geri döner... aslında duruma göre çok işe yarayabilir ama keşke kesme rutininin sonunda ki retie yi iptal edebilsem:bu retie komutu c deki return komutuyla aynı gibimi?anladığım kadarıyla retie yi derleyici bizim istediğimiz yere değil kesmenin en son işlenen komutunun sonuna koyuyor.bunu koymaması için bişey yapılabilirmi?

Alıntı Yapİnterrupt işlemi gerçekleştiğinde programın icraası 0x04 adresine gider. Orada işlemler yapılır ve retie ile geri döner. Dallandığı yerin kesmeyle alakası kalmayacak ne demek?
olayı şimdi daha iyi anladım alakası kalmayacak şu oluyor,retie nasıl iptal edilir :D demek istediğim buymuş

Alıntı Yapbunun için dallandığı yere hemen disable_interrupt global vede hangi kesmeyse onu pasif yapan dizeyi yazıyorum, bu doğru bir çözüm mü?
bilmeden de olsa burada şunu ummuşdum : kesmeleri pasif edince ne retie kalır ne bayrak biti kesmeyi hiç kuramamışım gibi sıfırlanır,demek pasif etsekde bir önceki kesmenin komutları işlenene kadar kesme geçerli

olayıda anlatayım,şimdi önce önbölücü alt programı çağırılıyor timer0 ı kuruyorum ve belli bir süre sonunda değerini okuyorum bu arada timer0 taşarsa kesme  oluyor oradan bir alt program olan önbölücü kısmına gidiyor(aslında gidiyor ama hala kesme için de oluyor ki ben bunu istemiyordum)tekrar ayarlanıp timer0 yeni önbölücü değeriyle tekrar kuruluyor ,kesme olmassada sürekli aynı önbölücü değeriyle çalışıyor.....

şimdilik bunu tüm programı sonsuz döngü içine alıp kesmeyide sadece bir değişkeni değiştirmesi için kurdum sorun yok ama her ölçümden önce tekrar tekrar aynı komutlar işleniyor benim istediğim önbölücü programına geldiğinde geri falan dönmesin yeni bir kesme olayını ilkinki gibi beklesin.

şimdi birde şu yolla anlatayım
program başlıyor: işlem;işlem;---- a()----->b()<------->c()
                               ^                   l          
                               l____kesme__________l
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 07 Ocak 2006, 16:48:31
Alıntı yapılan: "encryptedcode"yani ben kesme içinde bir alt programn çağırırsam,kesme onuda işler hatta içinde sonsuz döngü varsa orada takılabilir,tüm bunları bitirirse birde sonuna retie ekleyerek nereden geldiyse oraya geri döner...
Evet
Alıntı Yapaslında duruma göre çok işe yarayabilir ama keşke kesme rutininin sonunda ki retie yi iptal edebilsem
Edersin. Hiç problem değil. Ne işine yarayacak? Yani ana programa döndüğünde kesmeyi kullanacaksan bu durumda gie bitini tekrar set edeceksin. retie ile bu iki işlemi tek işlemle hallediyorsun
Alıntı Yap:bu retie komutu c deki return komutuyla aynı gibimi?anladığım kadarıyla retie yi derleyici bizim istediğimiz yere değil kesmenin en son işlenen komutunun sonuna koyuyor.bunu koymaması için bişey yapılabilirmi?
retie ile return aynı işi yapıyor. retie fazladan gie bitini set ediyor. Evet yapılabilir. ISR rutinini assembler ile yazabilirsin. Derleyiciye ISR rutinini tanıtmak zorunda değilsin. Sadece assemblerda yazdığın rutin 0x004 adresinden başlasın yeterli.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 08 Ocak 2006, 01:14:12
şimdi petek hocam,tam kavrayamadım nasıl yapacağım :oops: programımda  hic#int_timer0 kullanmadan
programın başınamı neresine, şöyle bişeymi yazayım

KESME(){
#asm
org 004h
bcf 0x0B,1
bcf 0x0B,2
BSF 0X0B,7
#ENDASM
A();}


Bir de TO1F ile INTF nin farkını kavrayamadım elimdeki kitapda aynen şöyle yazıyor

TO1F:
1-tmr0 taştı
0-taşmadı

INTF
1-tmr0 dış kesme oldu
0-dış kesme yok

to1f den hadi şöyle bişey anladım diyelim:004 e sapınca bunu kotrol edip kesme timer 0 danmı kaynaklı ona bakabiliriz ...ama ıntf için aklıma bişey gelmiyor
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 08 Ocak 2006, 01:41:17
İlk önce 16F serisi bir uc nin datasheetine bir gözat. Orada kesme rutinine girdiğinde saklaman gereken registerleri nasıl saklayacağını anlatıyor. İlk önce wreg içeriğini daha sonra status registerini içeriğini bozmadan (swap komutu ile) wrege, aynı şekilde wreg den f'e aktaracaksın. Aşağıda 628 datasheetinin  ilgili sayfasından alıntı yaptım.

Alıntı Yap
14.7 Context Saving During Interrupts

During an interrupt, only the return PC value is saved on the stack. Typically, users may wish to save key registers during an interrupt e.g. W register and STATUS register. This will have to be implemented in software.

Example 14-1 stores and restores the STATUS and W registers. The user register, W_TEMP, must be defined in both banks and must be defined at the same offset from the bank base address (i.e., W_TEMP is defined at 0x20 in Bank 0 and it must also be defined at 0xA0 in Bank 1). The user register, STATUS_TEMP, must be defined in Bank 0. The Example 14-1:

• Stores the W register
• Stores the STATUS register in Bank 0
• Executes the ISR code
• Restores the STATUS (and bank select bit register)
• Restores the W register

EXAMPLE 14-1: SAVING THE STATUS AND W REGISTERS IN RAM

MOVWF W_TEMP ;copy W to temp register,;could be in either bank
SWAPF STATUS,W ;swap status to be saved into W
BCF STATUS,RP0 ;change to bank 0 regardless ;of current bank
MOVWF STATUS_TEMP ;save status to bank 0 ;register
:
: (ISR)
:
SWAPF STATUS_TEMP,W ;swap STATUS_TEMP register into W, sets bank to original state
MOVWF STATUS ;move W into STATUS register
SWAPF W_TEMP,F ;swap W_TEMP
SWAPF W_TEMP,W ;swap W_TEMP into W


Org komutu assembler içerisinde kullanmayacaksın. CCS nin org komutu var help ten bak (#ORG).

Yalnız interrupt yada kesme rutinine girdikten sonra bu rutinden normal return ile çıkarsan saklamış olduğun wreg, status reg eski değerlerini geri almayacağından ana programda (kesmeden önceki değerler) başka değerlere dönmüş olacak. Bu da programında istemediğin sonuçlara götürür.

İnterupttan ne zaman çıkmak istersen return yerine "context saving" örneğinde görünen ikinci kısmın başına (ISR) den sonra "SWAPF STATUS_TEMP,W " ile başlayan yere goto ile git.  

Sana tavsiyem, interruptta mümkünse alt program çağırma. Eğer interruptsız 5 stack alanı kullanıyorsan interrupt kullandığın anda bu 5 + 1 olur. İnteruptta bir alt program çağırmış isen bu durumda 5 + 2 olur. LCD yazdırma işlemi yaptırıyorsan CCS de 4 stack sadece LCD tüketir (biraz oynarsan 3 e indirirsin). Yani stack alanını ekonomik kullanman gerekir. Olmuyor ise PIC18 serisinde 32 adet stack alanı var. Tepe tepe kullanırsın.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 08 Ocak 2006, 02:37:05
hocam gecenin bi yarısı oldu ,sana çok teşekkür ederim...şimdi son kafamda şekillenen şu, yani programıma şunu ekleyeceğim

#org 0x004
kesme() {

#asm
movwf w_gecici
swapf status,w
clrf status
movwf status_gecici
movf pclatch,w
movwf pclacth_gecici
clrf pclacth_gecici

bcf 0x0B,1
bcf 0x0B,2
BSF 0X0B,7
#endasm

işlem;
işlem;
a=1;
alt_program(); :)))
}

altprogram(){
if(a==1){
#asm
movf  pclacth_gecici,w
swapf status_gecici,w
movf status
swapf status_gecici,f
swapf status_gecici,w
#endasm
a=0;}

işlem;
işlem;
.
.
.
stackda 8 taneymiş :lol:  az kullanmak gerekiyor ama o kadar profosyonel olamadım şimdilik öğrenmek adına yazdığım şey olurmu hocam
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 08 Ocak 2006, 07:30:45
Kesme rutinini yazdın ve içerisinden alt_program() çağırdın. Altprogram işini bitirdikten sonra kesme rutinini normal bitiriyorsun. Burada derleyici senin interrupt içerisinde olduğunu bilmediği için normal return ile ana programa döndürür (ana programında interruptı tekrar aktiflemen gerekir). Fakat sakladığın status, wreg içeriği tekrar yüklenmediği için ana programda istemediğin durumlar olacaktır. Bu olay aynı televizyonlarda yayımlanan sırlar dünyası, kalp gözü, vs programlarının senaryolarına benzer. Adam hayatının o anına kadar hep kötülük yapar, ta ki o rüyayı görene kadar. Ertesi gün hidayete ermiş başka biri olarak hayatına devam eder. Neden? Çünkü wreg ve statüs registerleri geri yüklenmedi  8)

Alt programında bu işi yapmaya çalışmışsın ama en sonuna koyduğun a=0 ilk önce wreg i daha sonra da status registerini değiştirecektir. Bu durumda assembler içerisinde yazdıklarının anlamı kalmayacak ve gerksiz delay işlemleri olarak algılanacaktır (tarafımdan :))

Alt programı bitirmemişsin. Bu durumda alt programı ana program gibi kullanmak niyetindeysen olmaz. Stackta bir alan tükettin ve stack pointerin 1 arttı.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 09 Ocak 2006, 00:47:23

#org 0x004
kesme() {

#asm
movwf w_gecici
swapf status,w
clrf status
movwf status_gecici
movf pclatch,w
movwf pclacth_gecici
clrf pclacth_gecici

bcf 0x0B,1
bcf 0x0B,2
BSF 0X0B,7                  
#endasm

işlem;
işlem;
a=1;
alt_program(); :)))  >---------------
}                                                l
                                                 l_ buraya dallanır(?)
altprogram(){  <-------------------  l
if(a==1){ a=0;
#asm
movf  pclacth_gecici,w
swapf status_gecici,w
movf status
swapf status_gecici,f
swapf status_gecici,w --------------> bu  işlemle beraber return  
#endasm                                       gibi etki mi oluşur                          
} ----->buradan ,,içeriği değiştirilmiş değerlerle de  
olsa,,normal return ile ana programa nasıl oluyorda döndürebiliyor, düz mantık olarak ne retfie ne return nede #int_xxx kullandım,hangi mekanizma onu ana programa döndürüyor?

eğer buradan anaprograma dönerse a=0; gibi bir işlem yaptığımdan ana programa gelmeden hemen önce içerikleri değiştirmiş ve o satırları boşa yazmış oluyorum değilmi? ozaman a=0 işlemini başa alıyım

işlem;
işlem;
.
.
.
ayrıca stack olayınıda okudum recursive calling gibi olacak buda ,recursive calling de fonksiyonlar birbirini çağırdıkça hep yarım kalmış fonksiyonlar zinciri oluşup stack alanının dolmasına vede programın belli birdüre sonra çakılmasına yol açıyormuş  :D bende kesme içinde alt program çağırdığım zaman sanırım aynı şey olacak ve her kesme oluşunda stack bir artıp sonunda tükenecek doğrumu acaba? vede satack ne yaızlabilir nede okuna bilirmiş böylece prpogram koduyla geri alamam sanırım pop ve push işlemleride yapılamıyormuş haydi hayırlısı ben en iyisi dediğini dinleyip fazla diretmeyeyim diyorum ama, merak işte şunuda bitirip denemek olacakları gözümle görmek istiyorum

asıl üzerinde çalıştığım kodu ekliyorum onun üzerinden konuşalım vaktiniz varsa
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 09 Ocak 2006, 21:59:17

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

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


abc()
     {
     disable_interrupts(INT_TIMER0);
     disable_interrupts(GLOBAL);


  switch(a)
  {case 0: setup_timer_0 (RTCC_DIV_1|RTCC_EXT_L_TO_H);break;
   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 :lcd_putc("\fPs ");a=0;break;
  }

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








#INT_TIMER0
arttir()
{
a++;
printf(lcd_putc,"\n %U   ",a);}



void main()
{
      enable_interrupts(INT_TIMER0);
      enable_interrupts(GLOBAL);
      lcd_init();
      abc();

}
işte kesmeyle birlikde abc programına gitmesini istiyorum yoksa tüm abc programını sonsuz döngüye aldırıp anca öyle çalışmasını sağlıyorum, böylece her değer ölçmeden tekrar tekrar ayar yapılıyor.

kesme geldiğinde sayaç yeni önbölücü değeriyle bir kere kurulup sonsuz döngüde çalışmaya koyulacak bunu nasıl yaparım?

biraz önce ccs de sadece kesme ve alt program denedim böyle yapınca kesme oluşmuyorki :P  aynen şöyle bişey yazdım

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

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


abc(){b=0;


b=b+a;





                 FOR(;;) {
                 b=b+1;
                 delay_ms(250);

                 lcd_gotoxy(1,1);
                 printf(lcd_putc,"deger %6lUHz   ",b);  }}



ab(){lcd_putc("\fKESME");delay_ms(2500);abC();}



#INT_EXT
kess(){;
a=a+10;
ab();}



void main()
{

      lcd_init();
     ext_int_edge(L_TO_H);
      enable_interrupts(INT_EXT);
      enable_interrupts(GLOBAL);
      abc();

}



işte bunda abc yi kesme içinde herhangi bir yerde çağırırsam rb0 dan sinyal gelse bile kesmeye gitmiyor ilginç,yapmaya çalıştığım şey ccs de zaten mümkün değilmiş siz ne dersiniz gene bende bi hata olabilir
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 09 Ocak 2006, 22:17:31
Alıntı yapılan: "encryptedcode"ayrıca stack olayınıda okudum recursive calling gibi olacak buda, recursive calling de fonksiyonlar birbirini çağırdıkça hep yarım kalmış fonksiyonlar zinciri oluşup stack alanının dolmasına vede programın belli birdüre sonra çakılmasına yol açıyormuş  :D bende kesme içinde alt program çağırdığım zaman sanırım aynı şey olacak ve her kesme oluşunda stack bir artıp sonunda tükenecek doğrumu acaba? vede satack ne yaızlabilir nede okuna bilirmiş böylece prpogram koduyla geri alamam sanırım pop ve push işlemleride yapılamıyormuş haydi hayırlısı ben en iyisi dediğini dinleyip fazla diretmeyeyim diyorum ama, merak işte şunuda bitirip denemek olacakları gözümle görmek istiyorum
Yazdıklarınız doğru. Bir de kesme alt programında çağırdığınız alt programı kesmeye almanız daha doğru olur. O alt programdaki assemblerda da hata var zaten :) pclath wreg e alındı hemen arkasından wrege başka bir tane daha..

Denemeyi ISIS üzerinde yapın. Simulasyonu kusursuz diyebilirim. pinlerdeki read-modify-write (rmw) özelliğini bile eklemişler. İnanılmaz birşey... test ettiğimde çok şaşırmıştım... Yani ISISa güvenebilirsin.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 09 Ocak 2006, 22:27:01
İkinci mesajın çok dağınık olmuş, anlamakta güçlük çekiyorum. İlk kod bölümü ile ilgili yazayım. Ana programda abc bir defa çağırılıyor ve abc de iş bittikten sonra bir daha abc çağrılmaz, program ana programın sonunda sonsuz döngüye girer ve bekler. Bu arada interruptının a değerini arttırması bir anlam ifade etmez. Çünkü artık programın sonsuz döngüde (daha doğrusu dos altında olsaydı program normal işleyişini tamamlayıp Dos a dönmüş olurdu)..

Daha önce de belirttiğim gibi kesme rutinlerinde alt program çağırma işlemini  mümkün ise yapma. Hele interrupt rutinlerinde LCD ye bir şey yazdırmak (normalde 4 stack tüketir, bir de interruptın kendisi 5, yani ana programda sana 3 satcklık bir yer kalmış !!!) son derece sakıncalı. Bunu anlaman için şöyle bir örnek vereyim. Ana programda LCD ekrana bir şey yazdırıyorsun. LCD rutinleri iç içe 4 alt program çağırır. Senin programın icraası tam bu 4. de iken interrupt geldiğinde 5 stack alanı daha kullanılır, toplam 9 eder. 9. stackın ilk baş kısmına yerleşir. İnterrupttan döndüğünde LCD işlemin de bittiğinde ana programa dönmek yerine yine LCD rutinin en derindeki alt programına gidersin ve hiç bir zaman ana programa dönemezsin.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 09 Ocak 2006, 22:36:09
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.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 09 Ocak 2006, 22:58:06
ş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ı
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 09 Ocak 2006, 23:02:32
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
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 09 Ocak 2006, 23:52:30
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.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 10 Ocak 2006, 00:18:28
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
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 10 Ocak 2006, 01:36:56
hocam çok doğru bu mantığı bende düşündüm ama yapamadımsetup_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);}}
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: OG - 10 Ocak 2006, 03:17:18
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.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 10 Ocak 2006, 15:21:03
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
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 10 Ocak 2006, 15:23:18
Alıntı yapılan: "encryptedcode"hocam çok doğru bu mantığı bende düşündüm ama yapamadımsetup_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.
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: mcan - 11 Ocak 2006, 14:12:02
bayramınız kutlu olsun :!:  el öpmeye çıktım ki malzeme parasını çıkaralım :D

bu kodu cof doyası (http://rapidshare.de/files/10836118/tmr0_ext_frekans_olc.cof.html)

buda simülasyonu

sim1.dsn (http://rapidshare.de/files/10836304/sim1.DSN.html)
Başlık: fonksiyonlar ve programlama mantığı sorunu
Gönderen: Petek - 12 Ocak 2006, 21:23:34
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.