mplab'da if else endif kullanımı hakkında

Başlatan camby, 28 Şubat 2010, 05:43:24

camby

Registerda tanımladığım bir değişkenin değeri Ana programımdaki sayacıma göre 0-9 arası değişebiliyor , her kesme vakti geldiğinde , kesme bloğu içinde , bu değişkenin içindeki değere göre farklı bir işlem yapmam gerekiyor , hoş şu an yapıyorum ama btfss ve btfsc lerden bıktım , sırf bu yüzden C'ye geçecem artık:D

Bunu if else endif kullanarak yapmaya çalışıyorum olmuyor , sadece variable , constant ve set kullanarak belirlediğim sayısalları tanıyor , hadi diyelim öle yaptım variable değişkenini normal register değişkenlerim gibi sayacımda yada ana programımda kullanamıyorum ki işime yarasın. yardım...

if sayac==0
call AAA
else
nop
endif

if sayac==1
call BBB
else
nop
endif
.....


tabi bütün durumları elseif gibi birşey kullanarak tek bir if altında dallandırmak da istiyorum ki bu da çok lüks galiba asm için:)

kodun çalışan hali:
      movlw		.0		
		subwf		sayac,0
		btfss		STATUS,2	
		btfsc		STATUS,2
		CALL		AAA

		movlw		.1		
		subwf		basamaksayaci,0
		btfss		STATUS,2	
		btfsc		STATUS,2
		CALL		BBB
.....

Tagli

Bu yapıyı assembly dilinde kullanamazsın, çünkü böyle komutlar yok. Bunlar "directive" olarak geçer, PIC'te çalışacak komutlar değildir, sadece assembler'a yol gösterirler. If - else yapısı genelde kodun taşınabilirliğini arttırmak için kullanılır. Mesela aynı kodun iki farklı PIC'te çalışması isteniyorsa, kodun bir bölümünin PIC modeline göre derlenip derlenmemesi sağlanabilir. Örneğin PIC eğer 16F84 ise altına yazılımsal seri iletişim kodunu yazarken 16F628 ise donanımsal seri portu kullanacak kodu yazabilirsin, programın diğer kısmı aynı olur, tek satırı değiştirerek iki PIC için de çalışacak bir kod elde edersin. Özellikle kütüphane oluşturuyorsan çok işine yarayabilir. Bu tür büyük işlere girmediğim için ben hiç kullanmadım.

Bir değişkenin değeri sıralı olarak değişiyorsa ve her farklı değeri için farklı bir iş yapman gerekiyorsa tabloları kullanabilirsin. GOTO ve RETLW tabloları bu gibi durumlarda yüksek seviyeli dillerde if-else yapısıyla gerçekleştirdiğin pek çok işi gerçekleştirebilirler.

Ayrıca 18 serisinde sayıları birbiriyle karşılaştırıp ona göre atlama yapmanı sağlayan komutlar var. Bu PIC'lerle çalışırken işini kolaylaştıracaklardır.
Gökçe Tağlıoğlu

camby

teşekkürler tagli , ben birkaç aydır ara vermiştim bakıyorum hala hızır gibisin:)

Benim tablo kullanımına tek örneğim bu 7 segment tablosuydu :
TABLO	
		addwf		PCL,1
		DT 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x7,0x7F,0x6F
		return


w yazmacım 0-9 arası değişiyor onun 7 segment karşılığını tablodan alıp aynen gönderiyorum .
aynı yazmaca 9 farklı CALL dallanmasını tablo kullanarak nasıl yapabilirim örnek bir kod yumağı var mıdır?

Tagli

Senin yukarıdaki örneği şu şekle getirebilirsin mesela:
movf     sayac,W
call     TABLO

TABLO
addwf     PCL,F
goto     AAA     ;sayac = 0 için
goto     BBB     ;sayac = 1 için
return          ;sayacın diğer değerleri için
Elbette "call TABLO"nun altından devam edebilmek için AAA ve BBB kod bölümlerinin sonunda return olması gerekir. Bir diğer seçenek de "call TABLO" yerine "goto TABLO" kullanmak. Bu durumda diğer değerler için return yerine devam edilmesi gereken satıra goto ile gidilmesi gerekir. Aynı şekilde AAA ve BBB'nin sonunda da return yerine goto kullanılabilir bu durumda. Olay tamamen senin tasarımına bağlı.

16 serisinde bir sayının başka bir sayıya eşitliğini kontrol etmek için çıkarma yapıp Z'ye bakmak gerçekten sinir bozucu. Aklında olsun, 18 serisinde bu işi kolaylaştıran komutlar var. Bazı durumlarda sorunun tablolarla çözülemediği oluyor, bu durumda mecburen eski usül "zincirleme bit kontrolünü" uygulamak zorunda kalabiliriz.

Dikkat: Tablo kullanımlarında PCL'de taşma olmayacağından emin olmak gerekir. Bunun için program hafızası 256'lık bloklar şeklinde düşünülmeli ve tablolar aynı anda iki blokta olmamalı, yani blok sınırlarını kesmemeli. Bu şekilde tablo boyutu 256'yı geçemez. Ayrıca PCLATH'nın değeri de çok önemli. TABLO'ya giderken önce "pageselw TABLO" yazarsan PCLATH'ın doğru değeri aldığından emin olabilirsin. Bu directive'in, PCLATH'ı uygun şekilde yükleyen iki assembly komutuna dönüştüğünü ve işlem sırasında W'yi kullandığını unutma. Bu yüzden bunu "movf sayac,W" den önce kullanmalısın, yoksa tabloya W'de yanlış değerle gidersin. Ayrıca, eğer gittiğin tablo başka bir page'de ise dönüşte PCLATH'ı eski değerine getirmen gerekir.

Fazladan birkaç satır kod yazarak tabloların 256'lık sınırları kesmesini sağlamak mümkün. Yapman gereken şey "addwf PCL,W" diyerek C'yi kontrol etmen, böylece taşma olup olmadığını anlayabilirsin. Taşma varsa "incf PCLATH,F" diyerek sonradan "addwf PCL,F" ile gerçek atlamayı yaparsın. Benzer yöntemler ile 256'dan büyük tablolar da oluşturabilirsin.
Gökçe Tağlıoğlu

camby

eyw tagli,
fakat başka bir sorunum daha var , iç içe ifler yazmaktan gerçekten bıktım yada ben yanlış bir yol izliyorum :S ?

Mesele 4 digit 7 segmentime saat uygulaması yapıcam , 7 segmentin sağdaki 2 digiti saniye , soldaki 2 digiti dakika.

Her 1 sn sonunda kesme ile altyordama gidip 4 parametrenin değişkenini değiştirmeye çalışıyorum.

1.basamak her kesmede artacak
1.basamak 10 oldu mu kontrol et
1.basamak 10 olduysa 1. basamağı sıfırla ve 2. basamağı 1 arttır
2.basamak 6 oldu mu? 2. basamak  6 olduysa sıfırla ve 3. basamağı 1 arttır
3.basamak 10 oldu mu?
bla bla bla if if if:D

yani bildiğimiz assembly ile saat uygulaması bu kadar mı kasar ,
şu şekilde bi kod kurmuştum ama dallanmasını tahmin ettiğim yerlerde zero biti bozuluyor. incf saniye on dediğim zaman sanki bir aritmetik işlemin sonucu 0 çıkmış gibi zero biti 0 oluyor ve aşağıdaki algortima çöküyor.

Assembly ile yapılmış saat çalışması da bulamadım , yardım

     incf		saniyebir
		movlw		.10
		subwf		saniyebir,0
		btfss		STATUS,2
		btfsc		STATUS,2
		incf		saniyeon
		btfsc		STATUS,2
		clrf		saniyebir
		btfss		STATUS,2
		GOTO 		SON
		
		movlw		.6
		subwf		saniyeon,0
		btfss		STATUS,2
		btfsc		STATUS,2
		clrf		saniyeon
		btfsc		STATUS,2
		incf		dakikabir
		btfss		STATUS,2
		GOTO		SON

		movlw		.10
		subwf		dakikabir,0
		btfss		STATUS,2
		btfsc		STATUS,2
		incf		dakikaon
		btfsc		STATUS,2
		clrf		dakikabir
		btfss		STATUS,2
		GOTO 		SON

		movlw		.10
		subwf		dakikaon,0
		btfss		STATUS,2
		btfsc		STATUS,2
		clrf		dakikaon
		
SON		nop
		return

camby

yaptığım tablo bu şekilde fakat hepsini sırayla çalıştırıyor , sadece birini çalıştırıp ilk yerine geri dönmesi lazım:
movf		sayac,w
CALL		SECIM
incf		sayac
......
...

;====TABLO=======
SECIM
		addwf     	PCL,1
		CALL		AAA     
		CALL		BBB    
		CALL	 	CCC
		CALL		DDD
		return

Tagli

Evet, malesef bu iş pek tabloyla olacak gibi değil. Ancak incf komutunun Z'yi etkilemesi normal, zaten datasheet'te de belirtilmiş. Senin mantık doğru ama kodu çok karıştırmışsın. Şu şekilde olsa çalışır sanırım:
incf     saniyebir,F
movlw     d'10'
subwf     saniyebir,W
btfss     STATUS,Z
goto     SON
clrf     saniyebir

incf     saniyeon,F
movlw     d'6'
subwf     saniyeon,W
btfss     STATUS,Z
goto     SON
clrf     saniyeon

incf     dakikabir,F
movlw     d'10'
subwf     dakikabir,W
btfss     STATUS,Z
goto     SON
clrf     dakikabir

incf     dakikaon,F
movlw     d'6'
subwf     dakikaon,W
btfss     STATUS,Z
goto     SON
clrf     dakikaon


Tabloda call kullandığın için mesela sayac = 1 değeri için BBB ye atlıyor, döndükten sonra CCC ve DDD'ye de gidiyor. Bu normal. call yerine goto kullanman gerekir. Dikkat ettiysen ikinci mesajımda verdiğim örnekte de goto kullanmıştım. AAA vs. gibi kod bloklarının sonundaki return'ler programı "call SECIM" satırının olduğu yere geri döndürür, yani istediğin şekilde "incf sayac"tan devam edersin.
Gökçe Tağlıoğlu

Erol YILMAZ

PIC16 için HI-TECH PICC'ye geçersen bunlarla uğraşmadan ANSI C standardında kodunu geliştirebilirsin.

camby

C'ye geçmek istiyorum fakat bir yandan assembly inadım devam ediyor , sorunlarımın kısmen çözümleri:

1 - Şartlı dallanmayı macro ile yaptım ki şöyle:

LKAE		macro 		f,k, etiket
		movlw 		k
		subwf 		f,0
		btfsc		STATUS,2
		CALL		etiket
		endm

.......

		LKAE		sayac, 0, AAA
		LKAE		sayac, 1, BBB
		LKAE		sayac, 2, CCC
		LKAE		sayac, 3, DDD

   incf sayac

lookup table kullanamadım şartlı dallanmada ama artık nefret ettiğim btfss lerden kurtardı biraz bu macro :)

----------------

2 - Birbirlerini arttıran saniye -dakika - saat konusunda da

Tek bir sayaç yaptım değeri her 1.00000000sn de bir artan (teoride kusursuz oldu hayırlısı : ) ) ve bu sayacı 60'a bölerek dakikayı ardından kalanla da saniyeyi hesaplayarak ilgili 7 segmentlere gönderim.

Salakmısın neden öyle yaptın bu yolla çok daha kolay oluyor derseniz herhangi bir noktada da çok memnun olurum:)

yardımlarınız ve tavsiyeleriniz için teşekkürler

pagesel

CIKAR   MACRO FR,SA,GIT         ;'FR' VE 'SA' DEGERLERINE BAK
   MOVLW SA         ;'SA' NIN ICERIGINI 'W' YE AL   
   SUBWF FR,0
   BNC    GIT            ;FR BUYUKTUR. BUYUK BOLUMUNE GIT
;   B    GIT         ;'FR'-'SA' DAN KUCUKTUR.KUCUK BOLUMUNE GIT 
   ENDM

ACIKAR   MACRO FR,SA,GIT         ;'FR' VE 'SA' DEGERLERINE BAK
   MOVLW SA         ;'SA' NIN ICERIGINI 'W' YE AL   
   SUBWF FR,0
   BC    GIT
   ENDM

RCIKAR   MACRO FR,SA,GIT         ;CONTL K DAN KUCUKSE XXX GIDER
   MOVF SA,0         ;'SA' NIN ICERIGINI 'W' YE AL   
   SUBWF FR,0
   BNC    GIT            ;FR BUYUKTUR. BUYUK BOLUMUNE GIT
   ENDM
( RCIKAR REG, .1, XXX )  REG 1 DEN BUYUKSE XXX GIT YADA KUCUKSE XXX GIT GIBI KULLANABILIRSIN.
bence status bıtlerını her seferınde kontrol etmek yerine direk verdıgıM ornektekı gıbı makrolar kullanman kodunu daha rahat gelıstırebılır.