State Machine mantigi ile program yazmak

Başlatan z, 28 Nisan 2014, 01:16:22

z

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.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

z

Alıntı YapBu programı state machine mantığı kullanmadan yazabilecek varmı?

Yok mu?
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

ErsinErce

#17
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ı

z

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.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

kantirici


Klein

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.


Erol YILMAZ

#21
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 :)

z

#22
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.



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.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com