3 wire lcd ve macro kullanımı

main_picture Merhaba, Bu uygulamızda 3 wire(tel) üzerinden lcd uygulamasını gerçekleştirirken asm içinde macronun nasıl kullanıldığını göreceğiz. Öncelikle neden 3 wire üzerinden lcd ile haberleşmeye gereksinim var sorusuna cevap vereyim? Şahsen mümkün olduğunca küçük boyutta işlemci (az sayıda porta sahip) kullanmaya çalışıyorum ve haberleşmeleri ise seri haberleşme seçiyorum ki en az pinli işlemci kullanabileyim. Bu şekilde kullanmanın daha çok avantajları ama dezavantajları da var.

Avantajları :
Port sayısı az olduğu için işlemci ucuz oluyor, pcb’de daha az yer kaplıyor ve pcb yaptırım ücreti azalıyor.

Belki diyebilirsiniz ki, işlemci küçük ama yerine başka bir IC kullanıyorsun bu maliyete ve pcb yerleşimine etki etmiyor mu? Evet başka bir IC kullanıyorum, 74HC595, fiyat açısından çok ucuz (paha açısında çok portlu işlemci ile karşılaştırılamaz bile) ve IC’yi smd kullandığım için yer sorunu olmuyor.

LCD’yi 4bit haberleşme ile bile sürersek işlemcinin en az 7 portunu harcamamız gerekir. 3 wire kullanarak 4 port avantaja geçiyoruz. Bu olay bazı durumlarda maliyetten de önemli oluyor. Hatta 74hc595 için kullanılan latch pini hariç, serial data ve clock uçlarınıda başka IC’ler ile haberleşirken kullanabilir.

Dezavantajı : Endüstriyel uygulamalarda, 74hc595 latch’li bir shift register olduğu için yogun gürültü altında latch pini etkilenebilir ve çıkışları farklı bir değere latch edebilir.Bunun önüne geçmek için pcb üzerinde ve elektronik malzeme olarak bazı önlemler alınmalıdır. 74hc595’in diğer güzel tarafı hem latch’li olması hemde 50Mhz’e kadar clock’landırılabilir olmasıdır.

Genelde çoğu uygulamamda PC ortamında şema çizmem (aslında bunun nedeni eagle kullanıyorum ve şematik editörünü beğenmiyorum), karakalem ile şemayı belirler sonra program içinde şemadaki kritik değerleri belirtirim. Pcb’yi ise doğrudan çizerim. Elektroniğe hakimseniz böylesi kolay oluyor.

(Resimdeki lcd boardu delikli pertenax üzerine kuruludur, ana board’dan bağımsız olması ve tüm geliştirme boardlarıyla birlikte kullanılması için. Elektronik pahalı meslek, bazen ucuz çözümler kullanmak gerekir)

Bu uygulamada en kritik şey, 74hc595’in çıkışlarının lcd’ye hangi sıra ile bağlanacağıdır.
Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0 74HC595 çıkışları,
D7 D6 D5 D4 E RW RS – LCD pinleri , Q0 çıkışına bağlı pin yok.

E=enable, RW=Read/write, RS=Register select

Aşağıda bağlatının yapıldığı bir picture var. Yukarıda anlatılanlara göre bağlantısı yapıldı ve extra olarak

plaket üzerinde 78L05 (LCD 5V ve backlight için) ve backlight bias direnci var.

picture2_800600

Program içinde benim oluşturduğum assembly’de çok kullanışlı string’ler için bir macro var. Başka macrolar da var. Program içinde uygulamaları görülecektir. Macrolar sayesinde asm dilini biraz daha basitleştirmiş oluruz ve çok tekrar gerektiren ama birbirinden farklı durumlar için bir macro yeterli olmaktadır. Bizim yazmamız gereken kodları, bizim yerimize derleyici oluşturur.

Mesela aşağıdaki örnekte , LCD’nin 1 satırından ve 1 karakterinden başlayarak “satir1” adlı string’i yazdırır.
LCD_YAZI satir1,1,1

;==========================================================
; Aykut ULUSAN, Elektronik Mühendisi, IZMIR
;===========================================================
; 3wireLCD : 74HC595 ile SCK,SDA ve LOAD ucu ile 3 wire üzerinden LCD sürülür.
;===========================================================
LIST		P=16F877
INCLUDE		"P16F877.INC"
TITLE 		"3wire LCD"
ERRORLEVEL	-302,-207,-205
RADIX		DEC				; Sayı tipini belirtmediklerimi desimal kullan
__CONFIG 	0x3F32			; hs,code protects off,Wdt off,Pwrte on, boden off,wrt off,

CBLOCK		20H
LCD_DATA
DATA_OUT					; 3 wire LCD için
HC595_COUNT
TABLE_REG
COUNT1
COUNT2
COUNT3
ENDC

; LCD'yi 74HC595 ile sürmekteyim
#DEFINE	LCD_SDA		PORTA,1		; 74HC595'in SDA pinine
#DEFINE	LCD_SCK		PORTA,2		; 74HC595'in SCK pinine
#DEFINE	LCD_LOAD	PORTA,0		; 74HC595'in LOAD pinine

#DEFINE	CARRY_FLAG	STATUS,0	; Carry flag
#DEFINE	ZERO_FLAG	STATUS,2	; Zero flag

DLY_MS		MACRO	MS		; 1-255 msn arasında delay sağlar(20Mhz'de)
MOVLW		MS
CALL		X_MSN
ENDM

DLY_10US	MACRO US					; US'ye verilecek değer 1 - 255 ile 10usn ile 2550usn(2,5msn) delay sağlanır
MOVLW		US
MOVWF		COUNT1
CALL		X_ON_USN
ENDM

BANK0 		MACRO								; Bank0'a geç
BCF			STATUS,RP1
BCF			STATUS,RP0
ENDM

BANK1		MACRO								; Bank1'e geç
BCF			STATUS,RP1
BSF			STATUS,RP0
ENDM

MOVFF		MACRO	REG1,REG2					; Register1'i register2'ye kopyalayan macro
MOVF		REG1,W
MOVWF		REG2
ENDM

MOVLF		MACRO	L,F							; Literali file'a taşı
MOVLW		L
MOVWF		F
ENDM

; LCD karekter adresleri için macro :
; LCD_ADRES	1,1  için						; 1 .satır 1.adrese gider
; LCD_ADRES	1,3  için						; 1 .satır 3.adrese gider
; LCD_ADRES	2,1  için						; 2 .satır 1.adrese gider
LCD_ADRES MACRO	SATIR,ADRES		;
IF	SATIR==1
MOVLW	7FH						; 7F+1=80H 1. satır adres başlangıcı
ELSE
MOVLW	0BFH					; 0BF+1=0C0H 2. satır adres başlangıcı
ENDIF
ADDLW	ADRES						;80H  veya 0C0H ile ADRES değerini toplar
CALL	LCD_KOMUT_YAZ
ENDM

; YAZI : Ekrana yazdılacak yazı etiketi
; SATIR : LCD'nin satırı (1 veya 2)
; ADRES : LCD'nin adresi ( 1......16 ya kadar)
LCD_YAZI	MACRO	YAZI,SATIR,ADRES	;
LCD_ADRES	SATIR,ADRES				; LCD'de ilgili satıra gitmesini sağlar
LCD_STRING YAZI
ENDM

LCD_STRING MACRO	STRING
CLRF	TABLE_REG
MOVF	TABLE_REG,W
CALL	STRING
CALL	LCD_STR					; bu altprogram,
BTFSS	ZERO_FLAG					; table'dan 0 geldiyse çık
GOTO	$-4							; Call ile table'dan karekter alır.
ENDM

ORG		0
goto  	start

ORG		4
GOTO	start

LCD_INIT_TABLE_1:							; LCD'yi hazırlamak için hex değerler tutulur
MOVF		TABLE_REG,W
ADDWF		PCL,F
DT			30H,30H,20H,0

LCD_INIT_TABLE_2:							; Burada tüm bitler gönderilir (8 bit) (mesela önce 2 sonra 8 gönderilir)
MOVF		TABLE_REG,W
ADDWF		PCL,F
DT			28H,08H,06H,03H,0CH,0

satir1:
ADDWF		PCL,F
DT			"MACRO KULLANIMI",0

satir2:
ADDWF		PCL,F
DT			"ve 3 WIRE LCD",0

start:
CALL	PORTLARI_HAZIRLA		; port ayarlarını yap
CALL	LCD_INIT				; LCD'yi hazırla
call	YAZ_BAKALIM
goto 	$

;////////////////////////////////////////////////////////////////////////////////////////////////////
YAZ_BAKALIM:
LCD_YAZI	satir1,1,1			; 1. satır, 1 karakterden itibaren
LCD_YAZI	satir2,2,2			; 2. satır, 2 karakterden itibaren
RETURN

LCD_INIT:
;	BSF			LCD_ON				; lcd'nin power'ı ve backlight'ı iki tr. ile on yapılır
DLY_MS		.100				; LCD'nin hazırlanması için gerekli süre (en az 40msn)
MOVLW		30H					;
CALL		WRITE_595
DLY_MS		.1
MOVLW		38H
CALL		WRITE_595
DLY_MS		.1					; 1ms
MOVLW		30H					;
CALL		WRITE_595
DLY_MS		.10					; 10ms delay
CALL		CTRL_BYTE
CALL		LCD_SET_UP
RETURN
; *******************************************************************************************************
LCD_SET_UP:
CLRF		TABLE_REG
LCD_KOMUT:
CALL		LCD_INIT_TABLE_2
IORLW		0
BTFSC		ZERO_FLAG			; Table'dan W=0 gelirse geri dön
RETURN
CALL		LCD_KOMUT_YAZ
INCF		TABLE_REG,F
GOTO		LCD_KOMUT
; *******************************************************************************************************
LCD_CLR_LINE_1:						; 1. satırı sil
MOVLW		80H					; 1. satırın ilk adresini gönder
CALL		LCD_KOMUT_YAZ		;
CALL		LCD_CLR_LINE		; 16 hücreyi de sil
MOVLW		80H
CALL		LCD_KOMUT_YAZ		; 1. satırın ilk adresini gönder
RETURN

LCD_CLR_LINE_2:						; 2. satırı sil
MOVLW		0C0H				; 2. satırın ilk adresini gönder
CALL		LCD_KOMUT_YAZ		;
CALL		LCD_CLR_LINE		; 16 hücreyi de sil
MOVLW		0C0H
CALL		LCD_KOMUT_YAZ		; 2. satırın ilk adresini gönder
RETURN

LCD_CLR_LINE:
CLRF		TABLE_REG
LINE_SIL:
MOVLW		" "					; Working'e boşluk yükle
CALL		LCD_DATA_YAZ
INCF		TABLE_REG,F
BTFSS		TABLE_REG,4
GOTO		LINE_SIL
RETURN

LCD_CLEAR:							; LCD'yi komple temizler ve 2.satır başında bekler
CALL		LCD_CLR_LINE_1		; 1. satırı sil
CALL		LCD_CLR_LINE_2		; 2. satırı sil
RETURN
; *******************************************************************************************************
CTRL_BYTE:							; 4 bit komutları göndermek için kullanılır
CLRF		TABLE_REG
CTRL_BYTE_AL:
CALL		LCD_INIT_TABLE_1	;
IORLW		0					; 0 gelirse gönderme bitmiştir
BTFSC		ZERO_FLAG			; Table'dan W=0 gelirse geri dön
RETURN
CALL		CONTROL_BYTE_GONDER
INCF		TABLE_REG,F
GOTO		CTRL_BYTE_AL
; *******************************************************************************************************
CONTROL_BYTE_GONDER:
MOVWF		LCD_DATA			; komutu registere taşı
MOVF		LCD_DATA,W			; Sadece ilk 4 bit gönder, Enable=0
ANDLW		0F0H				; D7-D4 maskele
CALL		WRITE_595
MOVF		LCD_DATA,W			; Sadece ilk 4 bit gönder, Enable=0
ANDLW		0F0H				; D7-D4 maskele
IORLW		08H					; E=1
CALL		WRITE_595
MOVF		LCD_DATA,W			; Sadece ilk 4 bit gönder, Enable=0
ANDLW		0F0H				; D7-D4 maskele
CALL		WRITE_595
DLY_MS		.1
RETURN
; *******************************************************************************************************
; LCD'ye komut gönderen alt program, LCD'ye E'nin düşen kenarı ile yazılır.
; 4bitlik nibble datalar ve RS ve R/W ucları , E=0 sonra E=1 daha sonra E=0 için gönderilir
LCD_KOMUT_YAZ:
MOVWF		LCD_DATA			; komutu registere taşı
MOVF		LCD_DATA,W			; yine aynı datanın
ANDLW		0F0H				; D7-D4 bitlerini maskele
IORLW		08H					; E=1 RS=R/W=0 ve Datanın high order byte'nı LCD ye gönder
CALL		WRITE_595
MOVF		LCD_DATA,W			;
ANDLW		0F0H				; D7-D4 maskele
CALL		WRITE_595			; RS,R/W ve E ucu low, Datanın high order byte'nı LCD ye gönder
SWAPF		LCD_DATA,W			; LSB için nibble'ları değiştir
ANDLW		0F0H				; D7-D4 maskele
IORLW		08H					; E=1 RW=0 RS=0    x
CALL		WRITE_595			; RS,R/W ve E=1, Datanın low order byte'nı LCD ye gönder
SWAPF		LCD_DATA,W			; LSB için nibble'ları değiştir
ANDLW		0F0H				; D7-D4 maskele
CALL		WRITE_595			; RS,R/W ve E ucu low, Datanın low order byte'nı LCD ye gönder
DLY_10US 	.50					; LCD'nin komutu çalıştırması için 500us
RETURN
; *******************************************************************************************************
; LCD'ye karekter gönderen alt program ve karekterin hazır olması için gerekli delay'i
; kapsar

LCD_DATA_YAZ:
MOVWF		LCD_DATA			; komutu registere taşı
MOVF		LCD_DATA,W			; Ilk önce msb gönderilir
ANDLW		0F0H				; D7-D4 maskele
IORLW		0AH					; E=1 RW=0 RS=1   x
CALL		WRITE_595			; LCD ye gönder
MOVF		LCD_DATA,W			; Ilk önce msb gönderilir
ANDLW		0F0H				; D7-D4 maskele
IORLW		02H					; E=0 RW=0 RS=1   x
CALL		WRITE_595			; LCD ye gönder,
SWAPF		LCD_DATA,W			; lsb için nibble'ları değiştir
ANDLW		0F0H				; D7-D4 maskele
IORLW		0AH					; E=1 RW=0 RS=1    x
CALL		WRITE_595			; LCD ye gönder, LCD enable
SWAPF		LCD_DATA,W			; lsb için nibble'ları değiştir
ANDLW		0F0H				; D7-D4 maskele
IORLW		02H					; E=0 RW=0 RS=1    x
CALL		WRITE_595			; LCD ye gönder, LCD enable
DLY_10US 	.10					; LCD'nin datayı yazabilmesi için en az 50us
RETURN
; *******************************************************************************************************
; DATA_OUT içindeki 8 bitlik veri 595'e yazılır ve Latch edilir
; Böylece LCD'ye komut veya karekter ulaşır

WRITE_595:
MOVWF		DATA_OUT			; DATA_OUT registerinin içeriği gönderilir
MOVLW		.8
MOVWF		HC595_COUNT			; 8 Bit için sayıcı
_595_BIT:
BCF			LCD_SDA
BTFSC		DATA_OUT,7
BSF			LCD_SDA
BSF			LCD_SCK				; Shift
BCF			LCD_SCK
RLF			DATA_OUT,F
DECFSZ		HC595_COUNT,F
GOTO		_595_BIT
BSF			LCD_LOAD			; Latch et
BCF			LCD_LOAD
RETURN
; *******************************************************************************************************
LCD_STR:							; LCD_STRING macrosunda kullanılır, tüm table'lar için geçerlidir.
IORLW		0					; 0 gelirse gönderme bitmiştir
BTFSC		ZERO_FLAG			; Table'dan W=0 gelirse geri dön
GOTO		$+3					; Yazma işlemi bitmiştir , zero_flag=1'dir
CALL		LCD_DATA_YAZ
INCF		TABLE_REG,F
RETURN

BLINK_ON:							; Blink Aç
MOVLW		0DH
GOTO		$+2
BLINK_OFF:							; Blink Kapat
MOVLW		0CH
CALL		LCD_KOMUT_YAZ
RETURN

; delay routinleri
X_MSN:								; COUNT3 x 1msn delay sağlar
;	CLRWDT							; Her msn'de WDT'yi sil
MOVWF		COUNT3
CALL		ONE_MSN
DECFSZ		COUNT3,F
GOTO		$-2
RETURN

ONE_MSN:
MOVLF		.100,COUNT1			; 1msn delay için COUNT1'e 100 yükle
; Count1=1 iken  toplam 11usn delay
; count1=100 iken toplam 1ms yani 1000usn olamalı(100x9,6usn+100x0,2usn+99x0,4usn+1,2usn)=960+20+40+1,2=1021usn
; count1=25 iken 250usn olmalı (25x9,6usn+25x0,2usn+24x0,4usn+1,2usn)=240+5+9,6+1,2=256usn
X_ON_USN:								; Buraya kadar 800ns
CALL		ON_USN				; Count1x9,6usn
DECFSZ		COUNT1,F				; COUNT1x200ns
GOTO		$-2						; (COUNT1-1)x400ns
RETURN								; 400ns

; 20Mhz'de tam 9,6 usn delay sağlar
ON_USN:								; 400ns
MOVLF		.11,COUNT2			; 400ns
NOP								; 11x200ns
DECFSZ		COUNT2,F			; 11x200ns
GOTO		$-2					; 10x400ns
RETURN							; 400ns

PORTLARI_HAZIRLA:
BANK0							; Bank0'a geç
CLRF		INTCON				; Interupt Control Registerlerini clear et
CLRF		PIR1				; Interrupt Flagleri temizle
CLRF		PORTA				; Latch'leri temizle
CLRF		PORTB
CLRF		PORTC
BANK1							; Bank1'e geç
MOVLF		07H,ADCON1			; PortA Digital I/O
MOVLF		00H,OPTION_REG
CLRF		TRISA				; PortA çıkış
BANK0							; Bank0'a geç
RETURN

END

Uygula ile ilgili aşağıya bir kaç resim ekledim. Dediğim gibi bu tür uygulamaları normalde 28pin’e kadar olan uC’ler de kullanıyorum(tabii ki C versiyonunu) ama aşağıya çalışırlığını göstermek için benim yaptığım PIC184520/PIC16F877A geliştirme boardunu kullandım. Resimlerden de görüldüğü gibi, LCD ile 3 tel üzerinden haberleşiliyor. LCD kart beslemesi için 7V5-8V arası 78L05 için en iyi değerdir.

picture1_800600 picture3_800600picture4_800600

Yorum ekle

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir