Stack problemi

Başlatan onurinci, 20 Haziran 2020, 23:40:47

onurinci

forumdan bulduğum bir projeyi kendi ihtiyaçlarıma göre yeniden düzenledim,simulasyonda hızlı hızı atlıyor,bu aşılabilir fakat 000 geri saydığında ,yanlışlıkla 000'dan da geri saymaya çalışırsam Stack yağmuruna tutuluyor ,999 sayısı aşıldığında böyle bir problem yok,birde 999 değilde 360'ta durması için ne yapmalıyım .iyi çalışmalar..
not PORTB=240 | BIRLER  burada | bu işaret neye yaryor ?
DEFINE OSC 4
@ DEVICE pic16F628A, WDT_OFF, PWRT_ON, PROTECT_OFF, MCLR_off, INTRC_OSC_NOCLKOUT

TRISA=%00000111           
TRISB=%00000000
              
BIRLER    VAR  BYTE          
ONLAR     VAR  BYTE          
YUZLER    VAR  BYTE          

PORTA=0
PORTB=0  
SYMBOL YUKARI=PORTA.0
SYMBOL  ASAGI=PORTA.1
SYMBOL  RESET=PORTA.2
CLEAR
;************** READING EEPROM *************************************************
READ 0,BIRLER
READ 1,ONLAR
READ 2,YUZLER

IF    BIRLER=255 THEN    BIRLER=0
IF     ONLAR=255 THEN     ONLAR=0
IF    YUZLER=255 THEN    YUZLER=0

;************** MAIN PROGRAM ***************************************************
BASLA: 
IF PORTA.2=0 THEN CLEAR
IF  YUKARI=0 THEN GOSUB ARTI
IF   ASAGI=0 THEN GOSUB EKSI
GOSUB EKRAN
GOSUB KAYIT
GOTO  BASLA
;************** COUNT UP ********************************************************
ARTI:
BIRLER=BIRLER+1                     ;COUNT UP
IF BIRLER=10 THEN    
BIRLER=0
ONLAR=ONLAR+1
ENDIF
IF ONLAR=10 THEN     
ONLAR=0
YUZLER=YUZLER+1
ENDIF

IF YUZLER=10 THEN    

YUZLER=9
ONLAR=9
BIRLER=9 
   ENDIF
PAUSE 10
 RETURN
;************** COUNT DOWN *****************************************************
EKSI:

IF BIRLER>0 OR ONLAR>0 OR YUZLER>0 then
BIRLER=BIRLER-1                         ;COUNT DOWN
ELSE 
GOTO BASLA
ENDIF
IF BIRLER=255 THEN 
BIRLER=9 
ONLAR=ONLAR-1 
ENDIF

IF ONLAR=255 THEN 
ONLAR=9
YUZLER=YUZLER-1
ENDIF

IF YUZLER=255 THEN 
YUZLER=9
ENDIF

PAUSE 10
RETURN
;************* LCD *************************************************************
EKRAN:
PORTB=240 | BIRLER   
LOW PORTB.7                  
PAUSE 1
HIGH PORTB.7
PAUSE 1
'~~~~~~~~~~~~~~~~~~~~  
PORTB=240 | ONLAR 
LOW PORTB.6
PAUSE 1
HIGH PORTB.6
PAUSE 1
'~~~~~~~~~~~~~~~~~~~~ 
PORTB=240 | YUZLER       
LOW PORTB.5                  
PAUSE 1
HIGH PORTB.5
PAUSE 1     
'~~~~~~~~~~~~~~~~~~~~ 
RETURN
;************* EEPROM **********************************************************
KAYIT:
WRITE 0,BIRLER    :PAUSE 10
WRITE 1,ONLAR     :PAUSE 10
WRITE 2,YUZLER    :PAUSE 10

RETURN
END

ete

Bütün sorunu yaratan kısım aşağıdaki yer.
EKSI:
IF BIRLER>0 OR ONLAR>0 OR YUZLER>0 then
BIRLER=BIRLER-1                         ;COUNT DOWN
ELSE 
GOTO BASLA
ENDIF
Gosub ile gelinen EKSI isimli alt programda şayet birler-onlar ve yuzler sıfır olur ve sen değer azaltmaya devam edersen program buraya gelir ve GOTO BASLA ile basa döner. Halbuki oraya GOSUB ile gelmiş idi ve RETURN ile dönmesi gerekirdi. Bu durumda gelirken sürekli stack dan adres alır ve goto ile başa döneceği için stack sıfırlanmadan başa döner ve sonunda stack şişer.
GOTO BASLA yerine oraya RETURN yazılmalıdır.
PORTB=240 | BIRLER  satırındaki "|" işareti lojik OR işaretidir. 240 rakamını binary olarak yazarsak %11110000 elde ederiz. Görüleceği üzere ilk 4 biti sıfır sondaki 4 bit ise 1 dir. Bu devredeki bir zorunluluk nedeni ile buraya koyulmuş. Görevi şu o portun sondaki 4 bitini sürekli 1 de tutmak. BU neden gerekli dersen 4511 in LT-BI ve LES pinlerinin sürekli HIGH da tutulma ihtiyacındandır.
Programın istenen bir sayıda durdurulması için başla bölümünün sonuna bir IF satırı eklenmesi gerekir. Aşağıda doğru program (BASLA satırından itibaren) yer almaktadır.

Ete
BASLA: 
       IF PORTA.2=0 THEN CLEAR
       IF  YUKARI=0 THEN GOSUB ARTI
       IF   ASAGI=0 THEN GOSUB EKSI
       
       GOSUB EKRAN
       GOSUB KAYIT
       IF YUZLER=3 AND ONLAR=6 AND BIRLER=0 THEN DURDUR       
       GOTO  BASLA
;************** COUNT UP ********************************************************
ARTI:
     BIRLER=BIRLER+1                     ;COUNT UP
     IF BIRLER=10 THEN    
       BIRLER=0
       ONLAR=ONLAR+1
     ENDIF
     IF ONLAR=10 THEN     
       ONLAR=0
       YUZLER=YUZLER+1
     ENDIF

     IF YUZLER=10 THEN    
       YUZLER=9
       ONLAR=9
       BIRLER=9 
     ENDIF
     PAUSE 10
     RETURN
;************** COUNT DOWN *****************************************************
EKSI:
     IF BIRLER>0 OR ONLAR>0 OR YUZLER>0 then
       BIRLER=BIRLER-1                         ;COUNT DOWN
     ELSE 
       RETURN
     ENDIF
     IF BIRLER=255 THEN 
       BIRLER=9 
       ONLAR=ONLAR-1 
     ENDIF

     IF ONLAR=255 THEN 
       ONLAR=9
       YUZLER=YUZLER-1
     ENDIF

     IF YUZLER=255 THEN 
       YUZLER=9
     ENDIF
     PAUSE 10
     RETURN
;************* LCD *************************************************************
EKRAN:
      PORTB=240 | BIRLER   
      LOW PORTB.7                  
      PAUSE 1
      HIGH PORTB.7
      PAUSE 1
'~~~~~~~~~~~~~~~~~~~~  
      PORTB=240 | ONLAR 
      LOW PORTB.6
      PAUSE 1
      HIGH PORTB.6
      PAUSE 1
'~~~~~~~~~~~~~~~~~~~~ 
      PORTB=240 | YUZLER       
      LOW PORTB.5                  
      PAUSE 1
      HIGH PORTB.5
      PAUSE 1     
'~~~~~~~~~~~~~~~~~~~~ 
      RETURN
;************* EEPROM **********************************************************
KAYIT:
      WRITE 0,BIRLER    :PAUSE 10
      WRITE 1,ONLAR     :PAUSE 10
      WRITE 2,YUZLER    :PAUSE 10
      RETURN

DURDUR:
       WHILE RESET=1:WEND
       BIRLER=0:ONLAR=0:YUZLER=0
       GOTO BASLA

END

onurinci

#2
hocam harika olmuş klavyenize emeğinize sağlık,aşağıda verdiğiniz programda tamda istenen değer 360'ta verilen şarlar ile duruyor harika,
fakat yukarı say butonu basık kaldı ise devreye yeniden enerji verdiğimizde 360 bariyerini aşıp yukarı doğru sayıyor acaba bunada bir önlem alınabilinirmi ?...

Hocam şimdi fark ettim 360 şa gelince aşma problemi bitti faka artık eksilt tuşu işe yaramıyor,normal durumda eksilt tuşu vazife yapıyor, sadece 360'şa dayanırsa komaya giriyor..

ete

Alınabilir elbette. Bu seferde başla satırından evvel bazı eklemeler yapmak lazım. Aşağıdaki program parçasını enbaştan BAŞLA etiketine kadar değiştir.
@ DEVICE pic16F628A, WDT_OFF, PWRT_ON, PROTECT_OFF, MCLR_off, INTRC_OSC_NOCLKOUT
DEFINE OSC 4
TRISA=%00000111           
TRISB=%00000000
              
BIRLER    VAR  BYTE          
ONLAR     VAR  BYTE          
YUZLER    VAR  BYTE          

PORTA=0
PORTB=0  
SYMBOL YUKARI=PORTA.0
SYMBOL  ASAGI=PORTA.1
SYMBOL  RESET=PORTA.2
CLEAR
pause 200
;************** READING EEPROM *************************************************
READ 0,BIRLER
READ 1,ONLAR
READ 2,YUZLER

IF    BIRLER=255 THEN    BIRLER=0
IF     ONLAR=255 THEN     ONLAR=0
IF    YUZLER=255 THEN    YUZLER=0
gosub ekran
IF YUZLER=3 AND ONLAR=6 AND BIRLER=0 THEN DURDUR  
;************** MAIN PROGRAM ***************************************************
BASLA: 

ete



onurinci

Hocam çok teşekkür ederim,harika olmuş, bu arada bende set değerlerini öğrenmiş oldum....

onurinci

Hocam son düzelttiğiniz ve paylaştığınız program set edilmiş 360 sayısını kesinlikle aşmıyor burası mükemmel olmuş,fakat 360 sayısına geldiğim zaman eksilme yada geri say tuşu işlevini yitiriyor,E2rom'a yazması gerektiği için enerjiyi kesip yeniden vermemde bir sonuç vermiyor.ama 359 kadar sayarsam dilediğim gibi geri gelebiliyorum,sanki bu set değeri sayısına gelindiğinde MCU koma'ya giriyor,ben epey uğraştım,bir netice elde edemedim...

ete

Yüzeysel (programa yada algoritmaya hakim olmadan) program düzeltmesi bu kadar olur.
Her şeyi yerli yerine oturtmak için olaya hakim olmak ve ne istenildiğini detaylı olarak bilmek gerekiyor.
Aşağıda programı son açıklamaya uygun hale getirdim getirirkende lüzümsuz uzun olan programı daha kısa kodlarla çalışır hale getirdim. Sistem yanlızca 3 hane saydığı için hane bazlı saydırma sistemi yerine direk sayı saydırma yöntemini kullanmak daha akıllıca olacaktı onu uyguladım.

Ete
@ DEVICE pic16F628A, WDT_OFF, PWRT_ON, PROTECT_OFF, MCLR_off, INTRC_OSC_NOCLKOUT
DEFINE OSC 4
TRISA=%00000111           
TRISB=%00000000
              
BIRLER    VAR  BYTE 56         
ONLAR     VAR  BYTE 57         
YUZLER    VAR  BYTE 58 
'ARA       VAR  BYTE 59 
DUR       VAR  WORD 70 
SAYAC     VAR  WORD 72     
YAZ       VAR  BIT
PORTA=0
PORTB=0  
SYMBOL YUKARI=PORTA.0
SYMBOL  ASAGI=PORTA.1
SYMBOL  RESET=PORTA.2
CLEAR
pause 200
;************** READING EEPROM *************************************************
READ 10,SAYAC.BYTE1,SAYAC.BYTE0
IF SAYAC=65535 THEN SAYAC=0

gosub ekran
DUR=360  'BURAYA DURULACAK SAYI YAZILMALIDIR
;************** MAIN PROGRAM ***************************************************
BASLA: 
       IF PORTA.2=0 THEN CLEAR
       IF  YUKARI=0 THEN GOSUB ARTI
       IF   ASAGI=0 THEN GOSUB EKSI
       
       GOSUB EKRAN
       IF YAZ=1 THEN GOSUB KAYIT     
       GOTO  BASLA
;************** COUNT UP ********************************************************
ARTI: 
     IF SAYAC=DUR THEN RETURN
     SAYAC=SAYAC+1:YAZ=1
     IF SAYAC=1000 THEN SAYAC=999
     PAUSE 100
     RETURN
;************** COUNT DOWN *****************************************************
EKSI:
     IF SAYAC=0 THEN RETURN
     SAYAC=SAYAC-1 :YAZ=1    
     PAUSE 100
     RETURN
;************* LCD *************************************************************
EKRAN:
      BIRLER=SAYAC DIG 0
      PORTB=240 | BIRLER   
      LOW PORTB.7                  
      PAUSE 1
      HIGH PORTB.7
      PAUSE 1
'~~~~~~~~~~~~~~~~~~~~  
      ONLAR=SAYAC DIG 1
      PORTB=240 | ONLAR 
      LOW PORTB.6
      PAUSE 1
      HIGH PORTB.6
      PAUSE 1
'~~~~~~~~~~~~~~~~~~~~ 
      YUZLER=SAYAC DIG 2
      PORTB=240 | YUZLER       
      LOW PORTB.5                  
      PAUSE 1
      HIGH PORTB.5
      PAUSE 1     
'~~~~~~~~~~~~~~~~~~~~ 
      RETURN
;************* EEPROM **********************************************************
KAYIT:
      WRITE 10,SAYAC.BYTE1,SAYAC.BYTE0:PAUSE 10
      YAZ=0
      RETURN

END

onurinci

Hocam emeğinize sağlık,bende yeni yöntemi öğrenmeye çalışacağım..

hasanemmii

Hocam merhaba.
GOSUB ile gittiğimiz yerden RETURN ile dönmemiz gerekir.
Son programımda IF içeren 3 satır, programın 30 küsur yerine yazmak gerekiyor.
Bu durumda alt program yapıp,  git-hallet-geri gel yapılabilir.

Ancak alt programda kullanılan IF şartı gerçekleştiğinde geri gitmek yerine ana programa dönülmesi gerekiyor.
Bu durumda Stack yığılması oluşacak.
GOSUB ile gidilip, geri dönülmeyecek bir durumda stack adresini silmek mümkün mü?

Yoksa RETURN ile geri dönülen her satıra yine bir IF şartı eklenmesi gerekiyor.
Teşekkürler.

Hattuşa

alt programa gitmeden olduğu yerde şartı irdeleseniz olmuyor mu? yada örnek bir kod koysanız üzerinden tartışsak

hasanemmii

PAUSE 30
SAY3=SAY3+1                  'ANA MENUYE OTOMATIK DONME SAYICISI
If SAY3>250 Then ANAMENU     '7 SN DIR TUSA BASILMADIYSA

30 dan fazla yerde yukarıdaki sayıcıyı devam ettirmem gerekiyor. Her butona basılışta sayıcı sıfırlanıyor ve başka bir alt programa yönleniyor. Yaklaşık 7sn butonlara basılmazsa sayıcı 250 yi geçiyor ve ana menüye dönülüyor.
Yukarıdaki sayma işlemini farklı alt programlarda devam ettirmem gerekiyor.

Bu nedenle bu üç satırı alt program olarak yazayım git geri gel şeklinde kullanayım diyorum. Ama bu kez de her geri geldiği yere sayıcı 250 yi geçtimi? demem gerekiyor. 30 adet daha IF kullanılacak.

Bunun yerine alt programda sayıcı 250 yi geçmezse RETURN, geçerse GOTO ANAMENU demek istiyorum. Ancak stack silinmesi gerek. stack silmenin yolu var mı?

ete

GOSUB ile gittiğiniz yerden kesinlikle GOTO ile dönmeyin. Bu eninde sonunda stack taşması meydana getirecektir. Taşma ise program kilitlenmesi yada programın bir noktada kararsız kalması anlamına gelir.
Bu gibi durumlar için bir işaret biti kullanılması uygun olur. Şöyle;
GOSUB ALTPROGRAM
IF DONBASA=1 THEN GOTO BASLANGIC
...
...
ALTPROGRAM:
SAY=SAY+1
IF SAY>250 THEN DONBASA=1
...
...
RETURN
Şimdi ne anlama geliyor ona bakalım. DONBASA bir bit değişkeni. Sizin BASA gidip gitmemenize karar verdirecek olan bit. ALt programa Gosub ile gittiniz. Orada sayac saydırıyorsunuz ve sayac 250 den büyük olunca geldiğin yere dönmesinde başa dönsün istiyorunuz. Ama o şekilde olmuyor. Ancak alt programda DONBASA değişkenini set ederek geri dönüşte Başlangıca gidileceğini programa anlatmış oluyorsunuz. Temel kaide şöyle GOSUB ile git RETURN ile dön. Şayt Gosub ile gittiğin yerde başka bir etikete atlama ihtiyacı doğmuş ise bunu bir bit değişkenini set ederek belirle ve RETURN ile geri döndükten sonra o değişkeni test et ve set edilmiş ise oradan yeni etikete git. Bu arada unutulmasın. DONBASA değişkeni set edildikten sonra ancak Basa dönüldüğü yerde reset edilmeli (sıfırlanmalıdır) yoksa program iş yapamaz.

hasanemmii

Aynen dediğiniz gibi yapmıştım hocam. Lakin yine her dönülen yerde IF kullanılmak zorunda. Toplamda 30 civarı IF kullanılmak zorunda kalınıyor. Sanırım stack silme imkanımız yok. İlginize teşekkür ederim.

Powered by EzPortal