WORD tipi bir değişkenin içeriğini değiştirmek.

Başlatan Kaldirim_Teknikeri, 07 Aralık 2009, 00:19:28

Kaldirim_Teknikeri

İçeriği 0-999(sayıcı) değişken bir sayı olan word tipi bir sabit değerin içeriğini donanımsal olarak iki butonla değiştirip değişken içinde saklamak istiyorum izleyeceğim yol ne olmalı?

Mesela bir örnek vereyim sayıcı 0'dan 999'a kadar sayarken sayac=100 olduğunda herhangi bir portun bitini set edeceğim. Daha doğrusu sayac=100 değerini dışarıdan iki butonla değiştirmek istiyorum ve sayac değerini görebilmek için ek olarak bir lcd'de ekleyebilirim.

Yorumlarınızı değerlendirerek kod yazmaya çalışacağım.

mustafa_cmbz

Alıntı yapılan: "Kaldirim_Teknikeri"İçeriği 0-999(sayıcı) değişken bir sayı olan word tipi bir sabit değerin içeriğini donanımsal olarak iki butonla değiştirip değişken içinde saklamak istiyorum izleyeceğim yol ne olmalı?

Mesela bir örnek vereyim sayıcı 0'dan 999'a kadar sayarken sayac=100 olduğunda herhangi bir portun bitini set edeceğim. Daha doğrusu sayac=100 değerini dışarıdan iki butonla değiştirmek istiyorum ve sayac değerini görebilmek için ek olarak bir lcd'de ekleyebilirim.

Yorumlarınızı değerlendirerek kod yazmaya çalışacağım.
say:
ıf buton=1 then sayac=sayac+1 
ıf sayac=100 then alarm 
goto say



butona basılı tuttuğunda 100e kadar sayar buna while wend li bi döngü eklersen her basışta 1 arttıracak şekilde de yapabilirsin...

Kaldirim_Teknikeri

Kusura bakmayın sanırım anlatmayı beceremedim yada siz beni anlayamadınız. Ben aşağıda ufak bir kod ve parçası yazmaya çalıştım. Bu sayıcı bir döngü içinde olduğu için sürekli 0-999 tekrar yapıyor.

IF SAYAC=100 THEN GOSUB CIKIS1


yukarıdaki sayac=100 adlı kod parçasında 100 değerini dışarıdan iki butonla arttırıp azaltmak ve seçtiğim değeri kaydetmek istiyorum. Şimdi umarım anlatabilmişimdir.

SAYAC VAR WORD
CLEAR

SAYAC=$0 
READ 0, SAYAC
IF SAYAC=999 THEN SAYAC=0 

BASLA:

IF SAYAC=100 THEN GOSUB CIKIS1

SAYAC=SAYAC+1
WRITE 0,SAYAC
PAUSE 10
IF SAYAC=999 THEN SAYAC=0

LCDOUT $FE,1
PAUSE 10
LCDOUT $FE,$C0,"SAYAC=",DEC3 SAYAC
PAUSE 50

GOTO BASLA

CIKIS1:
HIGH PORTA.0 : PAUSE 100 : LOW PORTA.0
RETURN

END


Yani benim düşüncem sayac değeri sabit kalacak. Burada 100 dediğim sayı 0-999 arasında değişebilen farklı bir register olacak. İşte bunu nasıl yaparım bilemiyorum :roll:

ete

Bana kalırsa hala ne istediğini anlatamadın sen. Zira isteğine bakıyorum ve birde yaptıklarına bakıyorum tamamen istediklerini yapmışsın.
Tek eksik olan buton kontrolü orda . Onuda Mustafa belirtmiş ama öyle değil demişsin. Ben anlamadım. Bir şeyler hissediyorum yani 6. hisiim bana diyorki bu arkadaş sayac değerini değilde döngüden dışarı çıkış değerini butonla değiştirmek istiyor. Zaten bana kalırsa başka alternatif de yok sanırım.
Peki şimdi bu alternatife göre düşünelim. Senin dışarı çıkış sayını bir değişkene verelim ve adınada LIMIT diyelim.
Program çalıştığı zaman LIMIT değerini 0 nolu eepromdan okusun ama birde default değeri olsun.
Read 0,LIMIT
If limit=255 then limit=100

Şimdi iki tus tanımlayalım.
Symbol ARTI=PortA.0  (rastgele tanımladım doğru pini sen verirsin)
Symbol EKSI=PORTA.1

Şimdi senin döngü içine gerekli ilaveleri yapalım.

IF ARTI=0 Then
  LIMIT=LIMIT+1
  POz=1
ENDIF
IF EKSI=0 Then
  LIMIT=LIMIT-1
  POZ=1
ENDIF
IF POZ=1 THEN
  WRITE 0,LIMIT:PAUSE 10
  POZ=0
ENDIF
Neden böyle yaptım hem Artı Hemde Eksi tuşuna basabilirsin her seferinde kayıt yapmasın yalnızca bir kere kayıt yapsın diye bunu yaptım.

IF SAYAC=LIMIT THEN GOSUB CIK

İşte hepsi bu kadar.
Umarım doğru anlamışımdır. Gerekirse LIMIT max değeri ile Min değerlerini artırma yada eksiltme kısımlarında ayrıca kontrol edebilirsin. Mesela şöyle yazabilirsin.
IF LIMIT <255 THEN LIMIT=LIMIT+1
yada
IF LIMIT>0 THEN LIMIT=LIMIT-1
böylece birisi sıfıra kadar düşer diğeride 255 e kadar artar.

KOlay Gelsin,
Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

Kaldirim_Teknikeri

Teşşekkürler, problemi düzgün aktaramadığım için üzgünüm fakat yine bilgilerinizden faydalanarak yapmak istediğim şeyi gerçekleştirdim. :) Fakat ne kadar doğruyum bilemiyorum.
DEFINE LCD_DREG  PORTB
DEFINE LCD_DBIT  4
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG  PORTB
DEFINE LCD_EBIT  1
DEFINE LCD_BITS  4
DEFINE LCD_LINES 2

TRISA=25 : TRISB=0 : PORTB=0
       
POZ      VAR BIT
SAYAC    VAR BYTE
DEGISKEN VAR BYTE
CLEAR

SYMBOL ARTI=PORTA.0
SYMBOL EKSI=PORTA.1
SYMBOL LED=PORTA.2

SAYAC=00 : DEGISKEN=00
READ 0,DEGISKEN
IF DEGISKEN=25 THEN DEGISKEN=00
READ 1,SAYAC
IF SAYAC=25 THEN SAYAC=00

BASLA:

IF SAYAC=DEGISKEN THEN 
HIGH LED : PAUSE 200 : LOW LED
ENDIF

IF ARTI=1 THEN
DEGISKEN=DEGISKEN+1
IF DEGISKEN=25 THEN DEGISKEN=00
POZ=1
ENDIF
IF EKSI=1 THEN
DEGISKEN=DEGISKEN-1
IF DEGISKEN=00 THEN DEGISKEN=25
POZ=1
ENDIF
IF POZ=1 THEN
WRITE 0,DEGISKEN : PAUSE 10 
POZ=0 
ENDIF 

SAYAC=SAYAC+1
PAUSE 100
IF SAYAC=25 THEN SAYAC=00
LCDOUT $fe,1," SAYAC= ",dec2 SAYAC
LCDOUT $fe,$C0," DEGISKEN= ",dec2 DEGISKEN
PAUSE 100

GOTO BASLA


Anlamadığım birkaç nokta var bu konuda beni aydınlatırsanız sevinirim.

Devreyi delikli plaket üzerine kurmayı becerdim.

LCDOUT $fe,1,"SAYAC=",dec2 SAYAC


Yukarıdaki kodu gerçekte denediğimde lcd'de AYAC=00 olarak okuyorum ve kesintili olarak ve yukarıdaki kodun yerine,

LCDOUT $FE,1
PAUSE 10
LCDOUT "SAYAC=",dec2 SAYAC
PAUSE 100


kullandığımda yazı güzel okunuyor fakat biraz titreşim oluyor. Bu titreşimide pot ile min seviyeye düşürdüm.

ve sadece 1. satırda bu problemi yaşıyorum. Benim düşündüğüm LCDOUT $fe,1 kodunun lcd'yi temizlemesinden kaynaklandığı için olabilir.

Diğer bir noktada,

IF ARTI=1 THEN
DEGISKEN=DEGISKEN+1
IF DEGISKEN=25 THEN DEGISKEN=00
POZ=1
ENDIF
IF EKSI=1 THEN
DEGISKEN=DEGISKEN-1
IF DEGISKEN=00 THEN DEGISKEN=25
POZ=1
ENDIF
IF POZ=1 THEN
WRITE 0,DEGISKEN : PAUSE 10 
POZ=0 
ENDIF


buton ile kontrol ettiğimi düşünürsem sayac=25 olduğunda sayac=0 oluyor ve hemen arkasından sayac değerini 1 eksilttiğimde sayac=55 oluyor. Yani bu kısım biraz kafa karıştırıcı gibi.

ete

Birinci sorunu gidermek için biraz komut gecikmesi ilave etmek gerek. Aşağıdaki satırları LCD dfine komutları altına ilave et.

DEFINE LCD_COMMANDUS 2000 'Command delay time in us
DEFINE LCD_DATAUS 50 'Data delay time in us

Öneri olarak söylüyorum. Kullanacağınız PAUSE ler var ise bunu LCDOUT satırından önce kullanmamaya özen gösterin. Pause den heman sonra LCDout komutu geliyor ise PAuse yi LCDOUT komutundan sonra ve gerekirse varsa Pauseleri birleştirerek kullanın. Bu sizin görüntünüzün titremeden ekranda kalmasını sağlayacaktır. Senin örneğinde;
SAYAC=SAYAC+1
PAUSE 100
IF SAYAC=25 THEN SAYAC=00
LCDOUT $fe,1," SAYAC= ",dec2 SAYAC
LCDOUT $fe,$C0," DEGISKEN= ",dec2 DEGISKEN
PAUSE 100
şeklinde komutlar va bunu şöyle yazmak daha doğru olurdu;

SAYAC=SAYAC+1
IF SAYAC=25 THEN SAYAC=00
LCDOUT $fe,1," SAYAC= ",dec2 SAYAC
LCDOUT $fe,$C0," DEGISKEN= ",dec2 DEGISKEN
PAUSE 200

Ayrıca desiam saylarda 00 şeklinde bir ifade kullanılmaz. Hexadesimalde kullanılır. Desimal için Sayac=0 demeniz yeterlidir. Yada Sayac=$00 demeniz gerekir.

İkinci sorunu izah etmekte çok basit. Tamamen bir komut mantığı hatası.

Şimdi If SAYAC=25 then SAYAC=0  demişsin. Nerede eksiltiyorsun bilemiyorum ama Sayac değerini önce eksiltip
Sayac=Sayac-1 şeklinde ve sonra;
If Sayac=0 Then sayac xx
der isen IF komutu sayacın sıfır halini hiç göremeyecek demektir.
Zira sıfır olan sayac değerini bir eksiltirsen sayac=255 olur ve sende zaten bu değeri ekranda görüyorsun Dec2 kullandığın için 55 kısmını görüyor ama 2 yi göremiyorsun.

Ne yapmak gerek. Muhtemelen IF sayac=255 then Sayac=25 demek daha doğru olur sanırım.
Yada IF SAYAC=0 then SAYAC=25 komutunu , SAYAC=SAYAC-1 komutundan önce kullanmak gerekir.

Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

Kaldirim_Teknikeri

Değerli zamanınızdan kesip vaktinizi benim için harcıyorsunuz. Bunun için teşekkür ederim. Sorması ayıp bu kadar bilgiyi nereden ve hangi kitapdan öğrendiğinizi sorabilirmiyim? :roll:
DEFINE LCD_COMMANDUS 2000 'Command delay time in us 
DEFINE LCD_DATAUS 50 'Data delay time in us

Öneriniz ve söylediğiniz komutlar işe yaradı. Fakat ikinci yöntemi dediğiniz gibi yapmışım fakat olmadı. Kod aşağıdaki gibidir.

A:
IF KAYIT=1 THEN GOTO B
IF YUKARI=1 THEN
SAYAC=SAYAC+1
IF SAYAC=999 THEN SAYAC=0
POZ=1
ENDIF
IF ASAGI=1 THEN
SAYAC=SAYAC-1
IF SAYAC=0 THEN SAYAC=999
POZ=1
ENDIF
IF POZ=1 THEN
WRITE 0, SAYAC
PAUSE 50 ' PAUSE 50 'Yİ PIC 20MHZ'DE ÇALIŞTIĞI İÇİN YAZDIM.
POZ=0
ENDIF
LCDOUT $FE,1,"SAYI=",DEC3 SAYAC
PAUSE 50
GOTO A


Donguden çıkma ile alakalı bir sorun daha yaşıyorum. Burada amacım menü gibi birşey yapmaktı. Gosub komutunuda denedim zaten mantıksız geldiği için goto komutunu kullandım.  

A:
IF KAYIT=1 THEN GOTO B
IF YUKARI=1 THEN
SAYAC=SAYAC+1
IF SAYAC=999 THEN SAYAC=0
POZ=1
ENDIF
IF ASAGI=1 THEN
SAYAC=SAYAC-1
IF SAYAC=0 THEN SAYAC=999
POZ=1
ENDIF
IF POZ=1 THEN
WRITE 0, SAYAC
PAUSE 50 ' PAUSE 50 'Yİ PIC 20MHZ'DE ÇALIŞTIĞI İÇİN YAZDIM.
POZ=0
ENDIF
LCDOUT $FE,1,"SAYAC=",DEC3 SAYAC
PAUSE 50
GOTO A

B:
IF KAYIT=1 THEN GOTO C
IF YUKARI=1 THEN
SAYAC=SAYAC+1
IF SAYAC=999 THEN SAYAC=0
POZ=1
ENDIF
IF ASAGI=1 THEN
SAYAC=SAYAC-1
IF SAYAC=0 THEN SAYAC=999
POZ=1
ENDIF
IF POZ=1 THEN
WRITE 0, SAYAC
PAUSE 50 ' PAUSE 50 'Yİ PIC 20MHZ'DE ÇALIŞTIĞI İÇİN YAZDIM.
POZ=0
ENDIF
LCDOUT $FE,1,"SAYAC=",DEC3 SAYAC
PAUSE 50
GOTO B

C:
...
...
...


bu kodda devreye enerji verdiğimde a döngüsü çalışıyor. Kayıt=1 yaptığımda b döngüsüne geçmesini beklerken başka yerlere dallanma oluyor yani program başka yerlere gidiyor. Mesela, c'ye gidiyor yada e'ye birkaç defada program sonuna gitti çalışma durdu.

WHILE WEND kullansam bu problem giderilirmi acaba? :roll:

Ben gerçekten bu kitaba çalışıyorum mesela goto komutunu inceliyorum. Goto komutu programın başka yerden çalışmasına yarar demiş konuyu kapatmış. Detay yok yani.

goto gonder
...
...
gonder:


verdiği örnekte hemen yukarıdaki gibi saygısızlık yapmış olmayayım ama bana kalırsa hiç güzel anlatamamış.

ete

Hemen belirteyim. Öğrendiklerimi kitaplardan öğrenmedim. Pic Basic den önce de Basic biliyordum. Ama o bildiğim basic'i de kitaptan öğrenmedim. Zira o devirde (1985 li ) yıllar öncesi bu konuda yazılmış kitap bile yok idi. Olanlar ise son derece basit bir kaç komut öğretiyor idi o kadar. Kendi kendime ve programların Help lerinden yararlanarak zaman içinde bilgimi geliştirdim.
İnsan eşeleye eşeleye öğrenince sanırım kitaplarda yazılmayanlarıda öğrenmek zorunda kalıyor. Zaman zamanda bu ve benzeri forumlarda öğrendiklerimi bilmeyenlere öğretmeye çalışıyorum.

Birinci sorunun hallolduğuna göre ikinciyi halletmeye çalışalım. Tekrar baktımda bir iki hata diyemeyeceğim ama pek de benimsemediğim kusurlar dan dolayı olduğunu düşünüyorum bu hatanın.  Neler olduğunu açıklayayım,
Şimdi Bir tarafta Sayac değişkenine 999'a ulaşınca  sıfır ol demişsin.  Ama diğer tarafta sıfır olunca da 999 ol demişsin bu bir çelişkidir. Bu işin doğrusu;
SAYAC değişkeni 999'u aşarsa yani 1000 olursa sıfıra eşitlenmeli, diğer taraftanda SAYAC değişkeni aşağı doğru sıfır aşarsa yani sıfırın altına ulaşırsa 999'a eşitlenmelidir.
Birincisi kolay , IF SAYAC=1000 THEN SAYAC=0 , bu tamam.
İkincisi zor değil. WORD değişkeni sıfırdan sonra bir eksiltilir ise değeri 65535 olur. O halde komut şöyle olmalı;
IF SAYAC=65535 then SAYAC=999
Bu şekilde SAYAC değişkeni birer eksiltmede önce sıfır değerine ulaşabilmeli ve sonra eksiltme devam ederse 999'a atlamalıdır.
Artırmada ise önce 998 'e ulaşmalı sonra 999 olmalı ve yeniden artırılırsa değeri sıfır olmalıdır. Yukarıda dediklerimi yaparsan bu sorun da düzelecektir sanırım. Aslında bir simulasyon dosyan olsa idi orada deneyebilirdik.

Program satırlarına dikkat edersen;
IF SAYAC=999 then SAYAC=0  bu komut sayac değerini 999 dan sıfır değerine eşitler. Şimdi sayac=0 oldu.
hemen altında ise Şayet  Aşağı tuşuna basarsan bu seferde;
IF ASAGI=0 THEN
SAYAC=SAYAC-1
komutu gelecek ve değeri sıfır olan sayac bir eksiltilince değeri 255 olacaktır.
Sende ekranda tabiiki 55 değerini göreceksin.
Bu nedenle dediklerimi uygularsan bu sorun hallolacaktır.
İllaki bu hali ile kullanmak istersen o zaman aşağıdaki komut satırlarını yazıldığı gibi düzelt.
IF ASAGI=1 THEN
SAYAC=SAYAC-1
IF SAYAC=0 OR SAYAC=255 THEN SAYAC=999

Ama işin doğrusu benim açıkladığım şekildedir.
Limitler 1000 ve 0 olmalı .

Bir konu dikkatimi çekti uyarayım istedim. Eeproma kayıt kısmında kayıttan sonra 10 ms lik gecikmeyi 20 Mhz de çalışıyor diye 50 ms olarak vermişsin.
Programın başında "DEFINE OSC 20" şeklinde komut satırı ilave edersen pic hangi frekansta çalışırsa çalışsın pause ler gerçek sürelerinde işlenir.
Pause 10 demişsen bu gerçekten 10 ms lik gecikme olarak uygulanır. Dolayısıyla bunu 50 yapman gerekmez.

Şimdi dallanma ile ilgili problemine bakalım.
A: etiketi altında ,
IF KAYIT=1 THEN GOTO B   şeklinde bir komut var. Şimdi diyelimki Kayıt=1 ve A döngüsünde çalışırken yukarıdaki komutu gördü program ve hemen B etiketine atladı. Dikkatini çekiyorum B etiketine gelirken veriler şunlar;
KAYIT=1 hala kayıt 1 değerini taşıyor.
Şimdi B etiketindeki ilk satıra bakalım,
IF KAYIT=1 THEN GOTO C
hemen anlaman gerek sanırım. Burada da Kayıt=1 ise C etiketine git şeklinde bir komut var. O halde program artık bağlasan durmaz B bölümünde ve tabiiki C etiketine atlayacaktır. Kimbilir C de de ayrıca bir satır vardır IF KAYIT=1 THEN GOTO D gibi bir şey de olabilir. Program ordan başka bir yere gidiyordur ve sende ipin ucunu muhtemelen kaçırıyorsundur.
Bu tip şeylere çok dikkat etmek gerek. Şayet belirli bir iş için bir yere gidip tekrar geri dönmen gerekiyor ise mutlaka GOSUB ile gidip RETURN ile dönmek gerek. Ama orada RETURN dan başka ayrıca GOTO şeklinde bir komut olmamalı. Aslında Goto olabilir ama goto ile gidilen yerden mutlaka bir RETURN ile ilk dallanmanın yapıldığı yere dönmek gerekir. Bunlar önemli şeyler ve programın sıhhatli çalışmasını etkileyen hususlardır. Yoksa program kitlenir kalır bir yerde.
Çok fazla Goto kullanmak da sakıncalıdır. İşlerin bir kısmını Gosub ile halletmeniz gerekir. GOTO komutu programın bir başka yerde çalışmaya devam etmesini sağlar. İyi bir programda bir ana program kısmı vardır. Ek işler GOSUB ile gidilip RETURN ile dönülen alt programlarda halledilir. Ama esas çalışma yeriniz Ana program kısmıdır. Programlarınızı bu esaslar üzerine yazınız. Bol bol örnek inceleyin onlar size programı yazan kişinin neyi nasıl düşündüğünü anlatır ve sizinde benzer şekilde düşünmenizi sağlar.
Bu konuda forumda yayınlanmış 13 dersten oluşan dersler yazmıştım . Bilmem aldınızmı. Hala almadınız ise alın ve inceleyin bayağı faydası olacaktır size.

Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

Kaldirim_Teknikeri

Şimdi sizi çok iyi anlıyorum ve onca yıllık tecrübelerinizi bizlerle paylaştığınız için çok teşekkür ediyoruz.

İkinci sorunda söylediğiniz gibi aşağıdaki kod parçası ile düzeldi.
IF SAYAC=1000 THEN SAYAC=0
IF SAYAC=65535 THEN SAYAC=999


Önerinizi dikkate alarak süreleri 10ms yaptım. Daha sağlıklı olduğunu düşünüyorum. Çünkü bazen chip'i resetlediğimde değerler değişiyordu. Şimdi o sorunda yok gibi.

Dallanma ile ilgili yazınızı birkaç defa okuduktan sonra yine sizden öğrendiklerimi birleştirerek aşağıdaki gibi bir kod oluşturdum ve çok sağlıklı çalışıyor.

MENU VAR BYTE
CLEAR

SYMBOL ARTI=PORTA.0
SYMBOL GEC=PORTA.2

MENU=0
READ X, DEGISKEN
...
IF MENU=8 THEN MENU=0

LOOP:

IF ARTI=1 THEN
MENU=MENU+1
PAUSE 100
IF MENU=8 THEN MENU=0
ENDIF

IF GEC=1 THEN
LCDOUT $FE,1
GOTO BASLA
ENDIF

IF MENU=0 THEN
...
ENDIF

IF MENU=1 THEN
...
ENDIF

IF MENU=2 THEN
...
ENDIF

.....

GOTO LOOP

READ Y, DEGISKEN
...

BASLA:
...
...
...
GOTO BASLA


Birşeyler öğrendiğimi düşünüyorum ve dökümanlarınızıda kısa zaman içinde indirip okumaya çalışacağım. Umarım tekrar başınızı ağrıtmam.

Kendinize iyi bakın...