pıc16f877a timer0 kullanarak sayıcı yapmak

Başlatan javax1, 31 Ekim 2013, 16:34:15

javax1

Arkadaşlar pıc16f877a kullanarak timer0 ile 4 bitlik bir sayıcı yapmak istiyorum. 0.5 saniye aralıklarla sayma yapıcak butona bastıgımda sayacak bir daha bastıgımda duracak tekrar basıldıgında ise kaldıgı yerden saymaya devam edecek. Kitapta aşagıdaki gibi bir örnek buldum benziyor fakat bazı sorunlarım var.


1-) Bu devreyi kurdugumda butona 4 kere basıldığında sayma işlemini yapıyor yani : ilk durumda 0000 --> 4 kere butona basıyorum 0001 oluyor. Bu 4 nereden geliyor? Tek seferde basınca döngüye giren bir koda dönüştüremezmiyiz bunu ? Yardımcı olursanız sevinirim herkese iyi çalışmalar...

   list p=16F877A
   include "p16F877A.inc"

   __config H'3F31'

Counter    equ 0x25
      ORG   0

      clrf PCLATH
      goto ana_program
      ORG 4

interrupt
   btfss INTCON, 5
   goto int_j1
   btfss INTCON, 2
   goto int_j1
   movlw 0xFF
   movwf TMR0
   bcf INTCON,2
   incf Counter, F
   movf Counter, W
   sublw D'15'

   btfss STATUS, C
   clrf Counter
   movf Counter, W
   movwf PORTB
int_j1
   retfie

ilk_islemler
   movlw b'11100001'
   banksel OPTION_REG
   movwf OPTION_REG
   movlw 0xFF
   movwf TRISA
   clrf PORTB
   bcf STATUS, RP0
   clrf PORTB
   movlw 0xFF
   movwf TMR0
   clrf Counter
   bsf INTCON, TMR0IE
   bsf INTCON, PEIE
   bsf INTCON, GIE
   return

ana_program
   call ilk_islemler


ana_j1
   goto ana_j1

   END   

acar

Option_reg ' e atanan degerde frekans secme biti wdt 1, prescaler secme biti ise 000 olmali.
Movlw b'11101000


javax1

#2
Alıntı yapılan: acar - 01 Kasım 2013, 10:38:56
Option_reg ' e atanan degerde frekans secme biti wdt 1, prescaler secme biti ise 000 olmali.
Movlw b'11101000

aynen hocam dün o sorunu çözdüm fakat istediğim olayı tam olarak gerçekleştirmiyor. Butona her bastığımda artış sağlanıyor. Benim istediğim olay ise butona 1 kere bastığımda otomatik saymaya başlasın 15'ten sonra tekrar 0'a dönsün(4-bit sayıcı).

Bu yüzden araştırırken farklı bir kod tasarımı buldum. Bu aşağıdaki kod ise 8 bit (0-255 binary) sayıyor ve butondan bağımsız (butona basmadan direk) sayıyor. Bunu 4-bit(0-15 binary)sayıcıya dönüştürmem ve bir butona bağlamam gerek. Yani butona bastığımda saymaya başlayacak bir defa daha bastığımda duracak, tekrar bastığımda ise kaldığı yerden saymaya devam edecek. Tüm bunlara ek olarak birde sayma süresini 0.5 saniye olarak ayarlamam gerekiyor. Fakat bunu en sona bırakacağım biraz daha karışık sanırım.(Prescaler kullanarak yapılacak heralde 0.5 saniye olayı)


İlgilendiğiniz için Teşekkürler.

   list p=16F877A
   include "p16F877A.INC"
   ORG 0x00
   GOTO BASLA
   ORG 0x04
   GOTO LED_YAK
BASLA
   BSF STATUS, 5
   CLRF TRISB
   MOVLW b'00000111'
   MOVWF OPTION_REG
   BCF STATUS, 5
   MOVLW h'00'
   MOVWF TMR0
   MOVLW b'10100000'
   MOVWF INTCON
   CLRF PORTB
DONGU
   GOTO DONGU
LED_YAK
   BCF INTCON, T0IF
   INCF PORTB, F
   MOVLW h'00'
   MOVWF TMR0
   RETFIE
   END


NOT : Hocam son olarak BASLA bloğunun hemen başına BTFSC PORTA, 4 -->GOTO LED_YAK diye komut ekledim bu sefer butona basınca çalıştırdı fakat tekrar bastığımda durmadı.

RaMu



   list p=16F877A                     ;m.d.
   include "p16F877A.INC"       ; tanımlamaları
  ORG 0x00                              ;program başlangıcı
   GOTO BASLA                         ;program başladığında BASLA etiketine dallansın
   ORG 0x04                             ;kesme oluştuğunda programın geleceği yer
   GOTO LED_YAK                     ;kesme olursa LED_YAK etiketine dallan
BASLA                                      ;Program işlenmeye başlayınca önce burası işleniyor
   BSF STATUS, 5                       ;bank1 e geç giriş çıkış vs. tanımlamaları yap
   CLRF TRISB                            ;portb çıkış
   MOVLW b'00000111'
   MOVWF OPTION_REG            ;option registeri kuruluyor bilmemne ayaraında (datasheete bakmam lazım üşendim)
   BCF STATUS, 5                       ;bank0 a dön
   MOVLW h'00'
   MOVWF TMR0                         ;tmr0 a 00 yğkle
   MOVLW b'10100000'
   MOVWF INTCON                     ;intcon registerine .... yükle şu ayarda olsun (datasheet...)
   CLRF PORTB                           ;portb sıfırla
DONGU
   GOTO DONGU                         ;sonsuz döngü, istenen işlemin yapılması için artık kesme oluşması beklenir burada
LED_YAK                                    ;kesmede işlenen kod parçası
   BCF INTCON, T0IF                   ;kesmeye girilince timer0 interrupt flag elle sıfırlanmalı (okey)
   INCF PORTB, F                         ;portbdeki değeri 1 arttır portbye yaz
   MOVLW h'00'                           ;tmr0 a 00 yükle
   MOVWF TMR0
   RETFIE                                     ;kesmeden dön,çık
   END




şimdi program bunu yapıyor,
kodunun yanına böyle ne yaptığını yaz,
kod yazmadan önce mantığını oluştur,
akış diyagramı oluştur yani, algoritmanı kur
sonra koda çevirirsin,
ayrıca programını adım adım yaz
önce kesme oluşuyormu doğru kurmuşmuyum kesmeyi diye bir bak,
mesela her kesme oluştuğunda bir ledi yanıyorsa söndür sönüyorsa yak,
sonra diğer kısmı yani sayıcı kısmını hallet tek başına
yani kesme kullanmadan sayıcı programı yaz çalıştır
kesmeninn sağlayacağı gecikmeyi kendin gecikme rutini yazarak oluşturabilirsin,
daha sonra bunlarıı birleştir olsun bitsin.





şimdi akış diagramına örnek verelim,
misal kesme ile 0-9 sayıcı yapacaksın;

1) giriş kurulumu (port yönlendirmesi, timer kurulumu vs.)  yap
    program başlangıç ve kesme adreslerini ata
2)sonsuz döngüde bekle bu sayede kesme gelirse kesme kısmında işlem yaptırılır

3)kesme rutini
  3_1> kesme bayrağını sil
  3_2> sayac değerini bir arttır sayac değişkenine tekrar yaz
  3_3> sayac değişkeni 0Ah (yani decimal 10 ) olmuşmu kontrol et
  3_4> evet olmuş o zaman en son 9 rakamı gösterilmiştir sayac değerini sıfır yap (sayaca 00 yükle) ve adım 3_5 e git
  3_5> hayır olmamış tamam öyleyse arttırılmış değer çıkış portunda gösterilmeli
           sayac değişkenindeki değeri çıkış portunda göster
  3_6> kesmeden çık






Şimdi misal bu programı yazdın artık butona basılırsa saymaya başlasın
butona basılırsa olduğu yerde dursun
tekrar basılırsa saymaya devam etsin istiyorsun,

o zaman ana döngüde yani sonsuz döngü dediğimiz yerde
ana dongu
butonu kontrol et, butona basıldımı?
         evet >    butona basılmış
                       kesme_durum değişkenini 1 mı kontrol et
                       > evet kesme durum değişkeni 1 miş (yani kesme aktifmiş)
                          kesme durum değişkenini sıfır yap, ve kesmeyi kapat
                       >hayır kesme durum değişkeni 0 mış (yani kesme kapalıymış)
                         kesme durum değişkenini 1 yap, ve kesmeyi aç
           
          hayır> butona basılmamış
                     tekrar butonu kontrol etmeye git  (ana dongu yazan yer)






Bunun gibi birşeyler yapacaksın yani,
hızlı yazdım hatalar olabilir,
fikir vermesi yönünden faydalı olur sanırım.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

javax1

#4
Alıntı yapılan: RaMu - 01 Kasım 2013, 20:55:38

   list p=16F877A                     ;m.d.
   include "p16F877A.INC"       ; tanımlamaları
  ORG 0x00                              ;program başlangıcı
   GOTO BASLA                         ;program başladığında BASLA etiketine dallansın
   ORG 0x04                             ;kesme oluştuğunda programın geleceği yer
   GOTO LED_YAK                     ;kesme olursa LED_YAK etiketine dallan
BASLA                                      ;Program işlenmeye başlayınca önce burası işleniyor
   BSF STATUS, 5                       ;bank1 e geç giriş çıkış vs. tanımlamaları yap
   CLRF TRISB                            ;portb çıkış
   MOVLW b'00000111'
   MOVWF OPTION_REG            ;option registeri kuruluyor bilmemne ayaraında (datasheete bakmam lazım üşendim)
   BCF STATUS, 5                       ;bank0 a dön
   MOVLW h'00'
   MOVWF TMR0                         ;tmr0 a 00 yğkle
   MOVLW b'10100000'
   MOVWF INTCON                     ;intcon registerine .... yükle şu ayarda olsun (datasheet...)
   CLRF PORTB                           ;portb sıfırla
DONGU
   GOTO DONGU                         ;sonsuz döngü, istenen işlemin yapılması için artık kesme oluşması beklenir burada
LED_YAK                                    ;kesmede işlenen kod parçası
   BCF INTCON, T0IF                   ;kesmeye girilince timer0 interrupt flag elle sıfırlanmalı (okey)
   INCF PORTB, F                         ;portbdeki değeri 1 arttır portbye yaz
   MOVLW h'00'                           ;tmr0 a 00 yükle
   MOVWF TMR0
   RETFIE                                     ;kesmeden dön,çık
   END




şimdi program bunu yapıyor,
kodunun yanına böyle ne yaptığını yaz,
kod yazmadan önce mantığını oluştur,
akış diyagramı oluştur yani, algoritmanı kur
sonra koda çevirirsin,
ayrıca programını adım adım yaz
önce kesme oluşuyormu doğru kurmuşmuyum kesmeyi diye bir bak,
mesela her kesme oluştuğunda bir ledi yanıyorsa söndür sönüyorsa yak,
sonra diğer kısmı yani sayıcı kısmını hallet tek başına
yani kesme kullanmadan sayıcı programı yaz çalıştır
kesmeninn sağlayacağı gecikmeyi kendin gecikme rutini yazarak oluşturabilirsin,
daha sonra bunlarıı birleştir olsun bitsin.





şimdi akış diagramına örnek verelim,
misal kesme ile 0-9 sayıcı yapacaksın;

1) giriş kurulumu (port yönlendirmesi, timer kurulumu vs.)  yap
    program başlangıç ve kesme adreslerini ata
2)sonsuz döngüde bekle bu sayede kesme gelirse kesme kısmında işlem yaptırılır

3)kesme rutini
  3_1> kesme bayrağını sil
  3_2> sayac değerini bir arttır sayac değişkenine tekrar yaz
  3_3> sayac değişkeni 0Ah (yani decimal 10 ) olmuşmu kontrol et
  3_4> evet olmuş o zaman en son 9 rakamı gösterilmiştir sayac değerini sıfır yap (sayaca 00 yükle) ve adım 3_5 e git
  3_5> hayır olmamış tamam öyleyse arttırılmış değer çıkış portunda gösterilmeli
           sayac değişkenindeki değeri çıkış portunda göster
  3_6> kesmeden çık






Şimdi misal bu programı yazdın artık butona basılırsa saymaya başlasın
butona basılırsa olduğu yerde dursun
tekrar basılırsa saymaya devam etsin istiyorsun,

o zaman ana döngüde yani sonsuz döngü dediğimiz yerde
ana dongu
butonu kontrol et, butona basıldımı?
         evet >    butona basılmış
                       kesme_durum değişkenini 1 mı kontrol et
                       > evet kesme durum değişkeni 1 miş (yani kesme aktifmiş)
                          kesme durum değişkenini sıfır yap, ve kesmeyi kapat
                       >hayır kesme durum değişkeni 0 mış (yani kesme kapalıymış)
                         kesme durum değişkenini 1 yap, ve kesmeyi aç
           
          hayır> butona basılmamış
                     tekrar butonu kontrol etmeye git  (ana dongu yazan yer)






Bunun gibi birşeyler yapacaksın yani,
hızlı yazdım hatalar olabilir,
fikir vermesi yönünden faydalı olur sanırım.



Hocam sonsuz döngü kısmını dediğiniz şekilde düzenledim fakat sorun gene aynı şekilde tekrar ediyor. Butona basılı tutunca saymaya başlıyor bırakınca bütün ledler sönüyor, tekrar basılı tutarsam en baştan(0'dan) tekrar saymaya başlıyor bırakınca gene ledler sönüyor. Ve bazen butona basılı tutunca bile yanmıyor, butona basılı gibi gözüküyor ama yanmıyor sonra biraz daha sert basıyorum Mouse'a o zaman yanıyor. Bu biraz ilginç :)

Benim yapmak istediğim olay ise butona basıp bırakmak; basılı tutmak değil, ilk basıp bıraktığımda saymaya başlasın sonra bir daha basıp bırakırsam saydığı yerde dursun, bundan sonra bir daha basıp bırakırsam tekrar kaldığı yerden saymaya devam etsin gibi... Aşağıdaki kodu kullanınca yukarıda dediğim basılı tutunca sayan bırakınca ledleri söndüren tekrar basılı tutarsam yeniden baştan saymaya başlayan olayı yapıyor. Buton basıp bırakma olayında yardımcı olabilirseniz sevinirim. İyi çalışmalar...



    list p=16F877A            ;m.d.
    include "p16F877A.INC"       ; tanımlamaları
    ORG 0x00                              ;program başlangıcı
    GOTO BASLA                         ;program başladığında BASLA etiketine dallansın
    ORG 0x04                             ;kesme oluştuğunda programın geleceği yer
LED_YAK                                 
    BCF INTCON, T0IF                   ;kesmeye girilince timer0 interrupt flag elle sıfırlanmalı (okey)
    INCF PORTB, F                         ;portbdeki değeri 1 arttır portbye yaz
    MOVLW h'00'                           ;tmr0 a 00 yükle
    MOVWF TMR0                             ;kesmeden dön,çık
    RETFIE                 
BASLA                                      ;Program işlenmeye başlayınca önce burası işleniyor
    BSF STATUS, 5                       ;bank1 e geç giriş çıkış vs. tanımlamaları yap
    CLRF TRISB                            ;portb çıkış
    MOVLW b'00000111'
    MOVWF OPTION_REG            ;option registeri kuruluyor bilmemne ayaraında (datasheete bakmam lazım üşendim)
    BCF STATUS, 5                       ;bank0 a dön
    MOVLW h'00'
    MOVWF TMR0                         ;tmr0 a 00 yÜkle
    MOVLW b'10100000'
    MOVWF INTCON                     ;intcon registerine .... yükle şu ayarda olsun (datasheet...)
    CLRF PORTB                           ;portb sıfırla
DONGU
              BTFSS PORTA, 4            ; PORTA'NIN 4.BİTİ(BUTON BAĞLI OLAN) 1 İSE ALTTAKİ SATIRI ATLA 0 İSE ALTTAKİ SATIRI İŞLE.
              GOTO DONGU               ; BUTONA BASILMAMIŞSA DÖNGÜYE GİT BUTONU KONTROL ET.
              BTFSS INTCON, 5          ; BUTONA BASILMIŞ TMR0IE KESMEYİ KONTROL ET 1 İSE ALTTAKİ SATIRI ATLA 0 İSE ALTTAKİ SATIRI İŞLE.
              BSF INTCON, 5             ; EĞER INTCON,5 --> TMR0IE "0" İSE BURASI İŞLENİR.
              BCF INTCON, 5             ; EĞER INTCON --> TMR0IE "1" İSE BURASI İŞLENİR.                   
              END

RaMu

(Uzun mesajların tamamını alıntı yapmazsan iyi olur görüntü kirliliği olmasın boşyere.)

Evet bence eklemeler güzek ışık var, biraz daha uğraşırsan bu işi çözersin ha gayret.

DONGU
              BTFSS PORTA, 4            ; PORTA'NIN 4.BİTİ(BUTON BAĞLI OLAN) 1 İSE ALTTAKİ SATIRI ATLA 0 İSE ALTTAKİ SATIRI İŞLE.
              GOTO DONGU               ; BUTONA BASILMAMIŞSA DÖNGÜYE GİT BUTONU KONTROL ET.
(button debounce buton arkı dediğimiz bir olay var biraz araştır,
buton arkını önlemek için buraya bir gecikme eklemek iyi olur,
call   gecikme100milisaniye gibi)

              BTFSS INTCON, 5          ; BUTONA BASILMIŞ TMR0IE KESMEYİ KONTROL ET 1 İSE ALTTAKİ SATIRI ATLA 0 İSE ALTTAKİ SATIRI İŞLE.
              BSF INTCON, 5             ; EĞER INTCON,5 --> TMR0IE "0" İSE BURASI İŞLENİR.
              BCF INTCON, 5             ; EĞER INTCON --> TMR0IE "1" İSE BURASI İŞLENİR.

bu yazdıkların pekbirişe yaramaz çünkü
intcon u girişte kuruyorsun ve bakdığın bit set durumda
sonra burada btfss set olduğunu görüyor ve bcf satırına atlayıp kesmeyi pasif yapıyor,
sonra programı buradan sonra biryere göndermemiş olduğun için program muhtemelen org 00 satırına gidiyor.

benim dediğim işlem tam olarak bu şekilde değil,
anlattıklarıma birdaha göz gezdir, zaten senin son dediğin-istediğin işlem için gerekl, şeyler var yukarıda.           
              END
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html