pic assembly ile 74595 7 Segment

Başlatan camby, 20 Temmuz 2009, 12:55:48

camby



16f84a ile şekildeki gibi 7 segment display'a 74595 ile 0-9 arası sayan bir program yazdım. DÖngünün her adımında Displayde görünmesi gereken sayıyı seri olarak 8 bit şeklinde DATA(RA1) çıkışından gönderiyorum. Her datayı yolladıktan sonra clock(RA0) yolluyorum ve 8 bit sonunda da ENABLE ile Displayde gösterilmesini sağlıyorum.
Fakat bu programı assemblyde yazarken çok uzun yöntemlerden yaptım gibime geliyor, bu program sonucunda program hafızasının da neredeyse yarısı dolu. Acaba bunun daha kolay bir yolu var mıdır sizlere onu sormak istiyorum?
Kodlar şu şekilde
Alıntı Yap
;=========Bit yollama alt programları==============
YUKSEK   
               bsf      PORTA,1           ;DATA YOLLA
      bsf      PORTA,0      ;CLOCK ON
      bcf      PORTA,0      ;Clock off
      return

ALCAK      
               bcf      PORTA,1      ;DATA YOLLA
      bsf      PORTA,0      ;Clock on
      bcf      PORTA,0      ;Clock off
      return

ENABLE1   
               bsf      PORTA,2      ;Enable ON
      bcf      PORTA,2      ;Enable OFF
      return

GOSTER0
      CALL      ALCAK      ;0 gönder
      CALL      ALCAK
      CALL      YUKSEK      ;1 gönder
      CALL      YUKSEK
      CALL      YUKSEK
      CALL      YUKSEK
      CALL      YUKSEK
      CALL      YUKSEK
      RETURN
.
.
.
GOSTER9   
      CALL      ALCAK
      CALL      YUKSEK
      CALL      YUKSEK
      CALL      ALCAK
      CALL      YUKSEK
      CALL      YUKSEK
      CALL      YUKSEK
      CALL      YUKSEK
;==========KONFİGÜRASYON===========

PRG         
               bsf       STATUS,5   
      movlw    0
      movwf   TRISA      
      movlw   H'FF'
      movwf   TRISB      
      bcf       STATUS,5   
      clrf      PORTA   

;==========Ana Program=============
SIFIRLA   
               clrf      SAYAC
      CALL      GOSTER0


TEKRAR   
      movf      SAYAC,w
      sublw      1
      btfsc      STATUS,2
      CALL      GOSTER1

      movf      SAYAC,w
      sublw      2
      btfsc      STATUS,2
      CALL      GOSTER2

      movf      SAYAC,w
      sublw      3
      btfsc      STATUS,2
      CALL      GOSTER3

      movf      SAYAC,w
      sublw      4
      btfsc      STATUS,2
      CALL      GOSTER4

      movf      SAYAC,w
      sublw      5
      btfsc      STATUS,2
      CALL      GOSTER5

      movf      SAYAC,w
      sublw      6
      btfsc      STATUS,2
      CALL      GOSTER6

      movf      SAYAC,w
      sublw      7
      btfsc      STATUS,2
      CALL      GOSTER7

      movf      SAYAC,w
      sublw      8
      btfsc      STATUS,2
      CALL      GOSTER8
   
      movf      SAYAC,w
      sublw      9
      btfsc      STATUS,2
      CALL      GOSTER9
   
      CALL      ENABLE1
      CALL      BEKLE
      incf      SAYAC,f              ;Sayac=Sayac+1
      movlw   H'A'                      ;W=10
      xorwf   SAYAC,w      ;       SAYAC 10 oldu mu
      btfss      STATUS,2
      GOTO   TEKRAR
      GOTO        SIFIRLA
      END

2. Konum:
Hadi diyelim 74595 ile 7 segmente sayı göndermek bu şekilde fakat
74595'in çıkışlarını 7 segment için değil de birbirinden bağımsız portlar gibi kullanmak istersem(yani port çoklama işinde kullansam) ve bu mantıkta kod yazarsam bu örnekte olduğu gibi 10 farklı durum değil 255 farklı durum olması lazım.
Yani örneğin SAYAC adlı yazmacının içeriği resgele b'10101010' diyelim. Bu sayacın her bitini sırayla test edip 74595'e giden data pinine yollamak istiyorum fakat programı kuramadım. Bildiğim tek test yöntemi olan "btfss" ve "btfsc" komutları ile

btfss    SAYAC,0
CALL   sıfırgonder
CALL   birgonder
.
.
.
btfss   SAYAC,7
CALL   sıfırgonder
CALL   birgonder

yapıyorum ama "1" biti gönderdikten sonra sorunsuz bir şekilde diğer biti teste geçiyor fakat "0" yollayınca peşine tekrar istenmeyen bir "1" biti yolluyor , sonuc olarak bunu da kuramadım.

Bilmiyorum iyi bir yoldamıyım ama hala assembly konusunda diretiyorum:) Hocalarımın tavsiyelerini de bekliyorum..
Kolay gelsin herkese

Tagli

Sorun genel bir seri iletişim kodu olmayışından kaynaklanıyor. Öyle bir kod parçası olmalı ki girdisi tek bir byte (register) olacak ve bir kez çağrılınca o byte'ı istenilen bacaktan seri olarak yollayacak. Şunun kadar kolay kullanılabilmeli:
MOVF     sayi, W
CALL     SERI_YOLLA

Bu şekilde genellenmiş bir kod programı ciddi ölçüde kısaltacak ve yazmayı da kolaylaştıracaktır. Bu bağlamda, her sayı için arka arkaya alçak ve yüksek kodlarını çağırman yanlış olmuş. Bunun yerine SERI_YOLLA parçasının altında 8 kez dönecek bir bölüm tasarlarsın ve sürekli 0. biti kontrol edersin btfsc ve btfss ile. Sonuca göre alçak veya yüksek kodunu çağırırsın ve sonra da rrf ile register'ı kaydırıp 7 kez daha tekrarlarsın işlemi. Bu şekilde tek bir kod ile herhangi bir byte'ı (yani 256 farklı durumu) seri olarak yollayabilirsin.

Ayrıca, uzun test işlemleri için tablo kullanmak daha mantıklıdır. Arka arkaya btfss ve btfsc kullanmaktan kurtarır (her durumda değil gerçi). Ben 3-5 durumu ifade etmek için bile tablo oluştururum. Tablo mantığını özetlemek gerekirse, PIC'in program counter'ını (kısaca PC) değiştirerek programın istenilen yere dallanmasını sağlamaktır. Bu şekide arada test komutları olmadan GOTO veya RETLW komutları sıralanabilir (aslında her komut sıralanabilir ama bu ikisi haricindekiler saçma olur ve bir işe yaramaz). Örnek vermek gerekirse; bir sinüs tablosu oluşturabilir ve hesaplama yapmadan tablodan bakarak yaklaşık bir sinüs değeri elde edebilirsin. Neyse, tablolar konusuna bu başlıkta baya ayrıntılı olarak değinmiştim. Bir incele.

Bu arada, 7 parçalı göstergeler genelde tarama yöntemiyle sürülüyor. Bu konuyu da bir araştır. İşini kolaylaştırır.
Gökçe Tağlıoğlu

arslan74

; SPI pinleri
#define SDO    PORTA,0         ;Data output 

#define SCK     PORTA,3         ; CLOCK


; SPI ile göndereceğiniz bilgiyi W registerine atıyorsunuz  
; sonra bu alt rutini cağırmanız yeterli.


WrSpiW 
        ; CLK ve Data da sıfırda olmalı. 
        ; göndericek bilgiyi buf reg. at. 
        movwf   buf
        movlw   8
        movwf   count           ; 8 Bits
WrSpiW1 
        ; Data bitini set et.
        bcf     SDO 
        rlf     buf,f 
        btfsc   STATUS,C        ; 0? 
        bsf     SDO            ; hayir, 1 
        nop 
        bsf     SCK             ; Clock high 
WrSpiW2 
        bcf     SCK             ; Clock low 
        decfsz  count,f         ; 8 bit gönderildi mi? 
        goto    WrSpiW1         ; hayır. 
        return                  ; evet. cık.



Çağırmayıda böyle yapiyorsunuz:
      movlw   H'91'           ; gönderilecek data.
       call    WrSpiW          ; datayı SPI ile gönder.


Kaynak:
http://www.sprut.de/electronic/pic/grund/i2c_soft.htm
Adresinden esinlerek yapılmışdır.

Selamlar

camby

@tagli
kendi kodlarıma dediğiniz eklentileri(arslan74 ün kodlarına bakmadan:D ) yazmaya çalıştım , uzun uğraşlar sonucu baya bir ilerledim ve dayanamayıp hazır kodlara baktım , düşündüğümüz kodların optimum şeklini yazmışlar...

@arslan74 çok teşekkür ederim artık port çoklama işi tamamdır. Dada da çok bacaklı pic kullanmam:)

@tagli 7 parçalı LEDlerde tarama moduna bakmadım henüz ama bu şekilde 7 segment sayıda her değişim olması gerektğinde bilgiyi yolluyor. 0.5 sn yada 10 dakikada bi neyse.. tarama yöntemi bundan daha mı optimum yoksa kullanımı mı kolay , neden tercih ediliyor.

Ayrıca sanırım tablolarla iligli olan bir sorunum var ki şöyle:

Diyelim benim bir 16bit'lik bir sayım var ve bu sayıyı 0-5000 arasında değişecek , ben bu sayıyı 4 adet 7 segment'e göndermek istiyorum. Düşündüğüm yöntemler ne yazıkki ki çok çok satırlı

sayı 5000'den büyük mü
evet büyük 4.led 5 yaz
hyr değil devam et
sayı 4000'den büyük mü
evet büyük 4.led 4 yaz
..
...
binler basamağım için 5 farklı durum diğerleri için 10 farklı durum olduna göre toplamda bu şekilde peşpeşe 35 sorguda sayıyı yazdırıyorum, 100-150 satır birşey:D
, kolay bir yolu var mıdır? tablo yapılabilir mi?
Tabi bunun için yukardaki gibi 4 tane 74595 kullanıcam ve bilgiller de yukaraki kodları kullarak seri bir şekilde yollayacam

Yardımlarını için çok teşekkür ederim , kolay gelsin

Tagli

Tarama yöntemi bacak sayısı sınırlamaları sebebiyle tercih ediliyor. Gerçi sen bu sorunu çözmek için shift register kullanmışsın ama bu da programı karmaşık bir hale getirir. Tarama yönteminde tüm göstergelerin 8 bacağı ortak bağlanır, ama her göstergenin ortak anot veya katot bacağı ayrı ayrı kontrol edilerek bir anda sadece bir göstergenin çalışması sağlanır. Çalışan gösterge sırayla ve hızlı bir şekilde değiştirilince göz yanılması olur ve sanki hepsi aynı anda yanıyor gibi gözükür.

Tarama yöntemini bir timer kesmesine bağlarsan (eğer boştaysa esnekliği sebebiyle timer2 daha kullanışlı olur) ana programda yapman gereken tek şey her gösterge için ilgili register'a gerekli değeri yazmaktan ibaret olur, ki bu da program yapısını çok basitleştirir. Ayrıca kesme kodu da karmaşık değil. Yani 16 bitlik bir sayıyı yazdırmak için bunun 4 basamağını ayrı ayrı elde edip 4 ayrı register'a yazınca gerisini kesme kodu yapacak. Yukarda bağlantısını verdiğim başlıkta 16 bitlik bir sayının nasıl 4 basamağa bölüneceği üzerince baya bir durmuştum. Hatta aynı başıkta taramayla ilgili ufak bir örnek de vermiştim.
Gökçe Tağlıoğlu

elektromer

Alıntı yapılan: "camby"
.......

Ayrıca sanırım tablolarla iligli olan bir sorunum var ki şöyle:

Diyelim benim bir 16bit'lik bir sayım var ve bu sayıyı 0-5000 arasında değişecek , ben bu sayıyı 4 adet 7 segment'e göndermek istiyorum. Düşündüğüm yöntemler ne yazıkki ki çok çok satırlı

sayı 5000'den büyük mü
evet büyük 4.led 5 yaz
hyr değil devam et
sayı 4000'den büyük mü
evet büyük 4.led 4 yaz
..
...
binler basamağım için 5 farklı durum diğerleri için 10 farklı durum olduna göre toplamda bu şekilde peşpeşe 35 sorguda sayıyı yazdırıyorum, 100-150 satır birşey:D
, kolay bir yolu var mıdır? tablo yapılabilir mi?

.............

Merhaba arkadaşım,
16 bitlik bir sayıyı Ondalık sisteme çevirmek için daha önceden göndermiş olduğum Assembly kodlarını incelerseniz sanırım probleminize bir çözüm olacaktır.

16 bit BINARY sayıyı DECIMAL'e çevirme...

Elimizde olan bir sayıyı analiz ederken, sizin yaptığınız gibi 35 sorguya gerek kalmadan daha kısa yöntemler kullanmak işinizi hem kolaylaştıracak hemde hızlandıracaktır.

Çalışmalarınızda başarılar dilerim.
Her şey gönlünüzce olsun..

camby

yardımlarınız için teşekkür ederiim , pclath konusuna koyduğum devreyi bu başlığa da ekliyorum:

4 adet 7 segmentin 74595 ile port çoklama yaparak tarama yöntemi ile sürülmesi:


;Buton ile 4'lü 7 Segment LED'li 0-9999 Sayıcı 07.08.2009
;2 Adet 74hc595 ile Port çoklama yapılmıştır
;1.BUTONA BASILDIĞINDA PROGRAM ÇALIŞMAYA BAŞLAR 
;7 Segment LED ortak KATOT(-) uçludur.
;Kristal tipi HS olduğundan 4-20MHz osilatör seçilebilir
		LIST 		P=16F84A    	
		include 	"P16F84A.inc"
		__CONFIG _WDT_OFF & _HS_OSC & _PWRTE_ON & _CP_OFF		
		ORG 		0x00			
		GOTO 		PRG

;=========Kaydediciler=========	
DONGU1	 	EQU 0C			
DONGU2 		EQU 0D
dtekrar		EQU 0E	
onlar       	EQU 10
yuzler     	EQU 11
binler     	EQU 12
birler		EQU 13
sayac0     	EQU 14   
sayac1     	EQU 15
sayici0		EQU 16
sayici1		EQU 17

;=========Display Tarama Gecikmesi=====

GECIKME		
		movlw 		.100
		movwf 		DONGU1
B000		
		movlw 		.10
		movwf 		DONGU2
B011		
		decfsz 		DONGU2,F
		GOTO 		B011
		decfsz 		DONGU1,F
		GOTO 		B000
		RETURN

;==========2byte binary 'den 4 basamak decimal'e dönüşüm===========

SAYI_CEVIR      		
		movf		sayici0,w	;sayici0 ve sayici1 , 10'luk sisteme çevirilmek üzere sayac0 ve sayac1'e yazılır.
		movwf		sayac0
		movf		sayici1,w
		movwf		sayac1	
		clrf            onlar           ;Onlar basamağı sayacı sıfırlanıyor
                clrf            yuzler          ;Yuzler basamağı sayacı sıfırlanıyor
                clrf            binler          ;Binler basamağı sayacı sıfırlanıyor

BINLER_HESAPLA
                movlw           b'11101000'     ;1000'in küçük byte'ı W'ye yüklendi
                subwf           sayac0,F        ;W, sayacın küçük byte'ından çıkarıldı
                btfsc           STATUS,C        ;Sonuç eksili mi?
                goto            $+5             ;Değilse büyük byte işlenecek
                movf            sayac1,F        ;Eksili ise sayac1 test için kendi üzerine yazılıyor
                btfsc           STATUS,Z        ;sayac1 0 mıymış? (büyük byte da mı kurtarmadı?)
                goto            BINLER_CIK_0    ;Demek ki döngü bitmis, (1000'in küçüğü) geri eklenecek
                decf            sayac1,F        ;sayac1 1 azaltılıyor
                movlw           b'00000011'     ;1000'in büyük byte'ı W'ye yüklendi
                subwf           sayac1,F        ;W, sayacın büyük byte'ından çıkarıldı
                btfss           STATUS,C        ;Sonuç eksili mi?
                goto            BINLER_CIK_1    ;Evet ise döngü bitmiş, sayaca 1000 eklenecek
                incf            binler,F        ;Binler sayacı 1 arttırılıyor
                goto            BINLER_HESAPLA  ;Döngüye devam ediliyor
BINLER_CIK_1
                movlw           b'11101000'     ;1000'in küçük byte'ı W'ye yüklendi
                addwf           sayac0,F        ;Sayacın küçük byte'ı eski haline getiriliyor
                btfsc           STATUS,C        ;Taşma var mı?
                incf            sayac1,F        ;Taşma varsa sayac1 1 arttırılacak
                movlw           b'00000011'     ;1000'in büyük byte'ı W'ye yüklendi
                addwf           sayac1,F        ;Sayacın büyük byte'ı eski haline getiriliyor
                goto            YUZLER_HESAPLA  ;Sonraki adıma geçiliyor
BINLER_CIK_0
                movlw           b'11101000'     ;1000'in küçük byte'ı W'ye yüklendi
                addwf           sayac0,F        ;Sayacın küçük byte'ı eski haline getiriliyor

YUZLER_HESAPLA
                movlw           d'100'          ;100 W'ye yüklendi
                subwf           sayac0,F        ;W, sayacın küçük byte'ından çıkarıldı
                btfsc           STATUS,C        ;Sonuç eksili mi?
                goto            $+5             ;Değilse yüzler sayacı artar
                movf            sayac1,F        ;Eksili ise sayac1 test için kendi üzerine yazılıyor
                btfsc           STATUS,Z        ;sayac1 0 mıymış? (büyük byte da mı kurtarmadı?)
                goto            YUZLER_CIK_0    ;Demek ki döngü bitmis, 100 geri eklenecek
                decf            sayac1,F        ;sayac1 1 azaltılıyor
                incf            yuzler,F        ;Yüzler sayacı 1 arttırılıyor
                goto            YUZLER_HESAPLA  ;Döngüye devam ediliyor
YUZLER_CIK_0
                movlw           d'100'          ;100 W'ye yüklendi
                addwf           sayac0,F        ;Sayacın küçük byte'ı eski haline getiriliyor

ONLAR_HESAPLA
                movlw           d'10'           ;10 W'ye yüklendi
                subwf           sayac0,F        ;W, sayacın küçük byte'ından çıkarıldı
                btfss           STATUS,C        ;Sonuç eksili mi?
                goto            ONLAR_CIK_0     ;Demek ki döngü bitmis, 10 geri eklenecek
                incf            onlar,F         ;Onlar sayacı 1 arttırılıyor
                goto            ONLAR_HESAPLA   ;Döngüye devam ediliyor
ONLAR_CIK_0
                movlw           d'10'           ;10 W'ye yüklendi
                addwf           sayac0,F        ;Sayacın küçük byte'ı eski haline getiriliyor

                movf            sayac0,0        ;Kalan değer W'ye alındı
                movwf           birler          ;Birler sayacı ayarlandı
                clrf            sayac0          ;Sonraki işlemler için sayac0 sıfırlanıyor 
		RETURN

;==========Gösterilecek Sayının binary karşılığı ORTAK KATOT=======

TABLO	
		addwf		PCL,1
		DT 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x7,0x7F,0x6F
		return

;==========7 Segment TARAMA===============

DISPLEY_SEC_YAZ
		bcf   		PORTA, 0   ;( DISPLAY 0)
   		bsf   		PORTA, 1   
   		bsf   		PORTA, 2   
 		bsf   		PORTA, 3           

  	 	movf   		binler, W
   		CALL   		TABLO
   		movwf  		PORTB      ;binleri port b ye gönder
   		CALL   		GECIKME    ;displey gecikme süresi
   
   		bsf   		PORTA, 0   
   		bcf   		PORTA, 1   ;( DISPLAY 1)
   		bsf   		PORTA, 2   
   		bsf   		PORTA, 3           

   		movf   		yuzler, W
   		CALL   		TABLO
   		movwf   	PORTB      ;yüzleri port b ye gönder
   		CALL    	GECIKME    ;displey gecikme süresi
       
  		bsf   		PORTA, 0   
   		bsf   		PORTA, 1   
   		bcf   		PORTA, 2   ;( DİSPLAY 2)
   		bsf   		PORTA, 3

   		movf   		onlar, W
   		CALL   		TABLO
   		movwf   	PORTB      ;onları port b ye gönder
  		CALL    	GECIKME    ;displey gecikme süresi
       
 		bsf   		PORTA, 0   
   		bsf   		PORTA, 1   ;( DİSPLAY 3)
   		bsf   		PORTA, 2   
   		BCF   		PORTA, 3

   		movf   		birler, W
   		CALL   		TABLO
   		movwf   	PORTB      ;birleri port b ye gönder
   		CALL    	GECIKME    ;displey gecikme süresi
           
		DECFSZ   	dtekrar, F   	;sayac 0 olana kadar  ekranı göster
   		GOTO   		DISPLEY_SEC_YAZ   ;sayac 00 olana kadar GÖSTER
   		
		bsf   		PORTA, 0   
   		bsf   		PORTA, 1   ;DİSP TEMİZLE
   		bsf   		PORTA, 2   
   		bsf   		PORTA, 3  
		RETURN

;==========KONFİGÜRASYON===========

PRG		
		bsf 		STATUS,5	;Bank1'e geç	
		movlw 		b'00000000'
		movwf		TRISB		;B portunu çıkış olarak ata
		movlw  		b'11110000'	;RA4 giriş,diğerleri çıkş
		movwf 		TRISA		
		bcf 		STATUS,5	;Bank0'a geç
		movlw		b'00001111'	;Display'ler kapalı
		movwf		PORTA
		movlw		b'00000000'	
		movwf		PORTB 

;==========ANA PROGRAM=============

KONTROL		
		btfss		PORTA,4		;RA0 1 ise 1 satır atla ;Butona Basıldı mı?
		GOTO  		KONTROL

SIFIRLA		
		clrf		sayici0
		clrf		sayici1

SAYICI						;0-9999 arası sürekli olarak sayan program
   		incf 		sayici0, F     ;sayici0 ve sayici1 'den oluşan 2byte'lik sayıcı
    		btfsc 		STATUS,Z       ;sayici0 alcak değerlikli,sayici1 yüksek değerlikli
    		incf		sayici1,F      
    				
		movlw		3		;7 Segment tekrarlama sayısı
		movwf		dtekrar

		CALL		SAYI_CEVIR	;16bitlik binary sayıyı 10'luk bileşenine ayırır

		CALL		DISPLEY_SEC_YAZ	;4 basamaklı sayıyı 7segmentte gösterir

		movlw		b'00100111'	;sayici 9999 oldu mu?
		subwf		sayici1,w   
		btfss           STATUS,Z	;sonuc 0 mı,0'sa 1 satır atla
  		GOTO 		SAYICI  
		movlw		b'00001111'
		subwf		sayici0,w
		btfss		STATUS,Z	;sonuc 0'mı ,0'sa 1 satır atla
		GOTO		SAYICI
		GOTO		SIFIRLA       
		END

give64

74hc595 entegresinin bozuk olma şansı varmıdır?