Açıklamalı pic16f877 uygulama kodları cod asm c

| Mayıs 26, 2023 Tarihinde güncellendi
Açıklamalı pic16f877 uygulama kodları cod asm c

Altaş Yayıncılık ve Elektronik satışa sunduğu “PIC Programlama Teknikleri ve PIC 16F877A” adlı kitabın ücretsiz dağıtılan uygulama devrelerine ait kaynak assembly ve c yazılımları pic16f877 deneme gelitirme kartları ile çalıştırılabilir. Türkçe açıklamaları olduğu için pic16f877 ile devre kurulabilir yada projelerinizde çözüm bulamadığınız durumlarda komut açıkamaları kullanılan yöntemler yardımcı olabilir ayrıca mplab üzerinde programın çalışmasını test edebileceğiniz .cod dosyalarıda bulunmakta

PCBway Türkiye PCB Manufacturer PCB Assembly

Hazırayanlar: Hikmet ŞAHİN Ayhan DAYANIK Caner ALTINBAŞAK Emeği geçen hazırayan kişilere teşekkürler

Kodları test edebilmeniz için çeşitli pic16f877 deneme geliştirme kartları PIC16F84 PIC16F877 Deneme devreleri isis simülasyon, Microchip PIC16F877 Test Deney Kartı

PIC 16F877 assembly proje listesi ve örnekler

12_2.asm: Seri LCD kullanımı
12_1.asm: 4-bit arabirim modunda LCD kullanımı
11_5_b.asm: Başka bir PIC’den USART ile senkron veri alımı
11_5_a.asm: 4×4 tuş takımı ile USART senkron iletişim
11_4.asm: 4×4 tuş takımı tasarımı
11_3.asm: Buton kontrolü
4_8.asm: WDT uygulaması.
4_7.asm: WDT uygulaması.
11_2.asm: 4 dijit 7 segment display uygulaması
11_1.asm: 7 segment display uygulaması
10_1.asm: PSP kullanımı
9_3.asm: Seri eeprom ile iletişim.
9_2.asm: Flash program belleğini okuma ve yazma
9_1.asm: Dahili eeprom belleğe veri yazma ve okuma
7_2.asm: A/D modülü ile ısı ölçümü (LM35 ile)
7_1.asm: A/D dönüştürücü uygulaması.
6_1.asm: SFR’siz Asenkron Seri veri İletişimi.
5_3.asm: PWM modülünün kullanılması.
5_2.asm: CCP1 compare modunun kullanılması.
5_1.asm: CCP1 capture modunun kullanılması.
2_2.asm: 0-255 ikilik düzende TMR0 ile dışardan aldığı saat darbesi ile sayan sayıcı
6_6.asm: I²C Protokolü ile Seri Veri İletişimi (PCF8574 kullanılarak).
6_5.asm: MSSP modülü SPI master iletişim (MAX7219 kullanarak).
6_4.asm: MSSP modülünün ile SPI master modunda veri iletişimi 74HC595 kullanarak).
6_3.asm: SFR’siz senkron seri veri iletişimi (74HC597 kullanılarak).
6_2.asm: SFR’siz senkron seri veri iletişimi (74HC595 kullanılarak).
4_6.asm: Timer2’nin Zamanlayıcı Olarak Kullanılması.
4_5.asm: Timer1’in Senkronize Sayıcı Olarak Kullanılması.
4_4.asm: Timer1’in Zamanlayıcı Olarak Kullanılması.
4_3.asm: Timer1’in Zamanlayıcı Olarak Kullanılması görmek.
4_2.asm:Timer0’ın Harici Tetikleme (RB0/INT) İle Sayıcı Olarak Kullanılması.
4_1.asm: Timer0’ın zamanlayıcı olarak kullanılmasını göstermek.
3_6.asm: RB4-RB7 uçlarındaki değişikle uyku modundan çıkışı göstermek.
3_5.asm: Kesmeden çıkmak için tuştan parmağın çekilmesini bekleyen program.
3_4.asm: İki kesmeyi kaynağını beraber kullanmak.
3_3.asm: Kesmeden çıkmak için tuştan parmağın çekilmesini bekleyen program.
3_2.asm: Kesmelerin genel özellikleri ve RB0 harici kesmesi.
3_1.asm: STATUS register’ı içeriğine bakarak karar vermek.
6_7.asm: USART Modülü İle Asenkron Seri Veri İletişimi.
2_1.asm: 0-255 arasında ikilik düzende sayıcı

8_3.asm: Komparatörün ortak referanslı PORTA çıkışlı iki karşılaştırıcı olarak kullanılması

8_2.asm: Komparatör modülünün dahili ortak referanslı 4 girişten seçimli iki karşılaştırıcı modunda kullanılması.

8_1.asm: Komparatör modülünün iki bağımsız karşılaştırıcı olarak kullanılması

6_11_2.asm: USART Modülü İle İki Mikrodenetleyici Arasında Master/Slave Senkron Seri Veri İletişimi.

6_11_1.asm: USART Modülü İle İki Mikrodenetleyici Arasında Master/Slave Senkron Seri Veri İletişimi

6_10.asm: USART modülü ile senkron master mod veriiletişimi(74HC595 kullanarak).

6_9.asm: USART Modülü İle Senkron Master Mod Veri İletişimi (74HC165 kullanarak).

6_8_2.asm: USART Modülü İle Asenkron Seri Veri İletişimi (PIC16F877A ile PIC 16F628A kullanılarak)

6_8_1.asm: USART Modülü İle Asenkron Seri Veri İletişimi (PIC16F877A ile PIC 16F628A kullanılarak).


;	Dosya Adı		: 9_1.asm
;	Programın Amacı		: Dahili eeprom belleğe veri yazma ve okuma
;	PIC DK2.1a 		: PORTB Çıkış ==> LED
;				: XT ==> 4Mhz

	list p=16F877A
	include "p16F877A.inc"	
	__config H'3F39' 		;Tüm program sigortaları kapalı, 
					;Osilatör XT ve 4Mhz
	ORG 	0			;Reset vektör adresi.
	clrf 	PCLATH			;0. Program sayfası seçildi.
	goto 	ana_program		;ana_programa'a git.
	
	ORG	4			;Kesme vektör adresi.
Kesmeler				;Kesme kullanımı gerekiyorsa 
					;buradan itibaren yazılmalı. 
					;ya da goto komutu ile buradan yönlendirilmeli.
	retfie

; Dahili EEPROM'a veri yazma alt programı:
; Çağrılmadan önce EEADR kaydedicisine yazılacak adres, EEDATA 
; kaydedicisine ise yazılacak veri yüklenmeli.

dahili_EEPROM_yaz
	banksel EECON1			;EECON1'in bulunduğu BANK seçildi.
	bcf	INTCON, GIE		;Genel kesmeler pasif. (Yazmada 
					;işlem akışı bozulmamalı.)
	bsf	EECON1, WREN		;Yazma etkinleştirme bit’i set 
					;edildi.
	movlw	0x55			;Yazma için buradan itibaren 5 
					;satır aynen korunmalı.
	movwf	EECON2
	movlw	0xAA
	movwf	EECON2
	bsf	EECON1, WR		;Yaz komutu verildi.
	bsf	INTCON, GIE		;Genel kesmeler aktif. (Kesme 
					;kullanılmayacaksa silinebilir.)
dahili_ee_j1
	btfsc 	EECON1, WR		;Yazma işlemi tamamlanana kadar 
					;bekle (WR=0 olana kadar).
	goto 	dahili_ee_j1
	bcf 	EECON1, WREN		;Yazma izni kaldırıldı.
	return

; Dahili EEPROM'dan veri okuma alt programı: Çağrılmadan önce EEADR 
; kaydedicisine okunacak verinin adresi yüklenmeli.

dahili_EEPROM_oku
	banksel EECON1
	bsf	EECON1, RD
	banksel EEDATA
	movf	EEDATA, W
	return

; Ana program: 0x0A dahili EEPROM adresine 0x97 bilgisi yükleniyor,
; Daha sonra aynı adresten veri okunarak PORTB'deki LED'lerde 
; görüntüleniyor.

ana_program
	banksel TRISB			;BANK1 seçildi, TRISB bu bankta.
	clrf	TRISB			;PORTB pinleri çıkışa ayarlandı.
	banksel PORTB			;BANK0 seçildi, PORTB bu bankta.
	clrf	PORTB			;İlk anda LED'ler sönük.
	movlw	0x0A			;Yazılacak Dahili EEPROM adresi
	banksel EEADR			;EEADR kaydedicisi için BANK 
					;seçildi.
	movwf 	EEADR			;Adres bilgisi yüklendi.
	movlw	0x97			;Yazılacak veri.
	movwf	EEDATA			;Veri yüklendi.
	call	dahili_EEPROM_yaz	;Yazma alt programını çağır.
	banksel EEADR			;EEADR kaydedicisi için BANK 
					;seçildi.
	movlw	0x0A			;Okunacak Dahili EEPROM adresi.
	movwf	EEADR			;Adres bilgisi yüklendi.
	call	dahili_EEPROM_oku	;Okuma alt programını çağır.
	banksel PORTB			;BANK0'a geç.
	movwf	PORTB			;Okunan değeri LED'lerde görüntüle.
ana_j1
	goto	ana_j1			;Sistem kapatılana yada resetlenene 
					;kadar boş döngü.
	END

;	Dosya Adı		: 9_2.asm
;	Programın Amacı		: Flash program belleğini okuma ve yazma
;	Notlar 			: Proteus programı simülasyonu.
;				: XT ==> 20Mhz

	list p = 16F877A
	include "p16F877A.inc"
	__config H'3B32'	;PWRT on, WRT Enable, diğer 
				;sigortalar kapalı, Osilatör HS ve 
				;20Mhz.

; Buton ve değişken tanımlamaları yapılıyor.

#define ADRESARTIR	1	;Adres artırma butonu.
#define PROGRAMSIL	2	;Program silme butonu.

FlashAdresL	equ	0x20	;Flash adresinin en değersiz byte 
;değişkeni.
FlashAdresH	equ	0x21	;Flash adresinin en değerli byte 
;değişkeni.
FlashDataL	equ	0x22	;Flash'a yazılan ya da okunan 
				;verinin en değersiz byte değişkeni
FlashDataH	equ	0x23	;Flash'a yazılan ya da okunan 
				;verinin en değerli byte değişkeni.
	org	0
	goto	ana_program
	
	org	4
	goto	kesme

; Kesme alt programı.

kesme
	retfie

; Ana program portları yönlendirir ve ilk durumları yükler. 
; ADRESARTIR butonuna her basıldığında 0. adresten başlayarak Flash 
; program belleğini okuyarak PORTB ve PORTC üzerinde görüntüler. 
; ADRESARTIR butonu bırakılana kadar ikinci bir görüntüleme yapmaz. 
; PROGRAMSIL butonuna basıldığı zaman 0. adresten itibaren programı 
; imha eden alt program çalışır.

ana_program
	banksel TRISB				;Bank0 seçildi.
	clrf	TRISB				;PORTB çıkışa ayarlandı.
	clrf	TRISC				;PORTC çıkışa ayarlandı.
	movlw	0x06	
	movwf	ADCON1				;PORTA dijital I/O ayarlandı
	movlw	0xFF
	movwf	TRISA				;PORTA tüm bit’leri giriş. 
	banksel PORTB
	clrf	PORTB				;İlk anda 0. 
	clrf	PORTC				;İlk anda 0.
	clrf	FlashAdresL			;0. adresten itibaren Flash 
						;program belleği okunacak.
	clrf	FlashAdresH
	movlw	0x07
	movwf	CMCON				;Komparatör girişleri 
						;kapatıldı.
ana_j1
	banksel PORTA				;Bank0'a geçildi.
	btfss	PORTA, PROGRAMSIL
	call	Program_Sil	
	btfsc	PORTA, ADRESARTIR		;Bir sonraki adresin 
						;içeriğini görüntülemek için 
						;devam et.
	goto	ana_j1				;Butonlara basılıp 
						;basılmadığını kontrole 
						;devam et.
	call	Flash_Read			;Flash program belleğinin 
						;ilgili adresini oku.
	banksel PORTB				;Bank0'a geçildi.
	movf	FlashDataH, W		
	movwf	PORTB				;Okunan verinin en değerli 
						;byte'ı PORTB çıkışlarında.
	movf	FlashDataL, W
	movwf	PORTC				;Okunan verinin en değersiz 
						;byte'ı PORTC çıkışlarında.
	btfss	PORTA, ADRESARTIR		;ARTIR'ma butonu bırakılana 
						;kadar boş döngü.
	goto	$-1
	incf	FlashAdresL, F			;Adresin yalnızca en 
						;değersiz byte'ını artır.
	goto	ana_j1				

; Flash program belleğine 2 byte veri yazan alt program.
; Adres = FlashAdresH:FlashAdresL,   Veri = FlashDataH:FlashDataL

Flash_Write 
	banksel FlashAdresL			;FlashAdresL kaydedicisinin 
						;bulunduğu banka geç.
	movf	FlashAdresL, W			;Adresin en değersiz byte'ı 
						;EEADR'ye yükleniyor.
	banksel EEADR				;EEADR kaydedicisinin 
						;bulunduğu banka geç.
	movwf	EEADR				;EEADR = FlashAdresL
	banksel FlashAdresH			;FlashAdresH kaydedicisinin 
						;bulunduğu banka geç.
	movf	FlashAdresH, W			;Adresin en değerli byte'ı 
						;EEADRH'a yükleniyor.
	banksel EEADRH				;EEADRH kaydedicisinin 
						;bulunduğu banka geç.
	movwf	EEADRH				;EEADRH = FlashAdresH
	banksel FlashDataL			;FlashDataL kaydedicisinin 
						;bulunduğu banka geç.
	movf	FlashDataL, W			;Verinin en değersiz byte'ı 
						;EEDATA kaydedicisine 
						;yükleniyor.
	banksel EEDATA				;EEDATA kaydedicisinin 
						;bulunduğu banka geç.
	movwf	EEDATA				;EEDATA = FlashDataL
	banksel FlashDataH			;FlashDataH kaydedicisinin 
						;bulunduğu banka geç.
	movf	FlashDataH, W			;Verinin en değerli byte'ı 
						;EEDATH laydedicisine 
						;yükleniyor.
	banksel EEDATH				;EEDATH kaydedicisinin 
						;bulunduğu banka geç.
	movwf	EEDATH				;EEDATH = FlashDataH
	banksel EECON1				;EECON1 kaydedicisinin 
						;bulunduğu banka geç.
	bsf	EECON1, EEPGD			;Program hafızasına erişim etkin
	bsf	EECON1, WREN			;Yazmayı etkinleştir.
	bcf	INTCON, GIE			;Kesmelere izin verme
	movlw	0x55				;Bu değerler EECON 
						;kaydedicisine sıralı 
						;yüklenmeli.
	movwf	EECON2
	movlw	0xAA
	movwf	EECON2
	bsf	EECON1, WR			;Yaz komutu veriliyor.
	nop					;İşlemin tamamlanması için 2 
						;komut çevrimi bekle.
	nop
	bsf	INTCON, GIE			;Kesmelere izin ver.
	bcf	EECON1, WREN			;Yazmayı pasif hale getir.	
	return					;Alt programdan çık.

; Flash program belleğinden 2 byte veri okuyan alt program.
; Adres = FlashAdresH:FlashAdresL,   Veri = FlashDataH:FlashDataL

Flash_Read
	banksel FlashAdresL			;FlashAdresL kaydedicisinin 
						;bulunduğu banka geç.
	movf	FlashAdresL, W			;Adresin en değersiz byte'ı 
						;EEADR'ye yükleniyor.
	banksel EEADR				;EEADR kaydedicisinin 
						;bulunduğu banka geç.
	movwf	EEADR				;EEADR = FlashAdresL
	banksel FlashAdresH			;FlashAdresH kaydedicisinin 
						;bulunduğu banka geç.	
	movf	FlashAdresH, W			;Adresin en değerli byte'ı 
						;EEADRH'a yükleniyor.
	banksel EEADRH				;EEADRH kaydedicisinin 
						;bulunduğu banka geç.
	movwf	EEADRH				;EEADRH = FlashAdresH
	banksel EECON1				;EECON1 kaydedicisinin 
						;bulunduğu banka geç.
	bsf	EECON1, EEPGD			;Program hafızasına erişim 
						;etkin.
	bsf	EECON1, RD			;Okumayı etkinleştir.
	nop					;İşlemin tamamlanması için 2 
						;komut çevrimi bekle.
	nop
	banksel EEDATA				;EEDATA kaydedicisinin 
						;bulunduğu banka geç.
	movf	EEDATA, W			;EEDATA W aracılığı ile 
						;FlashDataL kaydedicisine 
						;aktarılacak.
	banksel FlashDataL			;FlashDataL kaydedicisinin 
						;bulunduğu banka geç.
	movwf	FlashDataL			;FlashDataL = EEDATA
	banksel EEDATH				;EEDATH kaydedicisinin 
						;bulunduğu banka geç.
	movf	EEDATH, W			;EEDATH W aracılığı ile 
						;FlashDataL kaydedicisine 
						;aktarılacak.
	banksel FlashDataH			;FlashDataH kaydedicisinin 
						;bulunduğu banka geç.
	movwf	FlashDataH			;FlashDataH = EEDATH
	return					;Alt programdan çık.

; Flash program belleğinin 0x0000-0x00FF adres bölgesini 0x00 
; bilgileri ile doldurarak programı siler Programı silerken 
; Flash_Write alt programının bulunduğu adres bölgesinde program 
; işleyişi kontrolden çıkmaktadır. Bunun nedeni kendisini imha 
; ederken bir sonraki veriyi silmeye çalıştığında hatalı kodlar ile 
; karşılaşmasıdır.


;	Dosya Adı		: 10_1.asm
;	Programın Amacı		: PSP kullanımı
;	Notlar 			: Proteus programı simülasyonu
;				: XT ==> 20Mhz

	list p = 16F877A
	include "p16F877A.inc"
	__config H'3F3A' 		;Tüm program sigortaları kapalı, 
					;Osilatör HS ve 20Mhz

; Genel değişken tanımlamaları

#define PSP_errorFlag	7
#define PSP_inputFlag	6
#define PSP_outputFlag	5

PSP_CtrlByte		equ 0x20
PSP_inputBuffer		equ 0x21
PSP_outputBuffer	equ 0x21

	ORG	0
	clrf	PCLATH
	goto	Ana_Program

	ORG	4

; PSP'den gelen kesmeleri işler. Veri alındı ise alınan veriyi 
; PSP_inputBuffer'a yazar ve verinin alındığına dair PSP_inputFlag 
; bayrağını set eder. Master cihazdan okuma komutu geldi ise ve 
; gönderilecek bir veri daha önceden PSP_outputBuaffer'a yazıldı ise 
; Master cihaza PORTD üzerinden veriyi transfer eder. Ve Verinin 
; hazır olduğunu belirten PSP_outputFlag bayrağı siler.

interrupt
	banksel PIR1
	btfss	PIR1, PSPIF		;PSP kesmesi oluştu ise (veri geldi 
					;ya da veri gönderildi ise) komut 
					;atla.
	goto	int_son			;Kesme sonuna git ve kesmeden çık.
	banksel TRISE
	btfss	TRISE, IBF		;Veri alındı ise komut atla.
	goto	int_j1
	banksel PSP_CtrlByte
	bsf	PSP_CtrlByte, PSP_inputFlag	;Veri alındı bayrağını 
						;set et.
	movf	PORTD, W			;Gelen veriyi W'ye al. 
	movwf	PSP_inputBuffer			;W'yi giriş buffer değişkenine 
						;aktar.
int_j1
	banksel TRISE				;Bank1'e geç.
	btfss	TRISE, OBF			;Veri gönderildi ise komut atla.
	goto	int_j2
	banksel PSP_CtrlByte			;Bank0 seçildi, bu değişken ve 
						;PORTD aynı bankda.
	btfss	PSP_CtrlByte, PSP_outputFlag	;veri gönderme bayrağı 
						;set ise komut atla.
	goto	int_j2
	movf	PSP_outputBuffer, W		;Çıkış buffer değişkenine 
						;yüklenen veriyi
	movwf	PORTD				;PORD'ye gönder.
	bcf	PSP_CtrlByte, PSP_outputFlag	;Veri göndermeye hazır 
						;bayrağını sil.
int_j2
	banksel TRISE				;Bank1'e geç.
	btfss	TRISE, IBOV			;PSP'de hata oluştuysa komut atla.
	goto	int_son
	banksel PSP_CtrlByte
	bsf	PSP_CtrlByte, PSP_errorFlag	;Hata bayrağını set et
	bcf	TRISE, IBOV	
	bcf	PIR1, PSPIF			;PSP kesme bayrağını sil.
int_son
	retfie	

; PSP iletişimi ayarlar, portları yönlendirir ve kesmeleri 
; aktifleştirerek PSP iletişimi başlatır.

init
	banksel TRISE			;Bank1'e geçildi.
	movlw	B'00110111'
	movwf	TRISE			;PSPMODE aktif hale getirildi, RD, 
					;WR ve CS uçları giriş yapıldı.
	clrf	TRISB			;PORTB çıkış yapıldı.
	movlw	0x07
	movwf	ADCON1			;Analog girişler kapatıldı. 
					;PORTE'nin RD, WR ve CS girişleri 
					;için
	banksel PORTB			;Bank0'a geçildi.
	clrf	PORTB			;PORTB'nin ilk çıkışları LOW 
					;yapıldı.
	clrf	PSP_CtrlByte		;PSP değişkenlerinin ilk durumu 
					;sıfırlanıyor.
	clrf	PSP_inputBuffer
	clrf	PSP_outputBuffer
	banksel PIE1
	bsf	PIE1, PSPIE		;Paralel Slave Port kesmesi 
					;etkinleştirildi.
	bsf	INTCON, PEIE		;Çevresel kesmeler etkinleştirildi.
	bsf	INTCON, GIE		;Etkinleştirilen kesmelere izin
					;verildi.
	return

; Ana program PSP'den yazma sinyali geldiğinde gelen veriyi alır ve 
; PORTB üzerinde bağlı olan LED’ler üzerinde görüntüler. Veri okuma 
; kısmı uygun bir master cihaz kullanılmadığı ve kurulan devremiz 
; uygun olmadığı için boş bırakılmıştır, fakat gerekli ipucu 
; verilmiştir.

Ana_Program
	call	init
ana_j1
	banksel PSP_CtrlByte
	btfss	PSP_CtrlByte, PSP_inputFlag
	goto	ana_j2
	movf	PSP_inputBuffer, W
	movwf	PORTB
	bcf	PSP_CtrlByte, PSP_inputFlag	;Veri alındı bayrağını 
						;sil.
ana_j2
	btfsc	PSP_CtrlByte, PSP_outputFlag	;Çıkış verisi hazır 
						;bayrağı sıfır ise 
						;komut atla.
	goto	ana_j1

;Buraya gönderilecek veriyi çıkış buffer değişkenine yazan kodlar 
;eklenecek. Örneğin sayac diye bir değişken içeriğini çıkışa 
;transfer etmek istersek

	;movf	sayac, W
	;movwf	PSP_outputBuffer		

;sayac içeriği çıkış buffer'ına yazıldı, gönderilmek için beklemede

	bsf	PSP_CtrlByte, PSP_outputFlag	;Veri gönderme 
;bayrağını set et 
;(veri gönderilmeye hazır).

;Eğer MASTER cihazdan okuma (RD) sinyali gelirse TRISE'nin OBF bit’i 
;set olur, kesmede ilgili kısım çalışır. PSP_outputBuffer'a yüklenen 
;veri kesme içerisinden Master cihaza gönderilir ve PSP_outputFlag 
;bayrağı silinir.
	goto	ana_j1

	END

;	Dosya Adı		: 12_1.asm
;	Programın Amacı		: 4-bit arabirim modunda LCD kullanımı
;	PIC DK2.1a 		: PORTB Çıkış ==> LCD display
;				: XT ==> 4Mhz

	list p=16F877A
	include "p16F877A.inc" 
	__config H'3F31' 		;PWRT on, diğerleri kapalı, 
					;Osilatör XT ve 4Mhz

; Değişken tanımları yapılıyor: Her bir değişken başlangıç 
; adresinden itibaren birbirinin peşi sıra 1 byte yer kaplar.

	CBLOCK	0x20	;16F877A'nın RAM başlangıç adresi, 
	sayacH		;sayacın yüksek byte'ı.
	sayacL		;sayacın düşük byte'ı.

	LCD_data	;LCD için geçici veri değişkeni.
	LCD_tmp0	;LCD için geçici veri değişkeni.
	LCD_tmp1	;LCD için geçici veri değişkeni.
	LCD_line	;LCD için satır bilgisini tutan değişken.
	LCD_pos		;LCD için sütun bilgisi tutan değişken.

	HexMSB		;Desimale çevrilecek sayının en değerli byte'ı.
	HexLSB		;Desimale çevrilecek sayının en değersiz byte'ı.
	binler		;Desimale çevrilen sayının binler basamağı.	
	yuzler		;Desimale çevrilen sayının yüzler basamağı.	
	onlar		;Desimale çevrilen sayının onlar basamağı.	
	birler		;Desimale çevrilen sayının birler basamağı. 

	delay_s_data	;Gecikme alt programları için veri değişkeni.	
	delay_data	;Gecikme alt programları için veri değişkeni.
	ENDC

	ORG 	0 
	pagesel Ana_program	 
	goto 	Ana_program	;Ana programa git.

	ORG 	4		;Kesme alt programı bu adresten başlıyor.
	goto	kesme

; LCD ile ilgili temel tanımlamalar ve mesajlar.

; LCD'nin bağlı olduğu port tanımları yapılıyor.
#define LCD_DataPort PORTB		;Data pinlerinin bağlı olduğu port 
					;(D7-D4  -> RB3-RB0 ).
#define LCD_CtrlPort PORTB		;Kontrol pinlerinin bağlandığı port

; LCD'nin kontrol pinlerinin bağlı olduğu mikrodenetleyici pinleri 
; tanımlanıyor.
#define LCD_RS	4		;LCD RS pini RB4'e bağlı.
#define LCD_EN	5		;LCD E pini RB5'e bağlı.
#define LCD_RW	6		;LCD RW pini RB6'ya bağlı.

mesajlar			;LCD'ye gönderilecek mesajlar buraya yazılıyor.
	addwf	PCL, F			;mesaj adresini yükle.
msg0	dt	"Merhaba ", 0		;0 sonlandırma karakteri.
msg1	dt	"DUNYA!..", 0
msg2	dt	"HEX:", 0
msg3	dt	"DEC:", 0

; LCD ile ilgili macro tanımları:

LCD_RS_HIGH	macro			;LCD'nin RS girişini HIGH yaparak 
	banksel LCD_CtrlPort		;veri alma modu seçilir.
	bsf	LCD_CtrlPort, LCD_RS
	endm

LCD_RS_LOW	macro			;LCD'nin RS girişini LOW yaparak 
	banksel LCD_CtrlPort		;komut alma modu seçilir.
	bcf	LCD_CtrlPort, LCD_RS	
	endm

LCD_EStrobe macro			;LCD'ye veri ya da komut 
	banksel LCD_CtrlPort		;gönderildiğinde LCD'nin 
	bsf	LCD_CtrlPort, LCD_EN	;bunu işlemesini sağlar.
	movlw	.20			;20us kadar bekle. 
	call	delay_us
	bcf	LCD_CtrlPort, LCD_EN
	endm

LCD_Locate	macro	line, pos
  	movlw 	line			;Satır bilgisini yükle.
	movwf	LCD_line	
 	movlw 	pos			;Sütun bilgisini yükle.
	movwf	LCD_pos				
	call	LCD_SetPos		;Kursörü konumlandır.
	endm

; ----------------LCD ile ilgili fonksiyonlar.---------------------

; 4 bit iletişim modunda LCD'ye veri transferi yapar.

LCD_NybbleOut                       
	andlw	0x0F			;En değersiz 4 bit W'de,
	movwf	LCD_tmp0		;geçici değişkene alınıyor.
	movf	LCD_DataPort,W		;LCD'nin data pinlerinin bağlı 
					;olduğu port bilgisi W'de.
	andlw	0xF0			;Port bilgisinin en değerli 4 bit’i 
					;korunuyor.
	iorwf	LCD_tmp0, W		;Korunan bilgi ile veri 
					;birleştiriliyor.
	movwf	LCD_DataPort		;PortA transfer ediliyor.
	LCD_EStrobe			;LCD'nin veriyi alması sağlanıyor.
	movlw	.255			;250us kadar bekle. Bu süre LCD 
					;içerisindeki işlemlerin tamamlanması
	call	delay_us		;için gerekli ( en az 160us kadar ).
	return

; LCD'ye 1 byte komut transfer eder.

LCD_SendCmd         	         	
	movwf	LCD_data	 	;Komutu geçici değişkene al.
	swapf	LCD_data, W   		;En değerli 4 bit’i gönder.
	LCD_RS_LOW			;RS = 0 (komut modu)
call	LCD_NybbleOut
	movf	LCD_data, W		;En değersiz 4 bit’i gönder.
	LCD_RS_LOW			;RS = 0 (komut modu)
	call	LCD_NybbleOut			
	return

; LCD'ye bir rakam ya da bir karakter göndermek için kullanılır.

LCD_SendASCII						
	addlw	'0'			;LCD'ye rakamı ASCII koda 
					;dönüştürerek göndermek için.
LCD_SendCHAR				;LCD'ye karakter göndermek için 
					;çağrılacak.
	movwf	LCD_data		;Komutu geçici değişkene al.
	swapf	LCD_data, W		;En değerli 4 bit’i gönder.
	LCD_RS_HIGH			;RS = 1 ( veri gönderme modu )
	call	LCD_NybbleOut
	movf	LCD_data, W		;En değersiz 4 bit’i gönder.
	LCD_RS_HIGH			;RS = 1 ( veri gönderme modu )
	call	LCD_NybbleOut
	return

; 1 byte veriyi hexadesimal formda LCD'ye yazar.

LCD_SendHEX	
	movwf	LCD_tmp1
	sublw	0x9F			;sayı > 0x9F mi? 
	btfss	STATUS, C		;hayır ise bir komut atla.
	goto	LCD_HEX_j0
	swapf	LCD_tmp1, W
	andlw	0x0F			;En değerli 4 bit W'nin en 
	call	LCD_SendASCII		;değersiz 4 bit’inde.
	goto	LCD_HEX_j1
LCD_HEX_j0
	swapf	LCD_tmp1, W
	andlw	0x0F			;En değerli 4 bit W'nin en 
	addlw	.55			;değersiz 4 bit’inde.
	call	LCD_SendCHAR
LCD_HEX_j1
	movf	LCD_tmp1, W
	andlw	0x0F			;En değersiz 4 bit W'nin en 
	movwf	LCD_tmp1		;değersiz 4 bit’inde.
	sublw	0x09			;sayı > 0x09 mi? 
	btfss	STATUS, C		;hayır ise bir komut atla.
	goto	LCD_HEX_j2
	movf	LCD_tmp1, W	
	call	LCD_SendASCII
	return
LCD_HEX_j2
	movf	LCD_tmp1, W
	addlw	.55
	call	LCD_SendCHAR
	return

; 1 byte veriyi binary formda LCD'ye yazar.

LCD_SendBIN
	movwf	LCD_tmp1		;Geçici değişkene al.
	movlw	.0
	btfss	LCD_tmp1, 7		;7. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 7		;7. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.

	movlw	.0
	btfss	LCD_tmp1, 6		;6. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 6		;6. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.

	movlw	.0
	btfss	LCD_tmp1, 5		;5. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 5		;5. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.

	movlw	.0
	btfss	LCD_tmp1, 4		;4. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 4		;4. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.

	movlw	.0
	btfss	LCD_tmp1, 3		;3. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 3		;3. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.
	movlw	.0
	btfss	LCD_tmp1, 2		;2. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 2		;2. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.

	movlw	.0
	btfss	LCD_tmp1, 1		;1. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 1		;1. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.
	
	movlw	.0
	btfss	LCD_tmp1, 0		;0. bit 1 ise bir komut atla.
	call	LCD_SendASCII		;0 yazdır.
	movlw	.1
	btfsc	LCD_tmp1, 0		;0. bit 0 ise bir komut atla.
	call	LCD_SendASCII		;1 yazdır.
	return

; LCD ekran belleğini siler.

LCD_Clear
	movlw	0x01			;LCD görüntü belleğini sil, 
					;dolayısı ile 
	call	LCD_SendCmd		;LCD'de görünen bilgileri de sil.
	movlw	.5
	call	delay_ms
	return

; Kursörü göster

LCD_CursorOn
	movlw	0x0F			;Display'i aç, kursörü göster. 
	call	LCD_SendCmd		;Blink ON.
	return


; Kursörü gizle

LCD_CursorOff
	movlw	0x0C			;Display'i aç, kursörü gizle,
	call	LCD_SendCmd		;Blink OFF.
	return

; LCD ekranı kullanıma hazırlar.

LCD_init
	bsf	STATUS, RP0		;BANK1 seçildi. Yönlendirme 
					;kaydedicileri bu bankta.
	movf	LCD_DataPort, W
	andlw	0xF0			;Portun en değersiz 
					;dörtlüsü çıkış yapıldı.
	movwf	LCD_DataPort		;Port yönlendirildi.
	bcf	LCD_CtrlPort, LCD_EN	;LCD_CtrlPort'un LCD_EN 
					;pini çıkışa yönlendirildi.
	bcf	LCD_CtrlPort, LCD_RS	;LCD_RS pini çıkış yapıldı. 
	bcf	LCD_CtrlPort, LCD_RW	;LCD_RW pini çıkış yapıldı.
	bcf	STATUS, RP0		;BANK0 seçildi.
	clrf	LCD_DataPort

	movlw	.50
	call	delay_ms		;40-50 ms kadar bekle.
	LCD_RS_LOW
	movlw	0x03			;8 bit iletişim komutu verildi.
	call	LCD_NybbleOut	
	
	movlw	.5			;LCD'nin hazır olması için 
					;bekleniyor.
	call delay_ms

	LCD_EStrobe			;8 bit iletişim için komut 
					;yinelendi.
	movlw	.255			;160-255us kadar bekle. 
	call	delay_us
	
	LCD_EStrobe			;8 bit iletişim için komut 
					;yinelendi.
	movlw	.255			;160-255us kadar bekle. 
	call	delay_us

	LCD_RS_LOW
	movlw	0x02			;LCD, 4 Bit iletişim moduna alındı.
	call	LCD_NybbleOut	

	movlw	.255			;160-255us kadar bekle. 
	call	delay_us

	movlw	0x28			;4 bit iletişim, 2 satır LCD, 5x7 
call	LCD_SendCmd			;font seçildi.
	movlw	0x10			;LCD'de yazının kayması engellendi.
	call	LCD_SendCmd
	movlw	0x01			;LCD görüntü belleğini sil.
	call	LCD_SendCmd

	movlw	.5			;5 ms bekle.
	call	delay_ms

	movlw	0x06			;Kursör her karakter yazımında bir 
	call	LCD_SendCmd		;ilerlesin.
	movlw	0x0C			;Display'i aç, kursörü gizle.
	call	LCD_SendCmd
	return

; Mesaj etiketi (adresi) W’ye yüklenen mesajı LCD ekranda görüntüler                       

LCD_SendMessage
	Movwf	FSR		;İlk karaktere işaret et (onun adresini 
LCD_SMsg:			;tut).
	Movf	FSR, W		;İşaret edilen karakter sırasını W'ye al.
	incf	FSR, F		;Bir sonraki karaktere konumlan.
	Call	mesajlar	;Mesajlardan ilgili karakteri al.
	iorlw  0		;Mesaj sonu mu? 0 bilgisi alındı ise 
				;mesaj sonu demektir.
	btfsc  STATUS, Z	;Mesaj sonu değil ise bir komut atla.
	return			;Mesaj sonu ise alt programdan çık.
	call   LCD_SendCHAR	;Karakteri LCD'ye yazdır.
	goto   LCD_SMsg		;Bir sonraki karakter için 
				;işlemleri tekrarla.

; Kursörü LCD'de istenilen satır ve sütuna konumlandırır. Text'in 
; nereye yazılacağını belirler. 1 - 2 satır olan LCD'ler için 
; yazıldığına dikkat ediniz. 4 satır LCD'ler için LCD_line değerinin
; 0, 1, 2 veya 3 olması durumuna göre DDRAM başlangıç adresleri 
; tespit edilmelidir.

LCD_SetPos
	movlw	0x80		;0. satır için DDRAM adres başlangıç 
	movf	LCD_line, F	;değeri.
	btfss	STATUS, Z	;0. satır ise bir komut atla.
	movlw	0xC0		;1. satır için 0x80 adresine ilave 
				;edilecek değer.
	addwf	LCD_pos, W	;Kursör pozisyonu da ilave edilerek 
				;DDRAM'deki adres bulunuyor.
	call	LCD_SendCmd
	return

; 2 byte binary veriyi bcd'ye dönüştürür. Sonuç binler, yüzler, 
; onlar ve birler  değişkenlerinde saklanır.

HexTODec
	clrf binler			;binler = 0
	clrf yuzler			;yuzler = 0
	clrf onlar			;onlar = 0
	clrf birler			;birler = 0
binler_kont
	movlw	04h			;W'ye 1024 (0x0400) sayısının en 
					;değerli byte'ını yükle.
	subwf	HexMSB, W		;HexMSB'den 1024 çıkart.
	btfss	STATUS, C		;HexMSB > 1024'mü?
	goto	yuzler_kont2		;hayır ise yüzleri kontrol et.
	incf	binler, F		;evet ise binleri bir artır.
	movlw	04h			;W'ye 0x04 yükle.
	subwf	HexMSB, F		;HexMSB'den 1000 çıkart.
	movlw	18h			;W'ye 0x18 yükle.
	addwf	HexLSB, F		;HexLSB'ye (0x18 = 24) ekle 
	btfsc	STATUS, C		;elde var mı?
	incf	HexMSB, F		;evet ise bir artır.
	goto	binler_kont		;binleri yeniden kontrol et
yuzler_kont2
	movlw	0x01			;256 (0x0100)
	subwf	HexMSB, W		;HexMSB'den 200 çıkart ve sonucu 
					;W'ye sakla.
	btfss	STATUS, C		;sonuç >=256'mı?
	goto	yuzler_kont1		;Hayır ise 100'ün katlarını
					;kontrol et.
	movlw	0x02			;değilse,
	addwf	yuzler, F		;yuzler'e 2 ekle
	movlw	0x01			;W = 1
	subwf	HexMSB, F		;HexMSB'den 200 çıkart.
	movlw	0x38			;W =0x38 (256'nın 56 lık kısmı)
	addwf	HexLSB, F		;HexLSB'ye 56'yı ekle.
	btfsc	STATUS, C		;elde var mı?
	incf	HexMSB, F		;evet ise HexMSB'yi bir artır.
	movlw	0x0A			;W = 10
	subwf	yuzler, W		;yuzler = 1000 olup olmadığını 
					;kontrol et.
	btfss	STATUS, Z		;sonuç sıfır mı?
	goto	yuzler_kont2		;hayır ise yuzleri yeniden kontrol 
	clrf	yuzler			;et. yuzler = 0
	incf	binler, F		;binler'i artır.
	goto	yuzler_kont2		;yuzler'i 200 ya da daha büyük 
					;sayı için yeniden kontrol et.
yuzler_kont1 
	movlw	0x64			;W = 0x64
	subwf	HexLSB, W		;HexLSB'den 100 çıkart.
	btfss	STATUS, C		;sonuç >= 100 mü?
	goto	onlar_kont		;hayır ise onları kontrol et.
	incf	yuzler, F		;evet ise yuzler'i bir artır.
	movlw	0x64			;W = 0x64 (100)
	subwf	HexLSB, F		;HexLSB'yi 100 azalt.
	movlw	0x0A			;W = 0x0A (10)
	subwf	yuzler, W		;yuzler = 1000 kontrolü yap.
	btfss	STATUS, Z		;sonuç = 0 mı?
	goto	yuzler_kont1		;hayır ise 100 için yuzler'i 
					;yeniden kontrol et.
	clrf	yuzler			;yuzler = 0
	incf	binler, F		;binleri bir artır.
	goto	yuzler_kont1		;100 ya da daha büyük olma durumu 
					;için yüzleri yeniden kontrol et.
onlar_kont
	movlw	0x0A			;W = 0x0A (10)
	subwf	HexLSB, W		;HexLSB'den 10 çıkart.
	btfss	STATUS, C		;sonuç >= 10 mu?
	goto	birler_kont		;hayır ise birleri kontrol et.
	incf	onlar, F		;evet ise onları bir artır.
	movlw	0x0A			;W = 0x0A (10)
	subwf	HexLSB, F		;HexLSB'den 10 çıkart.
	goto	onlar_kont		;onlar'ı yeniden kontrol et.
birler_kont
	movf	HexLSB, W		;W = HexLSB
	movwf	birler			;birler = W, dönüşüm işlemi tamam
	return				;alt programdan çık.

; 1-255 sn arasında gecikme sağlayan alt program.

delay_s
	movwf	delay_s_data
delay_s_j0:
	movlw	.250			;4 * 250 = 1000 ms bekle,
	call	delay_ms		;her çevrim 1 sn.
	movlw	.250
	call	delay_ms
	movlw	.250					
	call	delay_ms
	movlw	.250
	call	delay_ms
	decfsz	delay_s_data
	goto	delay_s_j0
	return


; 1-255 ms arasında gecikme sağlayan alt program.

delay_ms
	movwf	delay_data
delay_ms_j0
	movlw	.142
	movwf	delay_data+1
	nop
	nop
delay_ms_j1
	nop
	nop
	nop
	nop
	decfsz	delay_data+1, F
	goto	delay_ms_j1
	nop
	decfsz	delay_data, F
	goto	delay_ms_j0
	nop
	return

; 16-255 µs gecikme sağlayan alt program.

delay_us
	movwf	delay_data
	rrf	delay_data, F
	rrf	delay_data, F
	movlw	.63
	andwf	delay_data, F
	movlw	.3
	subwf	delay_data, F
	nop
	decfsz	delay_data, F
	goto	$ - 2
	nop
	return

; Kesme programı (kullanılacak ise LCD ya da zamanlamanın önemli
; olduğu cihazlarla çalışırken iletişimin kesilmemesine dikkat 
; ediniz).

kesme
	retfie

; Ana program

Ana_program
	call	LCD_init		;LCD’yi kullanıma hazırlar.
Ana_j0:
	call	LCD_Clear		;LCD'deki bilgileri sil.
	call	LCD_CursorOff		;Kursörü gizle.
	clrf	sayacH			;sayac = 0
	clrf	sayacL

	LCD_Locate	0, 0		;0. satır, 0. sütuna konumlan.
	movlw	msg0-6			;mesaj0 yaz (adresi 6 eksiği).
call	LCD_SendMessage
	LCD_Locate	1, 0		;1. satır, 0. sütuna konumlan
	movlw	msg1-6			;mesaj1 yaz.
    	call	LCD_SendMessage

	movlw	.10
	call	delay_s			;10 saniye bekle.

Ana_j1:
	call	LCD_Clear		;LCD'deki bilgileri sil.

					;sayac değerini hexadesimal formda 0. satıra yaz.		
	LCD_Locate	0, 0		;0. satır, 0. sütuna konumlan.	
	movlw	msg2-6			;mesaj2 yaz.
	call	LCD_SendMessage
	movf	sayacH, W
	call	LCD_SendHEX
	movf	sayacL, W
	call	LCD_SendHEX

;sayaç değerini desimal formda 1. satıra yaz.		
	LCD_Locate	1, 0		;0. satır, 0. sütuna konumlan.	
	movlw	msg3-6			;mesaj2 yaz.
	call	LCD_SendMessage
	movf	sayacH, W		;HexMSB = sayacH
	movwf	HexMSB
	movf	sayacL, W		;HexLSB = sayacL
	movwf	HexLSB
	call	HexTODec		;Desimale dönüştür.
	movf	binler, W		;binler basamağını yaz.
	call	LCD_SendASCII
	movf	yuzler, W		;yüzler basamağını yaz.
	call	LCD_SendASCII
	movf	onlar, W		;onlar basamağını yaz.
	call	LCD_SendASCII
	movf	birler, W		;birler basamağını yaz.
	call	LCD_SendASCII

	movlw	.1			;1 sn bekle.	
	call	delay_s

; sayacL değerini binary formda 1. satıra yaz (0. satırda aynı 
; sayının HEX değeri var).		
	LCD_Locate	1, 0		;0. satır, 0. sütuna konumlan.	
	movf	sayacL, W
	call	LCD_SendBIN		;sayacL değerini binary formda 
					;göster.
; sayaç değerini 10000 olana kadar bir artır, 10000 ise en başa dön
	incf	sayacL, F		;sayacL'yi bir artır.
	btfsc	STATUS, Z		;sayacL sıfırdan farklı ise bir 
					;komut atla.
	incf	sayacH, F		;sayacH'i bir artır.
	movlw	0x27
 	subwf	sayacH, W
	btfss	STATUS, Z		;sayacH = 0x27 ise bir komut atla.
	goto	Ana_j2			;sayac henüz 10000'e ulaşmadı, o 
					;halde devam et.
	movlw	0x10
 	subwf	sayacL, W
	btfss	STATUS, Z		;sayacL = 0x10 ise bir komut atla.
	goto	Ana_j2			;sayac henüz 10000'e ulaşmadı, o 
					;halde devam et.
	goto	Ana_j0			;En başa dönerek işlemleri tekrar 
Ana_j2:				;et.
	movlw	.1			;1 sn bekle.
	call	delay_s
	goto	Ana_j1			;sayma işlemine devam.
	
	end

;	Dosya Adı		: 6_3.asm
;	Programın Amacı		: SFR’siz senkron seri veri iletişimi
;				 (74HC597 kullanılarak).
;	PIC DK 2.1 		: PORTB<0:4> Çıkış ==> LED
;				: XT ==> 4Mhz

	list p=16F877A
	include "p16F877A.inc"	
	__config H'3F31' 	;PWRT on, diğerleri kapalı, 
				;Osilatör XT ve 4Mhz.

; Genel tanımlamalar ve değişken tanımlamaları yapılıyor.

#define hc597_port	PORTB		;74HC597’ün bağlı olduğu 
					;port tanımı yapılıyor.
#define LOAD_Pin	0		;Load pininin işlemciye bağlı 
					;olduğu pin tanımlanıyor.
#define DATA_Pin	1		;Data pininin işlemciye bağlı 
					;olduğu pin tanımlanıyor.
#define CLK_Pin	2			;Clock pininin işlemciye bağlı 
					;olduğu pin tanımlanıyor.
#define LATCH_Pin	3		;Latch pininin işlemciye bağlı 
					;olduğu pin tanımlanıyor.

delay_ms_data		equ 0x20 	;delay_ms için 2 byte'lık değişken 
					;tanımı yapılıyor.
i			equ 0x22 	;Transfer edilecek verinin bit 
					;sırasını tespit değişkeni.
hc597_data		equ 0x23 	;Okunacak veriyi tutan değişken.

	ORG 	0			;Reset vektör adresi burası. 
	pagesel Ana_program		;Ana programın bulunduğu program 
					;sayfası seçildi.
	goto 	Ana_program		;Ana programa git.

	ORG 	4

; hc597_Oku alt programı, 1 byte veriyi donanım modüllerini
; kullanmadan yalnızca yazılım ile 74HC597 entegresinden okuyup 
; işlemciye transfer eder.

hc597_Oku
	Banksel hc597_port		;hc597_port'nin bulunduğu 
					;bank seçildi.
	bsf	hc597_port, LATCH_Pin	;Anahtarlardan bilgi Latch'a 
					;alınıyor.
	nop
	bcf	hc597_port, LATCH_Pin
	bcf	hc597_port, LOAD_Pin	;Latch'taki bilgi kaydırmalı 
					;kaydediciye aktarılıyor.
	nop
	bsf	hc597_port, LOAD_Pin

	movlw	8			;i değişkenine 8 bilgisi yüklendi.
	movwf	i			;i, 8 bit’in de alındığını kontrol 
					;etmek için kullanılıyor.
hc597_j0
	rlf	hc597_data, F
	btfss	hc597_port, DATA_Pin	;Data pininden gelen veri 1 
					;ise bir komut atla.
	goto	hc597_j1		;Gelen veri 0, o halde 
					;hc597_j1'e git.
	bsf	hc597_data, 0		;hc597_data değişkeninin 0.
					;bit’ini set et.
	goto	hc597_j2		;Clock palsi için devam.
hc597_j1
	bcf	hc597_data, 0		;hc597_data değişkeninin 0. 
					;bit’ini reset et.
hc597_j2
	bsf	hc597_port, CLK_Pin	;74HC597'in CLK pinine inen 
					;darbe kenarı uygulanıyor.
	nop
	bcf	hc597_port, CLK_Pin
	decfsz	i, F			; i sayacını bir azalt ve 8 bit’in
					;tamamı okundu ise bir komut atla.
	goto	hc597_j0
	return

; delay_ms alt programı 1-255 ms arasında değişken bekleme süresi 
; sağlar delay_ms_data yüksek byte değişkenine yüklenecek değer 
; kadar ms olarak gecikme sağlar.

delay_ms
delay_j0
	movlw	D'142'			;1 ms gecikme için taban değer.
	movwf	delay_ms_data+1		;delay parametresinin düşük 
					;byte'ına yüklendi.
	nop				;2 us bekle.
	nop
delay_j1
	nop				;4 us gecikme.
	nop
	nop
	nop
	decfsz	delay_ms_data+1, F	;delay parametresinin düşük 
					;byte'ını azalt sıfırsa komut atla.
	goto	delay_j1		;Henüz 1 ms gecikme sağlanamadı, 
					;düşük byte'ı azaltmaya devam et
	nop				;1 us bekle.
	decfsz	delay_ms_data, F	;delay parametresinin yüksek 
					;byte'ını azalt sıfırsa komut atla.
	goto	delay_j0		;1 ms beklemeyi tekrarla.
	nop				;1 us bekle.
	return				;Alt programdan çıkış.

; delay_5s alt programı 5 saniye gecikme için 20 kez 250 ms gecikme 
; işlemi gerçekleştirir. Delay sonucunda 5 saniyeye çok yakın bir 
; gecikme sağlanır.

delay_5s
	movlw	0x14			;20 * 250ms = 5000ms 
	movwf	i
delay_5s_j0	
	movlw	D'250'			;250 ms değerini delay_ms_data 
					;değişkenine yaz.
	movwf	delay_ms_data	
	call	delay_ms		;250 ms bekle.
	decfsz	i, F
	goto	delay_5s_j0
	return

; Ana program 74HC597 entegresine bağlı anahtarlardan alınan 
; bilginin donanım modülleri kullanılmadan yalnızca yazılım ile 
; okunarak PORTB’nin en değerli 4 çıkışında (RB7 - RB4) 5 sn 
; aralıklarla görüntülenmesini sağlar.

Ana_program
	banksel TRISB			;TRISB’nin bulunduğu banka geç.
	movlw	2
	movwf	TRISB			;PORTB’nin RB1 pini giriş, diğer 
					;pinleri çıkış yapıldı.
	Banksel PORTB			;PORTB’nin bulunduğu banka geç.
	clrf	PORTB			;PORTB'nin pinlerinin ilk andaki 
					;çıkışları sıfır.
Ana_j0
	call	hc597_Oku		;hc597_data değişkenindeki değeri 
					;74HC597’e yaz.
	movf	hc597_data, W		;hc597_data değişkeninde bulunan 
					;veriyi W’ye aktar.
	andlw	0xF0			;Verinin en değerli 4 bit’ini al.
	movwf	PORTB			;En değerli 4 anahtarın konumlarını 
					;PORTB’nin RB7-RB4 çıkışlarında 
					;göster.
	call	delay_5s		;5 saniye bekle.
	swapf	hc597_data, W		;hc597_data değişkeninde bulunan 
					;verinin en değerli ve en değersiz 
					;4 bit’ini yer değiştirerek W’ye 
					;aktar.
	andlw	0xF0			;Verinin en değersiz 4 bit’i artık 
					;W’nin en değerli 4 bit’i durumunda
	movwf	PORTB			;En değersiz 4 anahtarın 
					;konumlarını PORTB’nin RB7-RB4 
					;çıkışlarında göster.
	call	delay_5s		;5 sn bekle.
	goto	Ana_j0			;Ana_j0 etiketine git.

	END

;	Dosya Adı		: 6_7.asm
;	Programın Amacı		: USART Modülü İle Asenkron Seri Veri
;				  İletişimi.
;	PIC DK 2.1 		: PORTC<6:7> RS232 kablosuyla PC’ye
;				: XT ==> 20 Mhz
 
	list p=16F877A	 
	include "p16F877A.inc"	
	__config H'3F3A' 		;Tüm program sigortaları kapalı, 
					;Osilatör HS ve 20 Mhz.

; Değişken tanımları

RS232_Data	equ	0x20
	org	0
	clrf	PCLATH
	goto	Ana_program
	org	4

; Kesme alt programı: Varsa istenen kesmelerin işlenmesinde 
; kullanılabilir.

interrupt
	;Bu kısımda gerekirse usart modülünden veri alma ya da 
	;gönderme kesmeleri, A/D kesmesi, TRM0, TMR1, TMR2, CCP1IF, 
	;CCP2IF kesmeleri işlenebilir. Kesmelerin işlenmesindeki 
	;öncelik sıraları belirlenebilir. Örneğimizde veri gönderme 
	;ve almada kesme alt programına girmeden yalnızca kesme 
	;bayrakları kontrol edilerek usart birimine ait asenkron veri 
	;iletişimi gerçekleştirilmiştir.
	retfie				;Kesmeden çıkış

; RS232 portunda 1 byte veri yazar. Yazılacak veri RS232_Data 
; değişkenine yüklenmelidir.

RS232_Karakter_Gonder
	banksel PIR1
	btfss	PIR1, TXIF
	goto	$ - 1			;Daha önceden bir veri gönderilmiş 
					;ise aktarılana kadar bekle.
	bcf	PIR1, TXIF		;Veri gönderme kesme bayrağını sil.
	movf	RS232_Data, W	
	banksel TXREG
	movwf	TXREG			;RS232_Data değişkenindeki veriyi 
					;TXREG kaydedicisine yükle. Böylece 
					;veri çıkış buffer'ına yazılmış olur.	
	return				;Alt programdan çıkış.

; RS232 portundan 1 byte veri alır.

RS232_Karakter_Al
	banksel PIR1
	btfss	PIR1, RCIF	;Bilgi alındı ise bir komut atla.
	goto	$ - 1		;Bir komut geriye gel.
	bcf	PIR1, RCIF	;Alma gerçekleşti kesme bayrağını sil.
	movf	RCREG, W	;RCREG seri bilgi alış buffer'ındaki 
				;veriyi W'ye yükle.
	return			;RS232_Karakter_Al alt programından çıkış.

; Usart modülünün asenkron iletişimi için ilk ayarları 
; gerçekleştirir.

RS232_ilk_islemler
	banksel TRISC		;BANK1 seçildi. TRISC bu bankta
	bcf	TRISC, 6	;TX çıkışa
	bsf	TRISC, 7	;RX girişe yönlendirildi
	movlw	0x81		;SPBRG = 129 Fosc = 20 MHz'de 9600 baud 
				;hız için.
	movwf	SPBRG
	movlw	0x26
	movwf	TXSTA		;USART mod: asenkron, high speed, 8 bit 
				;iletişim, TXEN set edildi.
	movlw	0x90
	bcf	STATUS, RP0	;BANK0 seçildi RCSTA için.
	movwf	RCSTA		;Seri port etkin, 8 bit veri alış, CREN 
				;set : sürekli alış. 
	bsf	STATUS, RP0
	bsf	PIE1, TXIE	;TXIE set edildi.
	bsf	PIE1, RCIE	;RCIE set edildi.
	bsf	INTCON, PEIE	;Çevresel kesmelere izin verildi.
	return			;RS232_ilk_islemler alt programından çıkış

; Ana program: RS232 seri portttan aldığı verileri tekrar seri porta
; gönderir.

Ana_program
	call	RS232_ilk_islemler	;RS232 iletişimi için ilk işlemler.
	bcf	INTCON, GIE		;Kesme alt programı kullanılmadığı 
					;için GIE = 0 yap.
Ana_j1
	call	RS232_Karakter_Al	;RS232 portundan 1 byte veri al.
	movwf	RS232_Data		;Alınan veriyi RS232_Data 
					;değişkenine aktar.
	call	RS232_Karakter_Gonder	;RS232'deki veriyi RS232 
					;portuna gönder.
	goto	Ana_j1			;Aynı işlemleri tekrarla.
	END

;	Dosya Adı		: 6_9.asm
;	Programın Amacı		: USART Modülü İle Senkron Master Mod Veri
;				  İletişimi (74HC165 kullanarak).
;	Notlar 			: XT ==> 4Mhz
 
	list p=16F877A		
	include "p16F877A.inc"	
	__config H'3F31' 		;PWRT on, diğerler sigortaları 
					;kapalı, Osilatör XT ve 4 Mhz.

; Değişkenler tanımlanıyor ve derleyici direktifleri veriliyor.
; Kodun anlaşılmasını kolaylaştırmak için sembolik adlar kullanıldı.

#define hc165_SHLD	PORTC, 0	;74HC165 entegresinin SH/LD' girişi 
					;RC0'a bağlı.
#define OKU_BUTONU	PORTB, 0	;OKU butonu için pin tanımı yapıldı.
hc165_data	equ	0x20		;hc165_Veri_Oku alt program 
					;değişkeni.
	ORG	0
	clrf	PCLATH			;0. program sayfası kullanılıyor.
	goto	Ana_program		;Ana programa git.

; 74HC165, USART modülü senkron master modda iletişim için hazırlanıyor.

hc165_Ilk_islemler
	movlw	0x09		;(Synchronous) Baud Rate = Fosc/(4(X+1))
				;Baud Rate 	= 4.000.000/(4*(9+1))
				;	= 4.000.000/40 = 100.000 Hz.
	banksel SPBRG
	movwf	SPBRG		;Baud Rate değeri SPBRG kaydedicisine 
				;yüklendi.
	bsf	TXSTA, SYNC	;Senkron iletişim seçildi.		
	bsf	TXSTA, CSRC	;Clock kaynağı seçme bit’i set 
				;edildi. Kaynak: BRG kaydedicisi.
	bcf	STATUS, RP0	;BANK0'a geç. RCSTA bu bankta.
	bcf	RCSTA, CREN	;Sürekli okuma modu kapatıldı.
	bcf	RCSTA, RX9	;RX9 kullanılmıyor, 8 bit veri iletişimi.
	bsf	RCSTA, SPEN	;Senkron master seri port aktif hale 
				;getirildi.
	return

; USART modülü Senkron master mod kullanarak veri 74HC165'ten 
; işlemciye transfer ediliyor.

hc165_Veri_Oku
	bcf	STATUS,RP0		;BANK0'a geç, RCSTA ve 74HC165'in 
					;SH/LD' ayağının bağlı olduğu port 
					;bu bankta.
	bcf	hc165_SHLD		;Entegre girişlerden veri 
					;alabilmesi için LOAD yükleme 
					;moduna alınıyor.
	bsf	hc165_SHLD		;74HC165 Shift moduna alınıyor. 
					;(Veri transferi için.)
	bsf	RCSTA,SREN		;Tek byte veri oku.
hc165_j1
	btfsc	RCSTA, SREN		;Reset ise veri okumuş demektir, 
					;bir komut atla.
	goto	hc165_j1		;Bir geriye git. Tekrar kontrol et. 
					;(goto $-1 ;kullanılabilir) 	
					;Alma işlemi tamamlandığında SREN 
					;reset olur.
	movf	RCREG, W		;Okunan değer W'ye alınıyor
	movwf	hc165_data		;ve hc165_data değişkenine transfer 
					;ediliyor.
	return 

; Ana program USART modülü senkron master modu kullanarak
; 74HC165’ten işlemciye veri transferini gösteriyor.

Ana_program
	banksel TRISB		;TRISB ve TRISC'nin bulunduğu bank seçildi
	bsf	TRISB,0		;RB0 girişe yönlendirildi.
	movlw	0x80		;W = 0x80
	movwf	TRISC		;RC7/RX/DT pini giriş diğerleri çıkış.	
	clrf	TRISD		
				;PORTD sonuçları görüntülemek için çıkışa 
				;yönlendirildi.
	bcf	STATUS, RP0	;BANK0'a geç.
	clrf	PORTC		;PORTC'nin ilk durumda tüm pinleri LOW.	
	clrf	PORTD
call	hc165_Ilk_islemler	;74HC165 için USART modülü Senkron 
				;Master moda alındı.
Ana_j1
	btfsc	OKU_BUTONU	;Oku butonuna basıldı mı? Evet ise 
				;bir komut atla.
	goto	Ana_j1		;Bir komut geriye, kontrole devam.
	call	hc165_Veri_Oku	;74HC165 kaydedicisinden veri oku
	movf	hc165_data, W	;Okunan veriyi W'ye yükle.
	movwf	PORTD		;Anahtar konumlarını PORTD'de 
				;görüntüle.
	goto	Ana_j1		;İşlemi sürekli yap.

	END

PIC16F877 C dili ile hazırlanan proje listesi ve örnekler

GrafikLCD.c: T6963C tabanlı Grafik LCD’ye text yazar ve çizgi çizer.
15_1.c: Terminal Projesi
14_13.c: MPX4115 basınç sensörü uygulaması
14_12.c: MT8870 ile DTMF ton kod çözücü uygulaması
14_11_2.c: RF alıcı modülü programı
14_11_1.c: RF verici modülü programı
14_10.c: Rotary pulse encoder ile ses üretme
14_9.c: Rotary pulse encoder uygulaması
14_8.c: DS1868 dijital potansiyometre uygulaması
14_7.c: DS1990(i-button) uygulaması
14_6.c: PCF8583 ile saat uygulaması
14_5.c: DS1307 RTC
14_4.c: DS1302 RTC
14_3.c: DS18B20 ısı sensörü ile ısı ölçümü
14_2.c: DS1621 ısı sensörü ile ısı ölçümü
14_1.c: DS1620 ısı sensörü ile ısı ölçümü
13_3.c: L297 ve L298 ile step motor kontrolü
13_3.c: L297 ve L298 ile step motor kontrolü
13_2.c: Step motor kontrolü (ULN2003 ile)
13_1.c: DC motor hız ve yön kontrolü


// Dosya Adı		: 15_1.c
// Açıklama		: Terminal Projesi
// PIC DK 2.1		: PORTB Çıkış ==> LCD display
//			: A/D seçim anahtarı RA1 A, diğerleri D konumunda
//			: XT ==> 4 MHz

// Hi ve Lo fonksiyonları için başlık dosyası programa katılıyor.
#include "built_in.h"
// Alarm fonksiyonu ile ilgili tanımlamalar yapılıyor.
#define ALARMPORT        PORTE
#define ALARMTRIS        TRISE
#define ALARMCIKIS       F0
#define ALARMKURULU      F1
#define ALARMKAPAT       PORTA.F4  // Alarm kesme butonu
// Sensörler için analog kanal tanımlamaları yapılıyor.
#define LM35            0    // 0. adc kanalına bağlı
#define LDR             1    // 1. adc kanalına bağlı
// Global değişken tanımlamaları yapılıyor.
unsigned short tmp,i;
unsigned char ControlReg, TaskControl, RxBuffer;
unsigned char saat, dakika, saniye, a_saat, a_dakika, AlarmCnt;
unsigned int isi, isik, epadres, adr;
unsigned short PWMDuty;

// Kesme Alt Programı.

void interrupt(void)
{
    // Timer1 kesmesi işleniyor.
    if (PIR1.TMR1IF)
    {
         TaskControl.F3 = 1;
         TMR1L = 0x00;    // Ön değerler atanıyor 4096 artış sonrası
         TMR1H = 0xF0;    // taşma gerçekleşecek
         PIR1.TMR1IF = 0;
    }
    // RX seri iletişim veri alma kesmesi işleniyor.
    if (PIR1.RCIF)
    {
        // alınan karakter RCREG'de
        if(RCSTA.FERR || RCSTA.OERR)
        {
            RCSTA.CREN = 0;
            asm nop       // Bit işlemleri arasında 1us kadar bekle
            RCSTA.CREN = 1;
        }
        PIR1.RCIF = 0;     	// Alma kesme bayrağını sil.
        RxBuffer = RCREG;       	// Alınan veriyi değişkene ata.
        ControlReg.F7 = 1;      	// Veri alındı kontrol bitini set et
	TaskControl.F0 = 1;      	// Terminal için görev kontrol 
     	// bayrağını set et.
	PIR1.RCIF = 0;
    }
}

// EEPROM’a veri yazar.

void e2eprom_write(unsigned int adr, unsigned short data)
{
  I2C_Start();           // I2C start sinyali gönder
  I2C_Wr(0xA0);          // I2C donanım adresi + yazma komutu gönder
  I2C_Wr(Hi(adr));       // Yazılacak adresin yüksek byte'ını gönder
  I2C_Wr(Lo(adr));       // Yazılacak adresin alçak byte'ını gönder
  I2C_Wr(data);          // Yazılacak veriyi gönder
  I2C_Stop();            // I2C iletişimi durdur
  Delay_ms(100);         // işlemlerin tamamlanması için 100ms bekle
}

// EEPROM’dan veri okur.

unsigned short e2eprom_read(unsigned int adr)
{
  unsigned short data;
  I2C_Start();           // I2C start sinyali gönder
  I2C_Wr(0xA0);          // I2C donanım adresi + yazma komutu gönder
  I2C_Wr(Hi(adr));       // Yazılacak adresin yüksek byte'ını gönder
  I2C_Wr(Lo(adr));       // Yazılacak adresin alçak byte'ını gönder
  I2C_Repeated_Start();  // I2C reStart sinyali gönder
  I2C_Wr(0xA1);          // I2C donanım adresi + okuma komutu gönder
  data = I2C_Rd(0u);     // Veriyi oku (NO acknowledge)
  I2C_Stop();            // I2C iletişimi durdur
  return data;           // okunan veriyi fonksiyon dışına taşı
}

// USART birminden bir karakter alır.

char GetChar()
{
  while(!(ControlReg.F7));  // Seri porttan 1 karakter alınana kadar 
                            // bekle
  ControlReg.F7 = 0;        // Karakter alındı bayrağını sil
  return RxBuffer;          // Alınan karakteri çıkışa aktar
}

// USART'a bir karakter gönderir.

void sendChar(char c)
{
  if(!(TXSTA.TXEN)) TXSTA.TXEN = 1;  // Veri gönderme kesmesini 
                                     // etkinleştir.
  while(!(PIR1.TXIF));               // Veri gönderilene kadar bekle
  PIR1.TXIF = 0;                     // Veri gönderildi, bayrağı sil
  TXREG = c;
}

// USART'a string yazar.

void writeString(const char *s)
{
  char i=0;      // Gönderilecek stringin karakter sırası
  while( s[i]!=0 ) sendChar(s[i++]); 	// stringin sıradaki 
// karakterini gönder
}

// Karakteri hex değere dönüştürür.

unsigned short Char_to_Hex(unsigned short gec)
{
  ControlReg.F6 = 0;
  if (gec>47 && gec<58)
  {
     gec=gec-48;
     return gec;
  }
  else if (gec>64 && gec<71)   // A, B, C, D, E, F girişleri için
  {
     gec=gec-65;
     gec=gec+0x0A;
     return gec;
  }
  else if (gec>96 && gec<103)   // a, b, c, d, e, f girişleri için
  {
     gec=gec-97;
     gec=gec+0x0A;
     return gec;
  }
  // Hatalı karakter ControlReg 6. bit set et. Gerekirse bu bit 
  // kontrol edilerek hatalı girişler engellenebilir.
  ControlReg.F6 = 1;
  return 0;
}

// USART'dan hex bilgi alır ve USART'a gönderir.

unsigned short GetSendHexByte()
{
    unsigned short ch;
    ch = GetChar();
    sendChar(ch);
    tmp = Char_to_Hex(ch);
    asm swapf _tmp,F
    ch = GetChar();
    sendChar(ch);
    ch = Char_to_Hex(ch);
    if (ControlReg.F6) return 0xFF;  	// Hatalı karakter ise 0xFF 
// aktar
    tmp = tmp + ch;
    return tmp;
}

// USART'dan desimal bilgi alır ve USART'a gönderir.

unsigned short GetSendDecByte()
{
    return Bcd2Dec(GetSendHexByte());
}

// USART'a Desimal olarak 1 byte yazar

void sendDecByte(unsigned short data)
{
    unsigned short onlar, birler;
    onlar = 0;
    birler = 0;
    while( data>=10) { onlar++; data = data - 10; }
    birler = data;
    sendChar('0'+ onlar);
    sendChar('0'+ birler);
}

// LCD'ye Desimal olarak 1 byte yazar

void LCD_DecWrite(unsigned short data)
{
    unsigned short onlar, birler;
    onlar = 0;
    birler = 0;
    while( data>=10) { onlar++; data = data - 10; }
    birler = data;
    Lcd_Chr_Cp('0'+ onlar);
    Lcd_Chr_Cp('0'+ birler);
}

// LM35 ISI sensörü ile ilgili fonksiyonlar

void IsiOlc()
{
    // LM35'in bağlı olduğu ADC kanalından ısı şiddetini al ve 
    // dönüştür
    Isi = Adc_Read(LM35) >> 1;   
    // 2'ye bölerek gerçek ısı değerini bul yaklaşık her bir artış 
    // değeri 5 mV, 2 arttığında 10 mV yani 1 derece, Bu nedenle 
    // 2'ye bölüyoruz. Sonuç gerçek ısı değerine çok yakın. 
    // İstenirse yarım derece hassasiyet ile ısı görüntülenebilir. 
    // Ayrıca referans gerilim ayarlanarak daha hassas ve daha doğru 
    // ısı ölçümleri gerçekleştirilebilir.
}
void IsiGoruntule()
{
    // Isı şiddetini PC terminalinde görüntüle
    sendDecByte(Isi);sendChar(' ');sendChar('C');
}

// LDR IŞIK sensörü ile ilgili fonksiyonlar

void IsikOlc()
{
    // LDR'nin bağlı olduğu ADC kanalından ışık şiddetinin en 
    // değersiz byte'ını al
    Isik = Adc_Read(LDR);
}

void IsikGoruntule()
{
    // Işık şiddetini PC terminalinde görüntüle
    sendDecByte(Isik);
}

// Zaman ile ilgili fonksiyonlar

void ZamanAyarla()
{
    saat = GetSendDecByte(); sendChar(':'); dakika = GetSendDecByte();
}

void ZamanGoruntule()
{
    // Saati PC terminalinde görüntüle
    SendDecByte(saat); sendChar(':'); SendDecByte(Dakika);
}

// Alarm ile ilgili fonksiyonlar

void AlarmAyarla()
{
    // Alarm saat ve dakika bilgisini al ve eeproma kaydet
    a_saat = GetSendDecByte(); sendChar(':'); a_dakika = GetSendDecByte();
    Eeprom_Write(0x10, a_saat);
    Eeprom_Write(0x11, a_dakika);
}

void AlarmGoruntule()
{
    // Alarmı eepromdan oku ve PC terminalinde görüntüle
    a_saat = Eeprom_Read(0x10); a_dakika = Eeprom_Read(0x11);
    sendDecByte(a_saat); sendChar(':'); sendDecByte(a_dakika);
}

// Saat ile ilgili fonksiyonlar

void ZamanIsle()
{
    saniye++;
    if(saniye>59)
    {
        saniye = 0;
        dakika++;
        if(dakika>59)
        {
            dakika = 0;
            saat++;
            if(saat>23) saat = 0;
            // Her saat başı saat bilgisi ve ısı bilgisi e2eproma 
            // kaydediliyor.
            IsiOlc();
            e2eprom_write(epadres, saat);
            epadres++;
            e2eprom_write(epadres, Isi);
            epadres++;
        }
        // 40 dk boyunca alarm susturulmadı ise alarmı kes
        if (ControlReg.ALARMCIKIS)
        { AlarmCnt++;
          if (AlarmCnt>=40)
          {
             ControlReg.ALARMCIKIS = 0;
             ControlReg.ALARMKURULU = 0;
             ALARMPORT.ALARMCIKIS = 0;
             AlarmCnt = 0;
          }
        }
    }
    // Alarm kurulu ise alarm zamanını kontrol et
    if (ControlReg.ALARMKURULU)
         if ((saat == a_saat) && (dakika == a_dakika))
         {
             ALARMPORT.ALARMCIKIS = 1;
             ControlReg.ALARMCIKIS = 1;
         }
    // LCD'de saat:dakika:saniye bilgilerini görüntüle
    Lcd_Out(1,1, "");
    LCD_DecWrite(saat);Lcd_Chr_Cp(':');
    LCD_DecWrite(dakika);Lcd_Chr_Cp(':');
    LCD_DecWrite(saniye);
    // LCD'de ısı bilgisini görüntüle
    IsiOlc();
    Lcd_Out(2,1, "ISI: ");
    LCD_DecWrite(Isi);
    Lcd_Chr_Cp('C');
}

// PC ile iletişim kuran terminal fonksiyonu

void TerminalProgram()
{
    unsigned short ch,tmp,i;
    ch=GetChar();
    if (ch==13)
    while(ch!=48)
    {
           do {
                // PC Terminalinde menü yazdırılıyor.
             writeString("\r\n\r\n        DK 2.1 Iletisim Menusune Hosgeldiniz");
             writeString("\r\n Copyright © Ayhan DAYANIK - 2006 [email protected]");
             	writeString("\r\n\r\n   MENU SECENEKLERI:\n\r");
             	writeString(" <1> Isi goster..\n\r");
             writeString(" <2> Isik siddeti goster..\n\r");
             writeString(" <3> Saati goster..\n\r");
             writeString(" <4> Alarmi goster..\n\r");
             writeString(" <5> e2eprom'dan saat-isi bilgilerini listele..\n\r");
             writeString(" <6> Saati ayarla..\n\r");
             writeString(" <7> Alarmi kur..\n\r");
             writeString(" <8> PWM darbe genisligi ayarla..\n\r");
             writeString(" <0> Cikis..\n\r\n\r");
             writeString("     SECIMINIZ: ");
             ch=GetChar();     // PC terminalinden karakter al
	   } while(ch<48 || ch>57);  	// Alınan seçim 0-8 arasında 
// değilse tekrar giriş al
            // Alınan seçim bilgisini PC terminaline yaz
            sendDecByte(ch-48);writeString("\n\r ");
            // Alınan karakteri kontrol et ve görevi yerine getir.
	    switch(ch)
	    {
           	// Alınan karakter '0' ise ch = 0 olduğundan while 
	// döngüsünden dolayısı ile Terminal Program'dan 
	// çıkılır.
                case 48:writeString("\n\r Menuye girmek icin ENTER'e basiniz.. \n\r");
                      break;
                // Isı değerini ölç ve PC terminalinde göster
	         case 49:writeString("\n\r Isi degeri: ");
                      IsiOlc();
                      sendDecByte(Isi);sendChar(' ');sendChar('C');
		        break;

// Işık şiddetini ölç ve PC terminalinde göster, Burada ışık şiddeti 
// işlenmemiş bir şekilde görüntülendi. Işık şiddetini doğru olarak 
// görüntülemek için okunan değerin logaritmik olarak işlenmesi 
// gerekmektedir. Projemizde ışık şiddeti ısı kadar önemli 
// olmadığından ve programın anlaşılırlığını korumak için dönüşüm 
// yapılmamıştır. İstenirse okunan belirli değerlerde ışık şiddeti 
// hesaplama yöntemi yerine bilgisayar ortamında hesaplanmış bir 
// tablo kullanmak daha yerinde olacaktır.
		case 50:writeString("\n\r Isik siddeti: ");
                        Isik = Adc_Read(LDR);
                        sendDecByte(Isik);
			break;

                // PC terminalinde saat:dakika formatında zaman 
                // görüntülenir.
              case 51:writeString("\n\r Saat: ");
		        SendDecByte(saat); sendChar(':'); SendDecByte(Dakika);
		        break;

                // PC terminalinde alarm kurulu ise alarm zamanını, 
                // kurulu değil ise alarmın kurulu olmadığına dair 
                // mesaj görüntüler.
	case 52:if(ControlReg.ALARMKURULU)
         {
           a_saat = Eeprom_Read(0x10); a_dakika = Eeprom_Read(0x11);
           writeString("\n\r Alarm zamani: ");
           sendDecByte(a_saat); sendChar(':'); sendDecByte(a_dakika);
           } else writeString("\n\r Alarm kurulmamis..");
           break;

           // PC terminalinde ESC tuşuna basana kadar ya da eeprom 
           // sonuna yakın bir değere ulaşana kadar 10'ar 10'ar 
           // belirli zamanlarda ölçülmüş ısı değerini görüntüle
		case 53:adr = 0; tmp = 1;
                        do {
                            writeString("\n\r Saat - Isi \n\r");
                            writeString("\n\r ----------- \n\r");
                            for ( i=0;i<10;i++)
                            {
                                writeString("  ");
                                ch = e2eprom_read(adr);
                                if (ch > 23) {tmp = 0; ch = 27; break;}
                                sendDecByte(ch);
                                writeString(" --- ");
                                adr++;
                                ch = e2eprom_read(adr);
                                sendDecByte(ch);
                                writeString("\n\r");
                                adr++;
                            }
                           if (tmp)
                           {
                                writeString("\n\r Cikis icin ESC tusuna basiniz..\n\r");
                                ch = GetChar();
                           } else
                           { if (adr < 0xFF0) ch = 0; else ch = 27; }
                        } while (ch!=27);
                        break;
                        
     // PC terminalinden saat:dakika girişini alarak zamanı ayarlar
     case 54:writeString("\n\r Saat ve dakika giriniz ( HH:MM ): ");
	             saat = GetSendDecByte(); sendChar(':'); dakika = GetSendDecByte();
                    break;

     // PC terminalinden alarma ait saat:dakika girişini alarak 
     // alarm zamanını ayarlar
     case 55:writeString("\n\r Alarm zamanini giriniz ( HH:MM ): ");
               a_saat = GetSendDecByte(); sendChar(':'); a_dakika = GetSendDecByte();
              Eeprom_Write(0x10, a_saat); Eeprom_Write(0x11, a_dakika);
              ControlReg.ALARMKURULU = 1; // Alarm etkinleştirildi
              break;

       // PC terminalinden PWM darbe genişliğini alarak darbe 
       // genişliğini ayarlar
	case 56:writeString("\n\r PWM darbe genisligini giriniz (00-FF): ");
              PWMDuty = GetSendHexByte();
              PWM_Stop();
              PWM_Init(1000);      // PWM frekansı 1KHz seçildi
              PWM_Change_Duty(PWMDuty);
              PWM_Start();
              break;
	      }
     }
}

// Kullanılan birimlerin kullanıma hazır getirildiği ve bazı 
// değişkenlere ilk değer atamalarının yapıldığı alt program

void main_init()
{
    TRISC.F1 = 1;               // Timer1 için RC1 giriş yapıldı
    ALARMTRIS.ALARMCIKIS = 0;   // Çıkışa yönlendirildi
    ALARMPORT.ALARMCIKIS = 0;   // İlk anda alarm çalmıyor


    //Port yönlendir TX çıkış, RX giriş
    TRISC.F6 = 0;       // TX ucu çıkış yapıldı
    TRISC.F7 = 1;       // RX ucu girişe ayarlandı
    TXSTA = 0;          // TXSTA ilk anda sıfır
    RCSTA = 0;          // RCSTA ilk anda sıfır
// SPBRG = 129;	    // 20 Mhz de 9600 baud hız için
    SPBRG = 25;	    // 4 Mhz de 9600 baud hız için
// SPBRG = 50;          // 8 Mhz de 9600 baud hız için
    TXSTA = 0x26;
    RCSTA = 0x90;
    PIE1.RCIE = 1;
    // Saat ile ilgili ilk değerler atanıyor.
    saat = 0;
    dakika = 0;
    saniye = 0;
    AlarmCnt = 0;
    // LCD kullanıma hazırlanıyor.
    Lcd_Config(&PORTB,4,5,7,3,2,1,0);  // LCD bağlantı tanımlamaları
    Lcd_Cmd(LCD_CLEAR);                // LCD'yi sil
    Lcd_Cmd(LCD_CURSOR_OFF);           // İmleci gizle

    I2C_Init(100000);             // I2C iletişimi 100 KHz
    epadres = 0;                  // eprom adresi sıfırlandı
    a_saat = Eeprom_Read(0x10);   // Alarm saatini oku
    a_dakika = Eeprom_Read(0x11); // Alarm dakikasını oku

    T1CON.TMR1ON = 0;           // ilk anda timer1 kapalı
    TMR1L = 0x00;               // Ön değerler atanıyor 4096 artış 
      // sonrası 32.768 kHz kristal için
    TMR1H = 0xF0;               // taşma gerçekleşecek
    T1CON = 0x3A;               // 1:8 prescaler, senkronizeli ext. 
      // clock,
    PIE1.TMR1IE = 1;
    T1CON.TMR1ON = 1;           // zamanlayıcı çalıştırıldı

    PWM_Init(1000);             // PWM frekansı 1KHz seçildi
    PWM_Change_Duty(0x80);      // Duty cycle %50 seçildi
    PWM_Start();

    ADCON1 = 0x84;              // RA0, RA1, RA3 analog, diğerleri 
      // dijital, sonuç sağa dayalı
    TRISA.F4 = 1;               // Alarm susturma butonu için giriş 
      // yapıldı
    ControlReg = 0;             // Kontrol kaydedicisini sil
    TaskControl = 0;            // Görev kontrol kaydedicisini sil
    INTCON.PEIE = 1;            // Çevresel kesmeleri etkinleştir.
    INTCON.GIE = 1;             // Etkinleştirilen kesmelere izin ver
}

// ANA PROGRAM

void main()
{
     main_init();             // İlk işlemler alt programını çağır
     while(1)
     {
// Aşağıda görevler yer almaktadır. Kesme içerisinde set olan 
// görev bayrakları burada sırası ile işlenirler. Öncelik 
// sıralaması görevin önceliğine göre tespit edilmelidir.
         
         // Seri iletişim görevi, Veri alındı ve işlenmesi gerekiyor
         if (TaskControl.F0)
         {
             TerminalProgram();	// Seri iletişim menüsünü PC'de 
// göster ve menü işlemlerini yap
             TaskControl.F0 = 0; // Yeni görev için silinmelidir.
         }
         
         // LM35 ısı sensöründen ısı okuma zamanı geldi
         if (TaskControl.F1)
         {
             IsiOlc();           // Isı şiddeti ölç
             TaskControl.F1 = 0; // Yeni görev için silinmelidir.
         }

         // LDR ışık sensöründen ışık şiddeti okuma zamanı
         if (TaskControl.F2)
         {
             IsikOlc();          // Işık şiddeti ölç
             TaskControl.F2 = 0; // Yeni görev için silinmelidir.
         }
         
         // 1 sn geçti. Zamanı işle, alarm zamanını kontrol et
         if (TaskControl.F3)
         {
             ZamanIsle();        // Saati işle
             TaskControl.F3 = 0; // Yeni görev için silinmelidir.
         }

         // Alarm susturma ve iptal butonuna basıldı mı?
         if (!ALARMKAPAT)
         {
            ControlReg.ALARMCIKIS = 0; // Alarm çalma bayrağını sil.
            ControlReg.ALARMKURULU = 0;// Alarm kurulu bayrağını sil
            ALARMPORT.ALARMCIKIS = 0;    // Alarmı sustur
            AlarmCnt = 0;       // Alarm süresi kaydedicisini sil
         }
         
         // Bu bölüme varsa diğer görevler eklenebilir
     }
}

// Dosya Adı		: 14_13.c
// Açıklama		: MPX4115 basınç sensörü uygulaması
// Notlar		: XT ==> 4 MHz


// MPX4115 Basınç sensörünün mikrodenetleyiciye bağlantıları 
// tanımlanıyor.

#define mpx4115         PORTA
#define mpx4115_tris    TRISA
#define mpx4115_pin     2

// Değişken tanımlamaları yapılıyor.

unsigned int mpx4115_data, ondalik;
char *str="   .  kP\0";

// Bir byte'lık hexadesimal sayıyı 2 basamaklı desimal sayıya 
// dönüştürür.

char Hex2Dec(char ch)                    // 2 digit dönüşüm
{
     char tmp = 0;                       // Geçici değişkeni sıfırla
// sayının onlar basamağı bulunuyor
     while(ch>=10) {tmp++; ch -= 10;}    
     tmp = (tmp<<4) + ch;       	// Birler basamağını sayıya ekle
     return tmp;         		// Sonucu fonksiyon dışına taşı
}

// hexadesimal değeri LCD'de görüntülemek için text'e dönüştürür.

void BintoStr(unsigned short tam, unsigned short ondalik)
{
// tam kısım 200 ve üzerinde ise str'nin ilk karakteri 2, değilse 
// 100 ve üzerinde olduğu kontrol edilir. 100 ve üzerinde ise 
// str'nin ilk karakteri 1. Eğer tam kısım 100'den küçükse str'nin 
// ilk karakteri boşluk. Tam kısmın 100 ve üzerindeki değeri tam'dan 
// düşülür.
    if(tam >= 200) {str[0] = 50; tam -= 200; }
       else if (tam >= 100) { str[0] = 49; tam -= 100; } else str[0] = 32;
// tam kısım artık 100'den küçüktür. 2 basamak desimal dönüşüme 
// uygundur.
    tam = Hex2Dec(tam);       // Kalan tam kısmı desimale dönüştür.
    str[1]= 48 + ((tam & 0xF0) >> 4);  // Onlar basamağını elde et
// Eğer yüzler ve onlar basamağının her ikiside sıfır ise str'de 
// onlar basamağına yani str'nin 2. karakterine boşluk yaz
    if ((str[0] == 32) && (str[1] == 48)) str[1] = 32;
// en değersiz dört bit text'e dönüştürülüyor
    str[2]= 48 + (tam & 0x0F); 
// ondalık kısmı str'nin 5. karakterine yazılıyor
    str[4]= 48 + ondalik;              
}

// Portları ve LCD birimini kullanıma hazırlar.

void init()
{
// Analog girişler seçildi, Vref+ = Vdd, Vref- = Vss seçildi.
    ADCON1 = 0x80;  
    TRISA  = 0xFF;
    LCD_Config(&PORTB,4,5,7,3,2,1,0); 
    LCD_Cmd(LCD_CURSOR_OFF);            
    delay_ms(500);                      
}

// MPX4115 basınç sensöründen analog basınç bilgisi elde edilir. Bu 
// bilgi MPX4115'in bağlandığı analog pinden 10 bit çözünürlüğünde 
// sayısal bilgiye dönüştürülür. Elde edilen bilgi işlenerek basınç 
// değeri tam ve ondalıklı kısmı elde edilir ve fonksiyon dışına 
// taşınır.

unsigned short mpx4115_read()
{
// tam kısmı tutacak değişken tanımlanıyor.
    unsigned short tmp;      
    unsigned i, hata;      // döngü ve hata değişkeni tanımlanıyor.
// Basınç değeri sayısal değere dönüştüülüyor
    mpx4115_data = Adc_Read(mpx4115_pin); 
// 15 kP'lık ilk değer çıkartılıyor.
    mpx4115_data -= 56;                   
    hata = 0;                 // hata payı ilk durumda sıfır.
// Hata oranı tespit ediliyor.
    for(i = 9; i <= mpx4115_data ; i +=15) hata++; 
    mpx4115_data += hata;                 // Hata payı ekleniyor
// tam kısım elde ediliyor ve 15 kP'lık ilk değer ekleniyor.
    tmp = mpx4115_data/10 + 15; 
    ondalik = mpx4115_data%10;     // ondalıklı kısım elde ediliyor.
    return tmp;             // tam kısım fonksiyon dışına taşınıyor.
}

// Ana program MPX4115 basınç sensöründen analog basınç bilgisini 
// alarak sayısal değere dönüştürüp işleyerek basınç değerini %1 
// hata payı ile hesaplar. Sonucu LCD display'de 500 ms ara ile 
// görüntüler.

void main()
{
// 1 byte işaretsiz geçici değişken tanımlanıyor.
    unsigned short tmp; 
// Portlar ve LCD kullanıma hazırlanıyor.         
    init();                      
    do        // do - while döngüsü ile sonsuz çevrim başlıyor.
    {
// MPX4115'ten basınç değerinin sayısal karşılığının tam kısmı ve 
// ondalıklı kısmı elde ediliyor.
         tmp = mpx4115_read();
// Tam ve ondalıklı kısım str dizisine aktarılıyor.
         BintoStr(tmp, ondalik);
         Lcd_Out(1,1, "Basinc= ");
// str dizisi LCD'de görüntüleniyor.
         Lcd_Out_Cp(str);
         Delay_ms(500);
    } while(1);                  // Ana program çevrimine devam et
}

// Dosya Adı		: 14_11_2.c
// Açıklama		: RF alıcı modülü programı
// Notlar		: XT ==> 4 MHz


// Sabit tanımlamalar yapılıyor.


// Anlamlı bir karakter olması önemli değil. Sonuçta sadece kontrol 
// içi kullanılacak LCD ya da terminalde yazdırılmayacak. Ancak 
// RF verici modülündeki kodlar ile aynı olmak zorunda.
#define ST1               0xA9    
#define ST2               0xAE    

// Genel değişken tanımlamaları yapılıyor

unsigned short i, Data[3];
unsigned char ControlReg, RxBuffer;
char txt[]="                \0";
char ch;

// RF_read fonksiyonu RF modülünden 1 byte veri alır

unsigned short RF_read()
{
// Yerel geçici değişkenler tanımlanıyor.
    unsigned short tmp, i;  
    i = 0;                  // Karakter sayacı sıfırlanıyor.
    do
    {
        if (Usart_Data_Ready())
        {   					// Eğer veri alındı ise
            tmp = Usart_Read();    	// Alınan veriyi oku
            switch(i)
            {
// 0. karakter alındı ise ve alınan karakter ST1 kontrol karakterine 
// eşitse Data[0]'a kaydet ve i sayacını artır.
                 case 0: if (tmp == ST1) {Data[0] = tmp; i++;} break;
// 1. karakter alındı ise ve alınan karakter ST2 kontrol karakterine 
// eşitse Data[1]'e kaydet ve i sayacını artır. Aksi halde i alınan 
// karakter sayacını sıfırla. Çünkü kontrol karakterleri hatalı, 
// dolayısıyle veri alımı hatalı olduğundan başa dön ve yeniden 
// almaya başla
                 case 1: if (tmp == ST2) {Data[1] = tmp; i++;} else i = 0; break;
// İlk 2 karakter doğru alındı ise 3. karakterde doğru gelecektir. 
// 3. karakter bizim gerçek verimizdir. İstenirse verilerin daha 
// hatasız ulaşması için kontrol karakter sayısı artırılabilir.
                 case 2: Data[2] = tmp; i++; break;
                 default: break;
            }
        }
        PORTD = tmp;
// 3 karakterde alındı ise do-while döngüsünden çık
    } while (i<3); 
    return tmp;    // Son alınan veriyi fonksiyon dışına taşı
}



// LCD ve Usart birimlerini kullanıma hazırlar

void init()
{
    Usart_Init(2400);
    LCD_Config(&PORTB,4,5,7,3,2,1,0);    
    LCD_Cmd(LCD_CURSOR_OFF);
}

// Ana program RF modülünden aldığı verileri LCD'de görüntüler

void main()
{
    init();          // LCD ve Usart birimlerini kullanıma hazırla
    do
    {
        i = 0;
        Lcd_Cmd(LCD_FIRST_ROW);
        do
        {
// RF modülünden alınan karakteri LCD'ye yaz
            ch = RF_read();
            Lcd_Chr_Cp(ch);
            i++;                // karakter sayacını artır
        } while (i<16);
    } while(1);   		// Okuma ve görüntüleme işlemine devam
}

// Dosya Adı		: 14_10.c
// Açıklama		: Rotary pulse encoder ile ses üretme
// Notlar		: Proteus programı simülasyonu
//			: XT ==> 4 MHz


// Rotary Encoder'in mikrodenetleyiciye bağlantısı tanımlanıyor.

#define RotaryEncoder           PORTE
#define RotaryEncoder_tris      TRISE

// Rotary Encoder'in mikrodenetleyiciye bağlantısı tanımlanıyor.

#define Buzzer                  PORTC
#define Buzzer_pin              1

// Global değişken tanımlamaları yapılıyor.

char Encoder, oldEncoder;
unsigned tmp, sayac;
char txt[5];


// Portları ve LCD'yi kullanıma hazırlar, değişkenlere ilk değer 
// atamaları yapar.

void init()
{
   LCD_Config(&PORTB,4,5,7,3,2,1,0);    
   LCD_Cmd(LCD_CURSOR_OFF);
// Buzzer'ın bulunduğu port ses çıkışı için hazırlandı    
   Sound_Init(&Buzzer, Buzzer_pin);     
   
   ADCON1 = 0x06;              // Analog girişleri kapat.
   RotaryEncoder = 0;          // Portun ilk durumu sıfırlanıyor.
   RotaryEncoder = 0x03;       // Rotary Encoder portu giriş yapıldı

// Rotary encoder'in değerini tutan değişkene ilk değer veriliyor.
   Encoder = 0x03;
   sayac = 0;                  // sayac değeri sıfırlanıyor.
   Lcd_Out(1,1,"Sayac:");
}

// Ana program Rotary encoder'den gelen bilgiyi değerlendirerek sağa 
// ya da sola doğru çevrildiğini belirler ve rotary encoder sağa 
// çevrilmiş ise sayac değerini 1 artırır, sola çevrildi ise sayacı 
// 1 azaltır ve sayac değerini LCD'de görüntüler ve sayac değerinin 
// 10 katı frekansta ses üzetir. Aynı zamanda herhangi bir 
// değişiklik yoksa değişim olana kadar rotary encoder'den gelen 
// bilgiyi bir önceki bilgi ile kıyaslamaya devam eder.

void main()
{
     init();
     do
     {
// yeni değer eski değere yükleniyor
          oldEncoder = Encoder; 
// 2 byte'lık sayac desimale dönüştürülüyor      
          tmp = Bcd2Dec16(sayac); 
// desimale dönüştürülün değer text'e çevriliyor.    
          WordToStr(tmp, txt);        
          Lcd_Out(1,1,"Sayac:");     
          Lcd_Out(2,4,txt);
// Rotary encoder'in eski değeri ile yeni değerini karşılaştır. 
// Birbirinden farklı olana kadar (rotay encoder çevrilene kadar) 
// karşılaştırmaya ve sayac frekansında ses üretmeye devam et.
          while(Encoder == oldEncoder)
          {
// Rotary encoder'in değeri okunuyor
               Encoder = RotaryEncoder & 0x03; 
// sayac*10 frekansında, 150 peryotluk ses 
               Sound_Play(sayac, 50);   
          }
// eski değerin 1. biti yeni değerin 0. bitinden farklı ise ve eski 
// değerin 0. biti yeni değerin 1. bitine eşit ise rotary encoder 
// sağa doğru çevrilmiştir, bu durumda sayac 254'den küçükse artır.
          if(oldEncoder.F1 !=Encoder.F0)
          {
              if(oldEncoder.F0 == Encoder.F1) if(sayac<254) sayac++;
          } else
// eski değerin 0. biti yeni değerin 1. bitinden farklı ise ve eski 
// değerin 1. biti yeni değerin 0. bitine eşit ise rotary encoder 
// sola doğru çevrilmiştir, bu durumda sayac 0'dan büyükse azalt.
          if(oldEncoder.F0 != Encoder.F1)
          {
              if(oldEncoder.F1 == Encoder.F0) if(sayac>0) sayac--;
          }
     } while(1);               // Ana program çevrimine devam et
}

// Dosya Adı		: 14_9.c
// Açıklama		: Rotary pulse encoder uygulaması
// Notlar		: Proteus programı simülasyonu
//			: XT ==> 4 MHz


// Rotary Encoder'in mikrodenetleyiciye bağlantısı tanımlanıyor.

#define RotaryEncoder           PORTE
#define RotaryEncoder_tris      TRISE

// Global değişken tanımlamaları yapılıyor.

char Encoder, oldEncoder;
unsigned tmp, sayac;
char txt[5];

// Portları ve LCD'yi kullanıma hazırlar, değişkenlere ilk değer 
// atamaları yapar.

void init()
{
   LCD_Config(&PORTB,4,5,7,3,2,1,0);  // LCD bağlantısı tanımlanıyor
   LCD_Cmd(LCD_CURSOR_OFF);           // imleci gizle
   ADCON1 = 0x06;                     // Analog girişleri kapat.
   RotaryEncoder = 0;          // Portun ilk durumu sıfırlanıyor.
   RotaryEncoder = 0x03;       // Rotary Encoder portu giriş yapıldı
// Rotary encoder'in değerini tutan değişkene ilk değer veriliyor.
   Encoder = 0x03;
   sayac = 0;                  // sayac değeri sıfırlanıyor.
   Lcd_Out(1,1,"Sayac:");
}

// Ana program Rotary encoder'den gelen bilgiyi değerlendirerek sağa 
// ya da sola doğru çevrildiğini belirler ve rotary encoder sağa 
// çevrilmiş ise sayac değerini artırır, sola çevrildi ise sayacı 
// azaltır ve sayac değerini LCD'de görüntüler. Herhangi bir 
// değişiklik yoksa değişim olana kadar rotary encoder'den gelen 
// bilgiyi bir önceki bilgi ile kıyaslamaya devam eder.

void main()
{
     init();
     do
     {
// yeni değer eski değere yükleniyor
          oldEncoder = Encoder; 
// 2 byte'lık sayac desimale dönüştürülüyor
          tmp = Bcd2Dec16(sayac); 
// desimale dönüştürülün değer text'e çevriliyor. 
          WordToStr(tmp, txt);        
          Lcd_Out(1,1,"Sayac:"); 
// sayac değeri LCD'de görüntüleniyor.
          Lcd_Out(2,4,txt); 
// Rotary encoder'in eski değeri ile yeni değerini karşılaştır. 
// Birbirinden farklı olana kadar (rotay encoder çevrilene kadar) 
// karşılaştırmaya devam et.
          while(Encoder == oldEncoder) Encoder = RotaryEncoder & 0x03;
          
// eski değerin 1. biti yeni değerin 0. bitinden farklı ise ve eski 
// değerin 0. biti yeni değerin 1. bitine eşit ise rotary encoder 
// sağa doğru çevrilmiştir, bu durumda sayac 9999'dan küçükse artır.
          if(oldEncoder.F1 !=Encoder.F0)
          {
              if(oldEncoder.F0 == Encoder.F1) if(sayac<9999) sayac++;
          } else
// eski değerin 0. biti yeni değerin 1. bitinden farklı ise ve eski 
// değerin 1. biti yeni değerin 0. bitine eşit ise rotary encoder 
// sola doğru çevrilmiştir, bu durumda sayac 0'dan büyükse azalt.
          if(oldEncoder.F0 != Encoder.F1)
          {
              if(oldEncoder.F1 == Encoder.F0 ) if(sayac>0) sayac--;
          }
     } while(1);               // Ana program çevrimine devam et
}

// Dosya Adı		: 14_2.c
// Açıklama		: DS1621 ısı sensörü ile ısı ölçümü
// Notlar		: Proteus programı simülasyonu
//			: XT ==> 4 MHz

// i2c adres tanımlanıyor
#define DS1621_WRITE_ADDR     0x90
#define DS1621_READ_ADDR      0x91
// Komutlar
#define DS1621_ACCESS_CONFIG_CMD      0xAC
#define DS1621_START_CONVERSION_CMD   0xEE
#define DS1621_STOP_CONVERSION_CMD    0x22
#define DS1621_READ_TEMPERATURE_CMD   0xAA
#define DS1621_ACCESS_TEMP_HIGH_CMD   0xA1
#define DS1621_ACCESS_TEMP_LOW_CMD    0xA2
#define DS1621_READ_COUNTER_CMD       0xA8
#define DS1621_READ_SLOPE_CMD         0xA9
// Config kaydedicisinin bit tanımlamaları
#define DS1621_ONE_SHOT_BIT           F0
#define DS1621_OUTPUT_POLARITY_BIT    F1
#define DS1621_NVRAM_BUSY_BIT         F4
#define DS1621_TEMP_LOW_BIT           F5
#define DS1621_TEMP_HIGH_BIT          F6
#define DS1621_CONVERSION_DONE_BIT    F7
// Config kaydedicisinin başlangıç değeri
#define DS1621_CONFIG_INIT_VALUE      0x00
// IsıKontrol kaydedicisinin bit tanımlamaları
#define ERROR                         F7
#define NEG                           F6
#define ONDABES                       F5
//Değişken tanımlamaları
char *str="  \0";
char IsiKontrol;

// DS1621 ilk işlemleri gerçekleştirir. Konfigürasyon kaydedicisine 
// ilk değer verir.

void ds1621_init(void)
{
     I2C_Start();
     I2C_Wr(DS1621_WRITE_ADDR);
     I2C_Wr(DS1621_ACCESS_CONFIG_CMD);
     I2C_Wr(DS1621_CONFIG_INIT_VALUE);
     I2C_Stop();
}

//Isı okuma çevrimini başlatır.

void ds1621_start_conversion(void)
{
     I2C_Start();
     I2C_Wr(DS1621_WRITE_ADDR);
     I2C_Wr(DS1621_START_CONVERSION_CMD);
     I2C_Stop();
}

// Isı bilgisi DS1621'den okunur ve en değerli byte'ı fonksiyon 
// dışına taşınır.

char ds1621_read_temperature(void)
{
     char data_low, data_high;
     I2C_Start();                   // I2C iletişimi başlat
     I2C_Wr(DS1621_WRITE_ADDR);
     I2C_Wr(DS1621_READ_TEMPERATURE_CMD);
     I2C_Repeated_Start();
     I2C_Wr(DS1621_READ_ADDR);
// Isının en değerli byte'ı okunur ve ACK gönderilir
     data_high = I2C_Rd(1); 
// I2C hattı meşgul olduğu sürece bekle        
     while(I2C_Is_Idle() == 0);  
// Isının en değersiz byte'ı okunur ve NOT ACK gönderilir  
     data_low = I2C_Rd(0);          
// I2C hattı meşgul olduğu sürece bekle
     while(I2C_Is_Idle() == 0);     
     I2C_Stop();
// Isı Kontrol kaydedicisinin 0. biti set ise bir hata olduğu 
// anlaşılır.
     if(data_low == 0xFF)
          if(data_high == 0xFF) {IsiKontrol.ERROR = 1; return(0);}
     else IsiKontrol.ERROR = 0;
// Eğer ısı 0 derecenin altında ise data_high byte'ın en değerli 
// biti set olur. Bu durumda data_high değerinin 2.tamlayanı 
// alınarak ısı değeri elde edilir ve bu ısının negatif olduğunu 
// belirtmek için IsiKontrol kaydedicisinin NEGATIF bayrağı set 
// edilir.
     if(data_high & 0x80)
     {
// Isının negatif olduğu kontrol kaydedicisine yazılır
        IsiKontrol.NEG = 1;
// Isının en değerli byte'ının 2. tamlayanı alınır                 
        data_high = ~data_high + 1;          
        if(data_low) data_high--;  // 1/2 C kısmı var ise bir eksilt
     } else IsiKontrol.NEG = 0;    // ısı pozitif
// data_low büyük 0 ise 1/2 C değeri var, o halde IsiKontrol 
// kaydedicisinin ilgili bitini set et data_low = 0 ise 1/2 C değeri 
// yoktur. Bu durumda IsiKontrol kaydedicisinin ilgili biti silinir.
   if(data_low) IsiKontrol.ONDABES = 1; else IsiKontrol.ONDABES = 0;
// Isı değeri 99'dan büyükse 99 olarak kabul et
     if(data_high > 99) return 99;           
     return data_high;
}

// Eğim değerini fonksiyon dışına taşır.

char ds1621_read_slope(void)
{
     char slope;
     I2C_Start();
     I2C_Wr(DS1621_WRITE_ADDR);
     I2C_Wr(DS1621_READ_SLOPE_CMD);
     I2C_Repeated_Start();
     I2C_Wr(DS1621_READ_ADDR);
     slope = I2C_Rd(0);
     I2C_Stop();
     return slope;
}

// Sayac değerini fonksiyon dışına taşır.

char ds1621_read_counter(void)
{
     char counter;
     I2C_Start();
     I2C_Wr(DS1621_WRITE_ADDR);
     I2C_Wr(DS1621_READ_COUNTER_CMD);
     I2C_Repeated_Start();
     I2C_Wr(DS1621_READ_ADDR);
     counter = I2C_Rd(0);
     I2C_Stop();
     return counter;
}

// Bir byte'lık hexadesimal sayıyı 2 basamaklı desimal sayıya 
// dönüştürür.

char Hex2Dec(char ch)                    // 2 digit dönüşüm
{
     char tmp = 0;                       // Geçici değişkeni sıfırla
// sayının onlar basamağını bulur
     while(ch>=10) {tmp++; ch -= 10;}  
// Birler basamağını sayıya ekler  
     tmp = (tmp<<4) + ch;                
     return tmp;               // Sonucu fonksiyon dışına taşı
}

// Bir byte'lık sayıyı text'e dönüştürür.

void BintoStr(char data)
{
    data = Hex2Dec(data);                // Desimale dönüştür
// Text'e dönüştürür (ilk karakter)
    str[0] = 48 + ((data & 0xF0) >> 4); 
// sayının 10'lar basamağı sıfır ise boşluk yazar
    if (str[0] == 48) str[0] = 32;   
// Text'e dönüştürür (ikinci karakter)    
    str[1]= 48 + (data & 0x0F);          
}

// İlk işlemler alt programı LCD, I2C ve DS1621'i kullanıma hazırlar 
// ve ısı dönüşümünü başlatır.

void init()
{
    LCD_Config(&PORTB,4,5,7,3,2,1,0);   // LCD bağlantısını tanımla
    LCD_Cmd(LCD_CURSOR_OFF);            // imleci gizle
    I2C_Init(100000);    // I2C iletişimi hazırla, full master mode
    IsiKontrol = 0;  // Isı kontrol kaydedicisinin ilk değeri sıfır.
    ds1621_init();                      // Isı sensörünü başlat
    ds1621_start_conversion();          // Isı dönüşümünü başlat
}

// Ana program, ısı bilgisini DS1621'den okuyarak LCD üzerinde 
// görüntüler.

void main(void)
{
     char isi;
     init();    // ilk işlemleri gerçekleştir
     while(1)   // Bu blok içerisindeki işlemler sistem kapatılana
     {          // ya da resetlenene kadar tekrarlar.
         isi = ds1621_read_temperature();   // Isıyı ölç
         if(IsiKontrol.ERROR) continue;     // Hata var yeniden ölç
         LCD_Out(1,1,"Isi = ");             
// Negatif ısı ise - işareti yaz, değilse boşluk koy
         if(IsiKontrol.NEG) LCD_Out_Cp("-"); else LCD_Out_Cp(" "); 
         BintoStr(isi);       // Isıyı text'e dönüştür (2 dijit)
         LCD_Out_Cp(str);     // Isıyı yazdır
         if(IsiKontrol.ONDABES) LCD_Out_Cp(".5"); else LCD_Out_Cp(".0");             // ondalıklı kısmı yazdır
         Lcd_Chr_Cp(0xDF);    // derece işareti
         LCD_Out_Cp("C");     // C yazdır
         Delay_ms(1000);      // yeni ölçüm için 1 saniye bekle
     }
}

// Dosya Adı		: 13_3.c
// Açıklama		: L297 ve L298 ile step motor kontrolü 
// Notlar		: Proteus programı simülasyonu
//			: XT ==> 4 MHz

// Step motor bağlantı tanımlamaları.
#define stepMotor          PORTB   	// Step motor kontrol uçlarının 
// bağlandığı port.
#define stepMotorTris      TRISB   // Step motorun bağlı olduğu 
// portun yönlendirme kaydedicisi
#define enable             F0      // L297 step motor sürücüsünü 
// etkinleştiren pin tanımı.
#define reset              F1      // L297'nin reset ucunun bağlı 
// olduğu pin tanımı.
#define halffull           F2      // Bu pin 1 ise half modda,
// 0 ise full modda.
#define direction          F3      // Yön kontrol pini, 1 ise saat
// yönünde (ileri), 0 ise geri.
#define clock              F4      // L297 için saat darbesi üreten 
// pin tanımı.
#define home               F5      // Bu pin step motorun her tam 
// dönüşünde işlemciye saat 
// darbesi üretir.
#define control            F6      // Kontrol pini tanımı.

// Step motoru half moda alır (45 derecelik açılar ile dönüş modu).
void half_mode()
{
     stepMotor.halffull = 1;	//L297'yi yarım adım moduna alır.
}
// Step motoru full moda alır (90 derecelik açılar ile dönüş modu).
void full_mode()
{
     stepMotor.halffull = 0;	// L297'yi tam adım moduna alır.
}
// Step motoru istenilen adım kadar saat ibresi yönünde döndürür.
void ileri(unsigned int adim)
{
     stepMotor.reset = 1; 	// L297'yi resetle.
     stepMotor.enable = 1; 	// L297'yi etkinleştir.
     stepMotor.direction = 1; 	// Yön saat ibrelerinin yönünde
     do                       	// do - while döngüsü açılıyor.
     {
          stepMotor.clock = 1;	// Yükselen darbe kenarı.
          asm nop
          stepMotor.clock = 0; 	// İnen darbe kenarı ile L297 
	// tetikleniyor.
          delay_ms(50); 	// 50ms bekle.
     }while(--adim);
}
// Step motoru istenilen adım kadar saat ibresinin tersi yönünde 
// döndürür.
void geri(unsigned int adim)
{
     stepMotor.reset = 1;	// L297'yi resetle.
     stepMotor.enable = 1; 	// L297'yi etkinleştir.
     stepMotor.direction = 0;	// saat ibresinin tersi yönünde
     do                     	// do - while döngüsü açılıyor.
     {
          stepMotor.clock = 1; 	// Yükselen darbe kenarı.
          asm nop
          stepMotor.clock = 0;	// İnen darbe kenarı ile L297 
	// tetikleniyor.
          delay_ms(50);  	// Step motor yeni konumu alması 
	// için kısa bir süre bekle.
                            	// Bu süre step motorun tepki 
	// süresinden büyük olmalıdır.
                  	// Örneğimizde 50 ms seçilmiştir.
     }while(--adim);
}
// L297'yi resetler.
void resetle()
{
     stepMotor.reset = 0; 	// L297 resetlendi.
     stepMotor.enable = 0; 	// L297 pasif yapıldı.
     delay_ms(1000);
}
// Ana program ilk işlemler alt programı port yönlendirir.
void init()
{
     stepMotor = 0;       	// ilk çıkışlar sıfır.
     stepMotorTris.enable = 0;	// enable pini çıkış yapıldı.
     stepMotorTris.reset = 0;  	// enable pini çıkış yapıldı.
     stepMotorTris.halffull = 0; 	// half/full pini çıkış yapıldı.
     stepMotorTris.direction = 0; 	// direction pini çıkış yapıldı.
     stepMotorTris.clock = 0; 	// clock pini çıkış yapıldı.
     stepMotorTris.home = 1;  	// home pini giriş yapıldı.
     stepMotorTris.control = 0;  	// control pini çıkış yapıldı.
     resetle();           	// L297'yi resetle
}
// Ana program: Step motoru half ve full modlarda ileri ve geri 
// yönlerde aralarında 1 sn bekleyerek döndürür ve aynı işlemleri 
// sistem resetlenene ya da kapatılana kadar devam ettirir.
void main()
{
     init();                	// İlk işlemler yapılıyor.
     while(1)               	// Sonsuz döngü açılıyor.
     {                      	// while bloğu başlangıcı.
         half_mode();       	// Half modda çalıştırılacak.
         ileri(50);         	// 50 adım saat ibresi yönünde.
         delay_ms(1000);    	// 1 sn bekle.
         geri(100);         		// 100 adım saat ibresinin tersi 
		// yönünde dön.
         delay_ms(1000);
         full_mode();       	// Full modda çalıştırılacak.
         ileri(100);        	// 100 adım saat ibresi yönünde. 
         delay_ms(1000);
         geri(50);          	// 50 adım saat ibresinin tersi. 
         delay_ms(1000);
     }                      	// while bloğu sonu.
}

Satın almak isterseniz kitap detayları :http://www.altaskitap.com/PIC_877kitab%C4%B1.htm

aciklamali-pic16f877-uygulama-kodlari-cod-asm-c

Şifre-Pass: 320volt.com

Yayım tarihi: 2009/06/09 Etiketler: , , , ,



9 Yorum “Açıklamalı pic16f877 uygulama kodları cod asm c

  1. mertymerty

    emeğine sağlık usta.Benim bir projem var , 16f877 ile ilgili. içinde dac-adc konvertorler ve lcd ekran olacak. hangi butona basarsak lcd ekranda “su butona bastınız ” ve yanında da ” x v ” yazacak.yani hem hangi butona basıldığını hem de o butonun üzerındeki gerilimi ekrana yazdıracak. yardımcı olursanız sevinirim. herkese iyi günler

    CEVAPLA
  2. omeromer

    Paylaşımlarınız için çok teşekkürler , ancak benim elimde de pic16f877 var ve kodlarınızı indirdim ama ya çalışmıyor ya bozuk çalışıyor , neden olabilir yardımcı olursanız sevinirim.

    CEVAPLA
  3. emreemre

    14_6.c: PCF8583 ile saat uygulaması nı bulamadım yardımcı olurmusunuz

    CEVAPLA

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir