Picproje Elektronik Sitesi

SERBEST BÖLGE => Programlama ve Algoritma => Konuyu başlatan: z - 28 Nisan 2014, 01:16:22

Başlık: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 01:16:22
Adi sani onemli olmayan bir islemci icin program yazmaya basladik.

Bayagi da bir sey yazdik. Ana program icinde hesaplar yapiyor dudukler otturuyor, LCD de bir seyler gosteriyor gidiyor bir yerlerde donguye giriyor donguden cikiyor seri porttan bir seyler yolluyoruz vs vs vs.

Bu islemcinin sadece 1 tane timeri var. Bu timeri da 2 mili saniyede bir interrupt (kesme) uretecek sekilde kurduk.

Haliyle ana program kostururken her iki mili saniyede bir bu interrupt rutinine giriyoruz.

Gelelim can alici noktaya.

Timer interrupt rutinin icinde A pinine bakmamiz; eger A pini 1 ise bir ledi yakmamiz ardindan da 100 mili saniye sonra da bu ledi sondurmemiz isteniyor olsun.

Sorunumuz aynen bu sekilde.

Islemcilere yeni yeni kod yazmaya baslayan arkadaslar bunu asagidakine benzer sekilde yapmaya calisiyorlar.


void Timer_Interrupt_Rutini()
{
       Timer=2;  // 2 mili saniye sonra tekrar int uret anlaminda

       if (A==1)  // Eger A pini 1 ise asagidaki islemleri yap
         {
            Ledyak();      // ledi yak
            Delay(100);   // 100 mili saniye bekle
            LedSondur(); // ledi sondur
         }
}


Not: Programda A girisi surekli 1 de tutulursa led hep yaniyor gorunecektir. Fakat ilk mesajdaki soruya dikkat ederseniz soru istendigi gibi cevaplanmistir.

Program yukaridaki gibi yazildiginda cok onemli bir hata yapiliyor.

Interrupt rutini, ana programdan islemciyi odunc alan bir rutindir.

Yahu komsu, acil carsiya gitmem gerekiyor arabani bana odunc ver demek gibi bir seydir. Komsunuz arabasini size verdiginde artik o bir yere kimildayamaz. Ne zaman arabayi geri verirsiniz o zaman arabasina biner ve gider.

Bu durumda bir daha arabayi istemeye yuzunuz olmasi icin odunc aldiginiz arabayi olabilecek en kisa zamanda teslim etmemiz gerekir. Cunku komsunuzun arabasina binerek gitmesi  gereken pek cok yer  (işler) varken sizi kiramadigi, size deger verdigi icin arabasini gozunu kirpmadan size odunc verdi.

Siz yukaridaki gibi program yazmakla ne yaptiniz biliyormusunuz?

Komsunuzdan arabayi alip carsiya gittiniz isinizin bir kismini yaptiniz sonra arabayi bir parkyerine parkettiniz. Ardindan bir kafeye gittiniz bir arkadasinizla 1 saat laklak edip kahve ictiniz. Daha sonra arabayi parkettiginiz yerden alip diger islerinizi yaptiniz ve ardindan komsunuza gidip arabayi teslim ve tesekkur ettiniz.

Sizin kafede laklak ettiginiz sure boyunca komsunuz arabasiz oldugu icin cok onemli randevularini kacirdi, karisina soz verdigi seyi alamadi cunku dukkan kapanmisti vs vs.

Devami yarin.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 01:59:43
Hocam kusura bakmazsan bu mesajini bir baska basliga tasiyacagim. Cunku yarin anlatacagim konu;

islemcilerle yeni yeni ugrasmaya baslayip interrupt rutini icinde delay tipi komutlar kullanarak bir seyler yapmaya calisan yani yanlis yolda olan arkadaslara yonelik.

Fakat bir baska baslikta yazacaklarini okumaktan keyif alirim.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 03:13:10
Simdi isin felsefesini anlatmadan once yukaridaki programi bir de asagidaki gibi yazdigimizi dusunelim. Ana program calismaya basladiginda State adini verdigim degiskeni sifirladigini varsayin.

void Timer_Interrupt_Rutini()
{
       Timer=2;  // 2 mili saniye sonra tekrar int uret anlaminda
       if (State==0)
         {
            if (A==1)
               {
                 State=1;
                 Ledyak();
                 N=0;
               }
          }
       else
         {
            N++;
            if (N==50)
              {
                 LedSondur();
                 State=0;
              }
         }
}


Dikkat ettiyseniz Timer_Interrupt_Rutini icinde delay gibi komutlarla hic bekleme yapmadik.

Kafanizda bir seyler canlandi mi?


Bu programda da komsumuzdan arabayi odunc aliyoruz. Isimizi yapmaya basliyoruz fakat isimiz bitsin bitmesin kisa bir sure sonra komsumuza arabayi geri veriyoruz. Komsum islerim bitmedi senin de cok isin var. Sen islerini yapmaya basla ben bir ara gelip senden gene arabayi alacagim diyoruz. (Yuzsuzlugun de bu kadarina pes ama komsumuzu asla zor durumda da birakmiyoruz)

Not: Programda A girisi surekli 1 de tutulursa led hep yaniyor gorunecektir. Fakat ilk mesajdaki soruya dikkat ederseniz soruyu istendigi gibi cevapladigimizi goreceksiniz.

Ana programimiz, interrupt rutininin ledi 100ms sonra sondurme girisiminden dolayi hic etkilendi mi? Hic isleyemez durumda kaldimi?

Interrupt rutinlerinde nicin bekleme yapilmaz (yapilmamali)  yada uzun sure alacak islemler yapilmaz (yapilmamali) dendigini simdi anladiniz mi?

Simdi soz sizde. Daha sonra tekrar devam edecegim.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: fgokcegoz - 28 Nisan 2014, 09:06:58
Peki @z hocam,
Timer interrupt rutinine hiç yüklenmeden yani tanımladığımız timeTick gibi bir değişkeni bir artırıp çıksak ve pinin lojik1 olup olmadığını - olduysa ledi yakıp 100ms sonra söndürmemiz gerektiği işini yapan durum makinesi yapısını ana döngüye yüklesek daha doğru olmaz mı ?
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: Kabil ATICI - 28 Nisan 2014, 09:56:37
Bunuda şöyle bakalım, şimdi değişkenin kontrolunu ana döngüde yapıyorsun, ama senin ana döngüdeki işlerin kesme süresinin çok üzerinde bir zamanda işlemi yapıyor olsun, olur mu olur.
Şimdi senin değerini kontrol edene kadar kesmede 2 veya 3 değer artışı olursa ne olur? Karşılaştırma noktası geçilir gider.

Bunu sadece timer bazında inceledik, birçok defalar aynı olay seri port haberleşmesinde de yaşanan bir durumdur.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: aliveli - 28 Nisan 2014, 11:04:28
konuyla ilgili güzel bir örnek
biraz ccs c ve ingilizce bilmek gerektirir

#include <16F877.H>
#device adc=8
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define LED_PIN  PIN_B0

// This equation calculates the duration of each timer tick in
// ms.  The timer is clocked at 1/4 of Fosc.  Because we are
// using a 4 MHz crystal, the timer clock is therefore 1 MHz.
// We are using a pre-scaler of 32.  Timer0 rolls over from
// 0xFF to 0x00 every 256 clocks
#define TICK_MS ((1000 * 256 * 32) / (4000000/4)) // 8 ms

#define TASK1_TIMER_VALUE (2000/TICK_MS)  // Every 2 seconds
#define TASK2_TIMER_VALUE (500/TICK_MS)   // Every 500 ms
#define TASK3_TIMER_VALUE (100/TICK_MS)   // Every 100 ms


int16 task1_timer;
int16 task2_timer;
int16 task3_timer;

//--------------------------
void timer_tick(void);
void task1(void);
void task2(void);
void task3(void);

//==========================
void main()
{
// Setup Timer0 so it rolls over at a 122 Hz rate.
// This gives a timer tick of approximately 8 ms.   
// All tasks (together) must execute in less than 8 ms.
setup_timer_0(RTCC_DIV_32);

task1_timer = TASK1_TIMER_VALUE;
task2_timer = TASK2_TIMER_VALUE;
task3_timer = TASK3_TIMER_VALUE;


// The sum of the time to complete all 3 tasks
// must be less than the timer tick duration.
// Currently the tick is set at 8 Ms.
while(1)
  {
   task1();
   task2();
   task3();

   timer_tick();
  }

}
//================================

// This task transmits a character (A to Z)
// to the PC once every 2 seconds.
void task1(void)
{
static char value = 'A';

if(task1_timer)
   return;
else
  task1_timer = TASK1_TIMER_VALUE;


putc(value);
value++;
if(value > 'Z')
   value = 'A';


}

//--------------------------
// This task blinks an LED at a 1 Hz rate.

void task2(void)
{
static int8 led_on = FALSE;

if(task2_timer)
   return;
else
  task2_timer = TASK2_TIMER_VALUE;

// Toggle the LED on/off.
led_on = !led_on;

if(led_on)
   output_high(LED_PIN);
else
   output_low(LED_PIN);

}

//--------------------------
// This task does slightly more complex blinking
// of an LED.  It is on for 100 ms, and off for 500 ms.

void task3(void)
{
if(task3_timer)
   return;
else
  task3_timer = TASK3_TIMER_VALUE;


// Task 3 doesn't do anything yet.
}

//--------------------------
// This function waits for the hardware timer0
// to count up to 0xFF and roll over to 0x00.
void timer_tick(void)
{
// Wait until the Timer0 rolls over from 0xFF to 0x00.
while(!bit_test(get_timer0(), 7));  // Wait until MSB goes high
while(bit_test(get_timer0(), 7));  // Wait until Timer rolls over to 0

if(task1_timer)
   task1_timer--;

if(task2_timer)
   task2_timer--;

if(task3_timer)
   task3_timer--;

}


Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: MrDarK - 28 Nisan 2014, 11:05:31
Bana kalırsa süresinden emin olamadığımız kritik tüm karşılaştırma işlemleri interrupt rutinleri içinde yapılmalı, ıvır zıvır diğer kod parçaları ana program ve modüller içinde yapılmalı. En azından incelediğim state machine programlarında böyle yapılar kullanılmakta.

Watchdog'a da takılmamak için süre taşma yapabilecek yerlerde refresh kullanmakta yarar var reset yememek için.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 11:31:47
Şimdi de daha güzel bir soru soracağım.

Ana program içinde gene bir sürü ıvır zıvır kodumuz var ve bunlardan bazıları bazen dakikalarca bir döngü içinde kalabiliyor.

Seri porttan ne zaman ve ne sıklıkta geleceği belli olmayan veriler geliyor.

Soru: Seri port receive interrupt rutini içine öyle bir kod yazalım ki;

Seri porttan peş peşe 0x41, 0x42, 0x43,  şeklinde datalar alınırsa ilk gelecek data A portuna yazılsın.

Örneğin 0x41 0x42 0x43 0x37 dataları alındığında A portuna 0x37 yazacağız.

0x41 0x42 0x41 0x43 0x41 0x42 0x43 0x55 alırsak bu kez A portuna 0x55 yazacağız.

Öyle bir interrupt rutini yazalım ki ana programı bloke etmeyelim.

Gene bu programı da state machine mantığı ile yazmamız gerekecek.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: picusta - 28 Nisan 2014, 11:48:58
Z hocam pedagojik yönden konuya çok güzel giris yapiyor, yeni baslayanlar için oldugunu belirtiyor.
Fakat gel gör arkadan gelen mesajlar tam yapilmamasi gerekeni yapiyor, Z'nin tekerine çomak sokuyor.
Konunu temelini anlatmaya çalisan makalede biri professyonel araç linki veriyor (yeni baslayanin bu araci anlamasi ve kullanmasi için birkaç derse daha ihtiyaci olacak).
Digeri ise ingilizce yorumlarla dolu bilmem kaç satirlik kod veriyor, konu ile uzaktan alakasi var üstelik (interrupt kullanmiyor), ve anlatilmaya çalisanin tam aksi (ana döngüde bekleme yapiyor).

Konuyla ilgili nacizane yorumlarim :
if State= 0 ... State = 3 ...
Seklindeki satirlar yerine söyle yapsak :

switch (LedState)
{
case YAK:
  ...
  break;

case BEKLE:
   ...
   break;

case SONUK:
  ...
  break;
}

Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 12:18:08
Aslında Gerbay'ın suçu yok. Suç benim. Konu başlığını açtığımda  mesaj olarak içine sadece "yarın devam" edeceğim diye not düşmüştüm. Bu nedenle de Gerbay olaya giriş yaptı.

Ama dediklerine tamamen katılıyorum. Dönen tekere farkında olmadan çomak sokma durumları olabiliyor.

Enumeration konusunda da çok haklısın. Sadece enumeration konusunu bir başlık altında başlı başına bir konu olarak ele alalım.

Enumeration işlemi için tıklayın.  (https://www.picproje.org/index.php/topic,52882.msg400745.html#msg400745)

Bu ikinci örnek programda da enumeration işlemini es geçeceğim.

mesaj birleştirme:: 28 Nisan 2014, 11:09:09

Seri porttan peş peşe 0x41, 0x42, 0x43,  şeklinde datalar alınırsa ilk gelecek data A portuna yazılsın.

Bu programı interrupt kullanmadan ana program içinde yazmaya kalksaydık;

   
            Rx=WaitData(); // Seri porttan data alıncaya kadar bekle, gelen datayı Rx içine yaz anlamında
            if (Rx==0x41)
              {
                 Rx=WaitData();
                 if (Rx==0x42)
                   {
                      Rx=WaitData();
                      if (Rx==0x43)
                        {
                           A=WaitData();
                         }
                   } 
               } 


Şekline yazabilir ve bir döngü içine yerleştirebilirdik. Gerçekten de program isteneni yapmaktadır. Fakat bu şekilde bir program yazımı işlemciyi veri gelinceye kadar beklemeye zorlar ve bu esnada interruptlar haricinde ilave hiç bir şey cevaplanmaz kod işletilmez.

Bu program parçacığını bu şekliyle interrupt rutini içine de yazamayız. 

Yukarıdaki yazım şekli berbat ötesi rezil bir kodlama şeklidir. Seri port hata kontrolu yapmamış olsak da soruda isteneni layıki ile yapar.

Bir de aşağıdaki kodlama şekline bakalım. Gene State değişkeninin sıfır olduğunu varsayın.

void Receive_Interrupt() // seri porttan data gelirse bu rutin çalışacak demektir.
{
       Rx=SeriPortRx_register; // Gelen datayı oku

       switch (State)         
           {
                 case 0:
                              if (Rx==0x41) State=1;
                              break;
                 case 1:
                              if (Rx==0x42) State=2;
                              else State=0;
                              break;
                 case 2:
                              if (Rx==0x43) State=3;
                              else State=0;
                              break;
                 case 3:
                              A=Rx
                              State=0;
                              break;
           }
}


Ya da daha case switch kullanmaya başlamadım ben if- else ile yazacağım diyorsanız

void Receive_Interrupt() // seri porttan data gelirse bu rutin çalışacak demektir.
{
       Rx=SeriPortRx_register; // Gelen datayı oku

       if ((State==0) && (Rx==0x41)) State=1;
       else if (State==1)
               {
                  if (Rx==0x42) State=2;
                  else State=0;
               }
       else if (State==2)
               {
                  if (Rx==0x43) State=3;
                  else State=0;
               }
       else if (State==3)
               {
                  A=Rx;
                  State=0;
               }
}
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: MrDarK - 28 Nisan 2014, 13:40:59
Tek tek gelen kodu kontrol etmek bence böyle mantıklı değil ;

Ana kod içindeyken interrupt rutini uart'dan gelen datayı bir buffer array içine aktarmalı ; daha sonra ana programda bu buffer registerı kontrol edecek uygulamayı aktif etmeli. Bu sayede zaten 19200 gibi baudrate datalar çoktan gelmiş olur. Yani tek tek sorgu çekmek yerine bir buffer içersine doldurup sadece uygulama kontrol programını aktif ederek tüm datayı kontrol edebiliriz. Süre tutmassa tüm dataların gelmesi için usart fonksiyonunu değiştirip önce data uzunluğu gönderilerek çözüm sağlanabilir. Ona göre interrupt fonksiyonu kendini konfigure edebilir.

Akış olarak düşünürsek ;


/** Main **/
static void Usart_Control_Execute (void)
{
      if(g_control_usartFlag != SET)
      return;

      Array_Kontrol_Fonksiyonu();
      g_control_usartFlag = CLEAR;
}

void main (void)
{
....

Usart_Control_Execute ();
}

void Receive_Interrupt() // seri porttan data gelirse bu rutin çalışacak demektir.
{
     RX_Array = RX;   // Gelen datalar array içine kayıtlanacak
     g_control_usartFlag = SET;
}
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 13:55:50
Diyelimki senin dediğin yöntemle kodlama yaptık.

Ana program içinde bir bölüm 1 sn den önce işini bitiremiyor olsun.

Interrupt rutini atıyorum 10 ms içinde 0x41 0x42 0x43 0x55 datalarını aldı ve buffera yazdı.

Ana program ancak  1 sn süren işini bitirdikten sonra buffera gelen verilerin neler olduğuna bakabilir ve gerekli tepkiyi verebilir.

Vermiş olduğum yazım şekli ana programa hiç müdahale etmez, ana programın ne yaptığı ile işini ne zaman bitireceği ile ilgilenmez fakat soruda sorulan işi layıkı ile yapar.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: MrDarK - 28 Nisan 2014, 14:12:36
Yapmaz demedik ki zaten hocam ;

Bence state machine mantığında önemli olan öncelikleri belirlemek sizin önceliğiniz datayı bi an önce yollamaksa tabiki bu işi interrupt içinde yapacaksınız.

Onun dışında state machine mantığı çoğu projede modüler kod tasarımını arttırıyor. Bu sayede istediğiniz işlemciye istediğiniz modülün taşımak için kodu çok bölmeden uygulayabiliyorsunuz. Ben o manada kontrol işini modülün kendi içinde denetlenmesini daha doğru buluyorum.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 14:32:49
Örneklere devam edelim.

Ledimiz ve 1 ms de bir int üreten timerımız ve seri portumuz var. Başkada bir donanım yok varsa da kullanımı yasak.

Seri portta 1 ms den daha kısa zamanda olmamak kaydıyla, ne zaman ve ne sıklıkta geleceği belli olmayan datalar ulaşmakta. Bu esnada ana programımız son derece önemli işlerle meşgul olmakta.  Aşağıda adı geçen X in ilk değeri 1 olsun.

Seri porttan;

0x01 gelirse derhal led yanacak ama X saniye sonra sönecek.
0x02 gelirse derhal led sönecek ama X saniye sonra yanacak.
0x03 gelirse derhal led tam tersi konuma geçecek (yanıyorsa sönecek, sönük ise yanacak) ama X saniye sonra ilk konumuna geri dönecek.
0x04 gelirse seri porttan gelecek ilk veri X değeri olarak atanacak.

Bu programı state machine mantığı kullanmadan yazabilecek varmı?
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: bakar - 28 Nisan 2014, 14:40:39
Hocam  önceki örneğinizde  interrupt rutinini daha çabuk terketmek için switch  case   kullanmak daha mantıklı bir yazım şeklimidir?
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 15:20:02
Derleyicinin ne yaptığına göre değişir. Switch case yapısının if else den çok bariz farklı olacağını sanmıyorum. Switch case, programı okumayı daha kolaylaştırıyor.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 18:59:49
Alıntı YapBu programı state machine mantığı kullanmadan yazabilecek varmı?

Yok mu?
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: ErsinErce - 28 Nisan 2014, 20:36:12
Alıntı yapılan: z - 28 Nisan 2014, 14:32:49
Örneklere devam edelim.

Ledimiz ve 1 ms de bir int üreten timerımız ve seri portumuz var. Başkada bir donanım yok varsa da kullanımı yasak.

Seri portta 1 ms den daha kısa zamanda olmamak kaydıyla, ne zaman ve ne sıklıkta geleceği belli olmayan datalar ulaşmakta. Bu esnada ana programımız son derece önemli işlerle meşgul olmakta.  Aşağıda adı geçen X in ilk değeri 1 olsun.

Seri porttan;

0x01 gelirse derhal led yanacak ama X saniye sonra sönecek.
0x02 gelirse derhal led sönecek ama X saniye sonra yanacak.
0x03 gelirse derhal led tam tersi konuma geçecek (yanıyorsa sönecek, sönük ise yanacak) ama X saniye sonra ilk konumuna geri dönecek.
0x04 gelirse seri porttan gelecek ilk veri X değeri olarak atanacak.

Bu programı state machine mantığı kullanmadan yazabilecek varmı?


istenen koşullar için mecburen böyle yazmak zorunda kalıyorsunuz örnek çok ters

birde kodu int içine mi yazıcaz? yoksa ana programa ek mi olacak?


int X=1,Y=0,Z=0;

TimerINT(){
    if(Y){
        Y--;
        if(Y==0){
            if(Z==1){
                LedOff();
            }
            if(Z==2){
                LedOn();
            }
            if(Z==3){
                LedToggle();
            }
        }
    }
}

SerialINT(){
    if(Z==5){
        X=Data;Z=0;
    }
    if(Data==1){
        Z=1;LedOn();Y=X*1000;
    }
    if(Data==2){
        Z=2;LedOff();Y=X*1000;
    }
    if(Data==3){
        Z=3;LedToggle();Y=X*1000;
    }
    if(Data==4){
        Z=5;
    }
}


Edit: Timer'ı kapatıp açma işi kaldırıldı
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 28 Nisan 2014, 21:34:45
Soruda Timer'in 1 ms de bir int caktigi belirtilmisti.

Dolayisi ile Timerin peryoduna mudahale etmemek gerekiyor.

Sonucta state machine haricinde yazilamayacak bir programla karsi karsiyayiz. Bunu ana programa da yazmanin yolu yok gorunuyor.

Bu arada bu soru bana sorulsaydi

yani;

0x01 gelirse derhal led yanacak ama X saniye sonra sönecek.
0x02 gelirse derhal led sönecek ama X saniye sonra yanacak.
0x03 gelirse derhal led tam tersi konuma geçecek (yanıyorsa sönecek, sönük ise yanacak) ama X saniye sonra ilk konumuna geri dönecek.
0x04 gelirse seri porttan gelecek ilk veri X değeri olarak atanacak.

Ornegin; 0x01 ardindan 100 ms sonra 0x02 gelseydi

ledi 100 ms boyunca yakar ardindan sondurur ve 1 saniye sonra tekrar yakardim.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: kantirici - 28 Nisan 2014, 22:43:19
@z devamını bekliyoruz hocam.
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: Klein - 29 Nisan 2014, 12:27:55
Alıntı yapılan: z - 28 Nisan 2014, 21:34:45
Sonucta state machine haricinde yazilamayacak bir programla karsi karsiyayiz. Bunu ana programa da yazmanin yolu yok gorunuyor.

State machine çalıştırmadan da yazılabilir bence.

Timer içerisinde X değeri geriye doğru sayar.  Değer 0 olduğunda portu  tersler.
Seri porttan komut geldiğinde  x değeri  ve port değeri yeniden yüklenir.
Bir tane de fonksiyon işaretçisi dizisi  kullanılıp , gelen veri array'ın indeksi olarak kullanılıp, doğrudan ilgili fonksiyon çağırılabilir.

Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: Erol YILMAZ - 29 Nisan 2014, 12:50:45
State Machine bence RTOS öncesi güzel bir uygulama...

tabi ki konuyu güzel tabana yayılmış bir uygulama ile görmekte fayda var.

void TaskBuzzer(void){
INT8U   ID = 1;

enum fsm{
   INIT,
   BEEP
};

switch (TASK_STATUS){

   case INIT:

      DOUT_BUZZER_INT = 0;

      if(sem.shortIntBeep){
         sem.shortIntBeep=0;
         TimerStart(T_INT_BUZZER, TSHORTBUZZER);
         TASK_STATUS=BEEP;
      }


burada belli ki TASK_STATUS birşeye define ile aktarılmış.

sem.shortIntBeep ile başka bir TASK tan tetiklendiğini düşünüyorum.

TimerStart(T_INT_BUZZER, TSHORTBUZZER); ile belli ki sanal timer lar kurulmuş ve bunlar kontrol ediliyor.

TASK_STATUS=BEEP; satırı ise uygun şartlar sağlanmış State Machine'de bir sonraki duruma geçeceğimizi belirtiyor.

Kısacası BEEP yaparken Mcu yu kilitleyip beklemiyoruz :)

Switch içindeki durumlara RAKAM değil de ENUM ile isim verilmesi anlamlı olmuş..
Düşünsenize 1,2,3 diye giderken 1 ile 2 arasında yeni bir durum tanımlamak zorunda olduğunuzu.
ENUM ile kolay, RAKAM ile meşakkatli ve hataya yol açabilir.

Ayrıca ENUM adı olarak FiniteStateMachine (fsm) tanımlandığı dikkatlerimizden kaçmıyor :)
Başlık: Ynt: State Machine mantigi ile program yazmak
Gönderen: z - 29 Nisan 2014, 13:08:14
Kelin hocam, Yazmayı dene. Ne yaparsan yap yazdıkların içinde state machine kendini gösterecek.

State machine yani durum makinesine hep örneklerle yaklaştık. Birazcık üzerinde konuşalım.

Geçmişte bir takım olaylar yaşanmış olsun. Şu anki tepkimiz, geçmişteki olaylara ve şu anki olaya bağlı olarak şekillenir.

Geçmişte 1 verisi gelmiş, çıkışı aktif etmişiz şu anda 100 ms olmuş. O halde şu anda bir şey yapmayayım (900 ms sonra çıkışı off yapalım) mantığında geçmişte girişlerimiz neymiş şu anda kaçıncı mili saniyedeyiz o halde şu anda çıkışımız ne olmalı sorgulaması yapıyoruz.

State machine mantığını zaten "sequantial logic" devre tasarımında uyguluyorduk. Bunun için durum diyagramı oluşturuyor ve FF (Flip Flop)ların durum geçiş ve çıkış tablolarını oluşturuyorduk. Yazılımda çok karmaşık bir durum yoksa doğrudan kodlama yapıyoruz. Fakat karmaşık bir durum makinesi kodlaması yapacaksak o zaman gene durum diyagramı ve tablolarını çizmemiz gerekir.

Durum diyagramı için bir örnek aşağıda görülmektedir. Buradaki yuvarlaklar durumları ifade eder. Fakat bu kısımlara girmeyi düşünmüyorum.

(http://www.ohio.edu/people/starzykj/webcad/ee224/lab3/lab3_files/image004.jpg)

Bir uygulama programını aşağıdaki gibi yazdığımızı varsayın;

          while(1)
               {
                    fonk1();     
                    fonk2();     
                    fonk3();     
                    fonk4();     
                    fonk5();     
                    Cok_Kritik_Fonk()
                }


Buradaki fonksiyonların birbirinden bağımsız yani ürettikleri sonuçların diğer fonksiyonlarca kullanılmayacağını varsayalım. Her bir fonksiyonun görevini 10 mili sn de tamamlıyor olsun. Fakat bu durumda Cok_Kritik_Fonk adındaki fonksiyon 60 mili saniyede bir çalışacak demektir. Bu fonksiyonun 60 ms de bir çalışması sistemin işlevini yitirmesi anlamına gelsin. Buna karşılık diğer fonksiyonların 100 hatta 1000 ms de bir çalışması hiç sorun teşkil etmesim.

Aynı programı bir de şu şekilde yazalım.


          State=0;
          while(1)
               {
                    State++;
                    if(State==1) { fonk1();  State02;}   
                    else if(State==2) { fonk2();  State=3;}                     
                    else if(State==3) { fonk3();  State=4;}                     
                    else if(State==4) { fonk4();  State=5;}                     
                    else if(State==5) { fonk5();  State=0;}                     
                    Cok_Kritik_Fonk()
                }


Bu durumda Cok_Kritik_Fonk her 20 mili saniyede bir çalışır ve sorun ortadan kalkar.
Burada Sate değişkeni geçmişi saklar. Yani geçmişte ne yapmışız bunu State değerine bakarak anlayabiliriz.
Şu anki davranışımızı gene State değerine bakarak belirleriz. Yukarıdaki örnekte State=4 ise demekki geçmişte fonk1, fonk2, fonk3 fonksiyonları çalışmış halde şimdi fonk4 fonksiyonu çalıştırmalıyız deriz.

Şu ana kadarki örneklerde hep State değişkenimiz bir bir arttı ve son değerde sıfırladık. Bu şart değildir.

Örneğin

             if (State==4) State=2;
             else if(State==3) State=7;

gibi durumdan duruma geçebiliriz.

Bunlara ait örnekleri de eğer yazıya devam edersek ayrıca vereceğim.