Merhaba arkadaşlar Assemble ile 4 Mhz frekansta çalışan bir PIC de 1 saniyelik gecikmeyi nasıl sağlayabiliriz.
Biraz düşündüm baktım ama öyle güzel de bi kaynak bulamadım. Orhan Altınbaşak gecikme algoritması vermiş bir tane ama ondada ne kadar süre olduğu yazmamış.
Bir de mesela 1 saniyelik gecikmeyi yapan bir betiği yazdık diyelim bunu 4-5-6 saniye gibi farklı süreler için nasıl kullanırız.
C ile PIC programlamaya başlamadan önce herşeyi adım adım mantığını kavrayarak öğrenmek istiyorum. O yüzden asm tercih ediyorum.
Yoksa delay_ms(1000) yazmak da hiç fena değil :) Umarım yanlış yolda gitmiyorumdur ;)
Teşekkürler şimdiden cevaplarınız için.
Kesme kullanmadan 1sn gecikme tam yapamak biraz zor. Alt program iç içe 2 döngü gerekirse 3 döngü düzenlenir. 1sn yakın ve 1sn küçük değerde hesaplama yapılır en sona eksik kalan zamanı nop komutları ekleyerek tamamlanır.
Daha öncede yayınlamıştım. bu işi yapan hazır programlar var.
http://www.piclist.com/techref/piclist/codegen/delay.htm?key=delay+ocde&from=%2Ftechref%2Fio%2Fserial%2FRCL1%2Ehtm
Selamlar
Arkadaşlar 1 saniye oluşturmak için kodları yazdım. Ayrıca 1'er saniye arayla PORTB'nin 0.ve 1 . pinie bağlı ledi sırayla yakan bir kod yazdım ama Proteusta hata verdi
;====1saniyeyle_yan_son===27.01.2008======
;==================================
LIST P=16F628A
INCLUDE "P16F628A.INC"
__CONFIG _INTRC_OSC_NOCLKOUT &_WDT_OFF &_PWRTE_ON &_MCLRE_ON &_BODEN_OFF &_LVP_OFF &_DATA_CP_OFF &_CP_OFF
;==================================
ORG h'00' ;Burdan yazmaya başla
TANIMLAMALAR ;Tanımlamalar diye etiket oluşturuluyor
CLRF PORTB ;PORT B'nin bütün uçlarını temizle
BANKSEL TRISA ;BANK1'e geç
MOVLW h'FF' ;Akü'ye FF koy
MOVWF TRISA ;Akü'nün içine TRISA'ya koy / A'nın bütün bitleri 1 yapıldı.-Giriş
CLRF TRISB ;B'nin bütün bitlerini 0 la- Çıkış yapıldı
BANKSEL PORTA ;BANK0'a geç
cblock
d1
d2
d3
endc
movlw 0x08
movwf d1
movlw 0x2F
movwf d2
movlw 0x03
movwf d3
SIFIRYAK ;PORTB'nin 0 numaralı pinine bağlı ledi yak
BSF PORTB,0
BCF PORTB,1
GOTO Delay_0
BIRYAK ;PORTB'nin 1. numaralı pinine bağlı ledi yak
BSF PORTB,1
BCF PORTB,0
GOTO Delay_0 ;
;=========1 saniye gecikme============
Delay_0
decfsz d1, f
goto $+2
decfsz d2, f
goto $+2
decfsz d3, f
goto Delay_0
;3 cycles
goto $+1
nop
BTFSC PORTB,0 ;PORTB'nın 0 numaralı bitine bak
GOTO BIRYAK ;HAYIR 0 değil Birinci Ledi Yak'a git
GOTO SIFIRYAK ;EVET 0 o zaman İkinci LED'i yaka git
END
Hata şu
http://img214.imageshack.us/img214/285/adsz2xh0.jpg
;====1saniyeyle_yan_son===27.01.2008======
;==================================
LIST P=16F628A
INCLUDE "P16F628A.INC"
__CONFIG _INTRC_OSC_NOCLKOUT &_WDT_OFF &_PWRTE_ON &_MCLRE_ON &_BODEN_OFF &_LVP_OFF &_DATA_CP_OFF &_CP_OFF
;==================================
ORG h'04' ;Burdan yazmaya başla
TANIMLAMALAR ;Tanımlamalar diye etiket oluşturuluyor
CLRF PORTB ;PORT B'nin bütün uçlarını temizle
BANKSEL TRISA ;BANK1'e geç
MOVLW h'FF' ;Akü'ye FF koy
MOVWF TRISA ;Akü'nün içine TRISA'ya koy / A'nın bütün bitleri 1 yapıldı.-Giriş
CLRF TRISB ;B'nin bütün bitlerini 0 la- Çıkış yapıldı
BANKSEL PORTA ;BANK0'a geç
CBLOCK 0x50
d1
d2
d3
ENDC
movlw 0x08
movwf d1
movlw 0x2F
movwf d2
movlw 0x03
movwf d3
SIFIRYAK ;PORTB'nin 0 numaralı pinine bağlı ledi yak
BSF PORTB,0
BCF PORTB,1
GOTO Delay_0
BIRYAK ;PORTB'nin 1. numaralı pinine bağlı ledi yak
BSF PORTB,1
BCF PORTB,0
GOTO Delay_0 ;
;=========1 saniye gecikme============
Delay_0
decfsz d1, f
goto $+2
decfsz d2, f
goto $+2
decfsz d3, f
goto Delay_0
;3 cycles
goto $+1
nop
movlw 0x08
movwf d1
movlw 0x2F
movwf d2
movlw 0x03
movwf d3
BTFSC PORTB,0 ;PORTB'nın 0 numaralı bitine bak
GOTO BIRYAK ;HAYIR 0 değil Birinci Ledi Yak'a git
GOTO SIFIRYAK ;EVET 0 o zaman İkinci LED'i yaka git
END
Merhaba,
Assembly'de registerler kullanarak uzun süreli delay yapmak iyi bir çözüm değildir mesela 1sn delay için işlemci 1sn boyunda aynı yerde dönüp durur ve 1sn boyunca başka hiçbirşey yapamaz. Bunun yerine timer kullan, timer'in overflag'i set oluncaya kadar denetlemek istediğin diğer işlemleri yaparsın.
16bit timer1'i 100ms'de bir timer1 overflow bit set olacak şekilde ayarladığımızı düşünelim(kullandığın xtal'e göre bu 100ms'yi değiştirebilirsin, 4Mhz için 500ms'ye çıkar, 20Mhz için 100ms). Bu 100ms'den daha uzun süreler için bir registerde kullanalım. Min süre : 100ms (register = 1 için) Max süre : 255x100ms=25,5sn'ye(reg:255) kadar delay sağlayabilirsin. Timer1 interrupt'ını kurarsan, 100ms'de bir interrupt'a gider ve registerini orada bir azaltırsın, ta ki 0 oluncaya kadar, böylelikle hiç bir işlemin uzun süreler boyunca aksamaz.
Kolay gelsin
Alıntı yapılan: "eemkutay"Merhaba,
Assembly'de registerler kullanarak uzun süreli delay yapmak iyi bir çözüm değildir mesela 1sn delay için işlemci 1sn boyunda aynı yerde dönüp durur ve 1sn boyunca başka hiçbirşey yapamaz. Bunun yerine timer kullan, timer'in overflag'i set oluncaya kadar denetlemek istediğin diğer işlemleri yaparsın.
16bit timer1'i 100ms'de bir timer1 overflow bit set olacak şekilde ayarladığımızı düşünelim(kullandığın xtal'e göre bu 100ms'yi değiştirebilirsin, 4Mhz için 500ms'ye çıkar, 20Mhz için 100ms). Bu 100ms'den daha uzun süreler için bir registerde kullanalım. Min süre : 100ms (register = 1 için) Max süre : 255x100ms=25,5sn'ye(reg:255) kadar delay sağlayabilirsin. Timer1 interrupt'ını kurarsan, 100ms'de bir interrupt'a gider ve registerini orada bir azaltırsın, ta ki 0 oluncaya kadar, böylelikle hiç bir işlemin uzun süreler boyunca aksamaz.
Kolay gelsin
İşte ben de bu olayı anlayamadım ki. Kolumdan tutup da bak kardeşim timer böyle olur diyen bir arkdaşım yok ki :D ezberci eğitim sistemi işte ne gördüysem yapmaya çalışıyorum Sağolsun arkadaşlar da yardımlarını esirgemiyorlar. Mesela bakıyorum ASM forumu pek hareketli değil. Neden çünkü adam için LCD_OUT("MERHABA DUNYA") yazmak çok kolay geliyor sanırım :)
Ben ince ince öğrenmek istiyorum.
Teşekkürler öneriniz için Timer modülünü araştırmaya başlıyorum birazdan. Bu arada ben devremi felan kurdum ama bi problem var sanırım :s çalışmadı program devrede bütün uçlar (proteusda) mavi görünüyor :s
Enteresan
Alıntı yapılan: "kostebek"Alıntı yapılan: "eemkutay"Merhaba,
Assembly'de registerler kullanarak uzun süreli delay yapmak iyi bir çözüm değildir mesela 1sn delay için işlemci 1sn boyunda aynı yerde dönüp durur ve 1sn boyunca başka hiçbirşey yapamaz. Bunun yerine timer kullan, timer'in overflag'i set oluncaya kadar denetlemek istediğin diğer işlemleri yaparsın.
16bit timer1'i 100ms'de bir timer1 overflow bit set olacak şekilde ayarladığımızı düşünelim(kullandığın xtal'e göre bu 100ms'yi değiştirebilirsin, 4Mhz için 500ms'ye çıkar, 20Mhz için 100ms). Bu 100ms'den daha uzun süreler için bir registerde kullanalım. Min süre : 100ms (register = 1 için) Max süre : 255x100ms=25,5sn'ye(reg:255) kadar delay sağlayabilirsin. Timer1 interrupt'ını kurarsan, 100ms'de bir interrupt'a gider ve registerini orada bir azaltırsın, ta ki 0 oluncaya kadar, böylelikle hiç bir işlemin uzun süreler boyunca aksamaz.
Kolay gelsin
İşte ben de bu olayı anlayamadım ki. Kolumdan tutup da bak kardeşim timer böyle olur diyen bir arkdaşım yok ki :D ezberci eğitim sistemi işte ne gördüysem yapmaya çalışıyorum Sağolsun arkadaşlar da yardımlarını esirgemiyorlar. Mesela bakıyorum ASM forumu pek hareketli değil. Neden çünkü adam için LCD_OUT("MERHABA DUNYA") yazmak çok kolay geliyor sanırım :)
Ben ince ince öğrenmek istiyorum.
Teşekkürler öneriniz için Timer modülünü araştırmaya başlıyorum birazdan. Bu arada ben devremi felan kurdum ama bi problem var sanırım :s çalışmadı program devrede bütün uçlar (proteusda) mavi görünüyor :s
Enteresan
Arkadaş önce bu şekilde burada insanları yargılamaman gerektiğini söylemek istiyorum ki, arkadaşlar çok güzel olayı izah etmişler. Tamam sen çok güzel diyorsun ben ağırdan alıp bütün herşeyi yavaş yavaş öğrenmek istiyorum demişsin. Sana tavsiyem önce gecikme nedir nasıl yapılır ile alakalı bütün yazıları oku ve elinde olan kitap veya ebook ları karıştır, en önemlisi çalışmak istediğin, atıyorum pic16f84 ün datasheetini açıp "timer" bölümünü bir oku sonra bu yazdıklarını tekrardan bir düşün. Hem burada kimse sana ilkokul öğretmeni gibi herşeyi hece hece anlatmak zorunda değil ayrıca bu sitede paylaşım yapan çoğu kişinin elektronik ve mikroişlemciler ile biraz bilgi sahibi olduğu varsayılarak cevap veriliyor...Arkadaşlar gecikme olayını anlatmışlar ben girmiyeceğim...Kolay gelsin.
Merhaba,
Timer1 ile ilgili ufak bilgi vereyim gerisini sen getir.
Timer1 16 bittir, 0000-FFFF arasında sayar, FFFF'den 0000'a geçerken TMR1IF (timer1 overflow flag) set olur. Bizde zamanın dolduğunu anlarız. Timer1'in sayması için, istediğimiz sayıdan başlatabiliriz,Bunun için TMR1L ve TMRH registerleri kullanılır.
Aşağıdaki örneğimde TMR1L=00H ve TMR1H =00H , dolayısıyla timer1, 0000H'den itibaren saymaya başlayacak,Örneğimizde xtal 4Mhz, dolayısıyla instruction cycle(bir komutun çalışma süresi) (xtal/4)=1us'dir. 0000H'den başlayacağımız için,
FFFFH(desimal olarak 65535),
Son değer - ilk değer = 65535 - 0000= 65535 (aslında 65536, 65535'den 0'a geçerken flag set olur bu nedenle 0'da sayılır, ama önemli değil)
Ayrıca Timerlarda prescaler'lar vardır. Prescaler, ön ölçeklendirici demektir kelime anlamıyla yani kaç instruction cycle'da bir timer saymasını istiyorsak , buradan ayarlamalıyız. Mesela aşağıda 8 instruction cycle'da bir timer1 bir arttar.
Toplam zaman = prescale * instructioın cycle * (sondeğer - ilk değer)
= 8 * 1us * (65535 - 0)= 524280us = 525ms yapar
Gerisini örneğe bakarak anlamaya çalış.
; Program başında timer1'in prescale'lasını ayarla ve timer1 osc'yi ON yap
; TMR1 enable yapıp yapmamak sana kalmış, istediğin zamanda enable
; yapabilirsin
MOVLW 38H,
MOVWF T1CON ; 1/8 Prescale, T1 osc enable ama TMR1 off
RCALL START_500MS ; 500ms saymaya başlar
loop:
ekranı sür ; burada yapmak istediklerini yap
keyboard oku
bunu yap
şunu yap
BTFSS PIR1,TMR1IF ; 500ms olmuş mu?
GOTO loop ; hayır, diğer işleri yapmaya devam et
BCF PIR1,TMR1IF ; evet zaman dolmuş, flag'i sil
....
...
; 25ms ihmal ettim
START_500MS: ; 525msn'de bir overflow
BANKSEL TMR1H ; ilgili banka geç
CLRF TMR1H ; registerleri clear et
CLRF TMR1L
BCF PIR1,TMR1IF ; overflow flag'i clear et
BSF T1CON,TMR1ON ; Timer1 saymaya başlasın
RETURN
Kolay gelsin
Alıntı yapılan: "eemkutay"Merhaba,
Timer1 ile ilgili ufak bilgi vereyim gerisini sen getir.
Timer1 16 bittir, 0000-FFFF arasında sayar, FFFF'den 0000'a geçerken TMR1IF (timer1 overflow flag) set olur. Bizde zamanın dolduğunu anlarız. Timer1'in sayması için, istediğimiz sayıdan başlatabiliriz,Bunun için TMR1L ve TMRH registerleri kullanılır.
Aşağıdaki örneğimde TMR1L=00H ve TMR1H =00H , dolayısıyla timer1, 0000H'den itibaren saymaya başlayacak,Örneğimizde xtal 4Mhz, dolayısıyla instruction cycle(bir komutun çalışma süresi) (xtal/4)=1us'dir. 0000H'den başlayacağımız için,
FFFFH(desimal olarak 65535),
Son değer - ilk değer = 65535 - 0000= 65535 (aslında 65536, 65535'den 0'a geçerken flag set olur bu nedenle 0'da sayılır, ama önemli değil)
Ayrıca Timerlarda prescaler'lar vardır. Prescaler, ön ölçeklendirici demektir kelime anlamıyla yani kaç instruction cycle'da bir timer saymasını istiyorsak , buradan ayarlamalıyız. Mesela aşağıda 8 instruction cycle'da bir timer1 bir arttar.
Toplam zaman = prescale * instructioın cycle * (sondeğer - ilk değer)
= 8 * 1us * (65535 - 0)= 524280us = 525ms yapar
Gerisini örneğe bakarak anlamaya çalış.
; Program başında timer1'in prescale'lasını ayarla ve timer1 osc'yi ON yap
; TMR1 enable yapıp yapmamak sana kalmış, istediğin zamanda enable
; yapabilirsin
MOVLW 38H,
MOVWF T1CON ; 1/8 Prescale, T1 osc enable ama TMR1 off
RCALL START_500MS ; 500ms saymaya başlar
loop:
ekranı sür ; burada yapmak istediklerini yap
keyboard oku
bunu yap
şunu yap
BTFSS PIR1,TMR1IF ; 500ms olmuş mu?
GOTO loop ; hayır, diğer işleri yapmaya devam et
BCF PIR1,TMR1IF ; evet zaman dolmuş, flag'i sil
....
...
; 25ms ihmal ettim
START_500MS: ; 525msn'de bir overflow
BANKSEL TMR1H ; ilgili banka geç
CLRF TMR1H ; registerleri clear et
CLRF TMR1L
BCF PIR1,TMR1IF ; overflow flag'i clear et
BSF T1CON,TMR1ON ; Timer1 saymaya başlasın
RETURN
Kolay gelsin
Teşekkür ederim. Gayet açıklayıcı bir yazı olmuş. Ben bunun üzerinde yarın uzun uzun düşüneyim.
Verdiğiniz bütün bilgiler için teşekkür ederim arkadaşlar :)
arkadaşlar yukarıdaki koddan hareketle 500ms aralıklarla iki ledi sırayla yakan bir kod yazdım ama hata veriyor programı derlerken
;====500milisaniye_ile_yan_son===31.01.2008======
;==================================
LIST P=16F628A
INCLUDE "P16F628A.INC"
__CONFIG _INTRC_OSC_NOCLKOUT &_WDT_OFF &_PWRTE_ON &_MCLRE_ON &_BODEN_OFF &_LVP_OFF &_DATA_CP_OFF &_CP_OFF
;==================================
ORG h'04' ; Burdan yazmaya başla
TANIMLAMALAR ; Tanımlamalar diye etiket oluşturuluyor
CLRF PORTB ; PORT B'nin bütün uçlarını temizle
BANKSEL TRISA ; BANK1'e geç
MOVLW h'FF' ; Akü'ye FF koy
MOVWF TRISA ; Akü'nün içini TRISA'ya koy / A'nın bütün bitleri 1 yapıldı.-Giriş
CLRF TRISB ; B'nin bütün bitlerini 0 la- Çıkış yapıldı
BANKSEL PORTA ; BANK0'a geç
; Program başında timer1'in prescale'lasını ayarla ve timer1 osc'yi ON yap
; TMR1 enable yapıp yapmamak sana kalmış, istediğin zamanda enable
; yapabilirsin
MOVLW 38H
MOVWF T1CON ; 1/8 Prescale, T1 osc enable ama TMR1 off
RCALL START_500MS ; 500ms saymaya başlar
START_500MS ; 525msn'de bir overflow (25MS İPTAL ETTİK)
BANKSEL TMR1H ; ilgili banka geç
CLRF TMR1H ; registerleri clear et
CLRF TMR1L
BCF PIR1,TMR1IF ; overflow flag'i clear et
BSF T1CON,TMR1ON ; Timer1 saymaya başlasın
RETURN
SIFIRYAK ; PORTB'nin 0 numaralı pinine bağlı ledi yak
BSF PORTB,0
BCF PORTB,1
BTFSS PIR1,TMR1IF ; 500ms olmuş mu?
GOTO SIFIRYAK ; hayır, yakmaya devam et
BCF PIR1,TMR1IF ; evet, Birinici ledi yakmaya git
BIRYAK ; PORTB'nin 1. numaralı pinine bağlı ledi yak
BSF PORTB,1
BCF PORTB,0
BTFSS PIR1,TMR1IF ; 500ms olmuş mu?
GOTO BIRYAK ; hayır, BİRİ yakmaya devam et
BCF PIR1,TMR1IF ; evet zaman dolmuş, flag'i sil
GOTO SIFIRYAK ; SIRIFI YAKmaya git
END
hata da şu
Message[302] C:\USERS\KOSTEBEK\DESKTOP\A_500_MILISANIYE.ASM 14 : Register in operand not in bank 0. Ensure that bank bits are correct.
Message[302] C:\USERS\KOSTEBEK\DESKTOP\A_500_MILISANIYE.ASM 15 : Register in operand not in bank 0. Ensure that bank bits are correct.
Warning[207] C:\USERS\KOSTEBEK\DESKTOP\A_500_MILISANIYE.ASM 22 : Found label after column 1. (RCALL)
Error[122] C:\USERS\KOSTEBEK\DESKTOP\A_500_MILISANIYE.ASM 22 : Illegal opcode (START_500MS)
Merhaba,
Hata 1:
ORG 04h ; Bu adres interrupt adresidir, işlemci 0H adresinden başlar
ORG 00H; doğrusu budur, 00h ile 04H arasında goto komutu ile başka bir etikete(adrese gidilir)
Hata 2:
PIC16F serisinde rcall komutu yok, yerine call kullanacaksın sorun çözülecek
aşağıda hatalarını düzelttim incele ve çalıştır
;====500milisaniye_ile_yan_son===31.01.2008======
;==================================
LIST P=16F628A
INCLUDE "P16F628A.INC"
__CONFIG _INTRC_OSC_NOCLKOUT &_WDT_OFF &_PWRTE_ON &_MCLRE_ON &_BODEN_OFF &_LVP_OFF &_DATA_CP_OFF &_CP_OFF
;==================================
ORG h'00' ; Burdan yazmaya başla
GOTO START
;TANIMLAMALAR ; Tanımlamalar diye etiket oluşturuluyor
START:
CLRF PORTB ; PORT B'nin bütün uçlarını temizle
BANKSEL TRISA ; BANK1'e geç
MOVLW h'FF' ; Akü'ye FF koy
MOVWF TRISA; Akü'nün içini TRISA'ya koy / A'nın bütün bitleri 1 yapıldı.-Giriş
CLRF TRISB ; B'nin bütün bitlerini 0 la- Çıkış yapıldı
BANKSEL PORTA ; BANK0'a geç
; Program başında timer1'in prescale'lasını ayarla ve timer1 osc'yi ON yap
; TMR1 enable yapıp yapmamak sana kalmış, istediğin zamanda enable
; yapabilirsin
MOVLW 38H
MOVWF T1CON ; 1/8 Prescale, T1 osc enable ama TMR1 off
CALL START_500MS ; 500ms saymaya başlar
SIFIRYAK: ; PORTB'nin 0 numaralı pinine bağlı ledi yak
BSF PORTB,0
BCF PORTB,1
BTFSS PIR1,TMR1IF ; 500ms olmuş mu?
GOTO SIFIRYAK ; hayır, yakmaya devam et
BCF PIR1,TMR1IF ; evet, Birinici ledi yakmaya git
BIRYAK: ; PORTB'nin 1. numaralı pinine bağlı ledi yak
BSF PORTB,1
BCF PORTB,0
BTFSS PIR1,TMR1IF ; 500ms olmuş mu?
GOTO BIRYAK ; hayır, BİRİ yakmaya devam et
BCF PIR1,TMR1IF ; evet zaman dolmuş, flag'i sil
GOTO SIFIRYAK ; SIRIFI YAKmaya git
START_500MS: ; 525msn'de bir overflow (25MS İPTAL ETTİK)
BANKSEL TMR1H ; ilgili banka geç
CLRF TMR1H ; registerleri clear et
CLRF TMR1L
BCF PIR1,TMR1IF ; overflow flag'i clear et
BSF T1CON,TMR1ON ; Timer1 saymaya başlasın
RETURN
END
Kolay gelsin
Teşekkür ederim eemkutay;
hergün başka birşey öğreniyorum :D o değil de öğren öğren de bitmiyor bu küçücük alet yawww :?
eemkutay arkadaşa katılıyorum yazılımsal olarak yapılan gecikme işlemleri ile tam olarak zamanı tutturmak zor olabilir ... Ama Timer bu işi çok güzel bir şekilde yapıyor kullanılması çok daha rahat ve kolay...