avatar_elektro77

20 mhz de option_reg bölme oranı

Başlatan elektro77, 23 Temmuz 2020, 18:08:10

elektro77

Yaptığım bir tasarımda 16f877A yı 20 mhz de çalıştırmak istiyorum. Programda bir adet saat kesmesi ve ayrıca birde ds1307 saat var.
portb dahili pulluplar kapalı.
Option_reg bölme oranı ne olmalı ve nasıl set etmeli. Datasheete baktım ama nereye bakacağımı tam bulamadım. Gerçek devreyi kurup denemedim henüz ama kurduğumda 20Mhz de zamanın doğru çalışması için ön bilgi ediniorum.
Saygılarımla
Kodun bir kısmı aşağıdadır.
@ __config _HS_OSC & _WDT_ON & _LVP_OFF & _CP_ON
DEFINE OSC 20
TRISA=%111111
TRISB=%00000011
TRISC=%11110000
TRISD=%01111111
TRISE=%00000000
PORTA=0:PORTB=0:PORTC=0:PORTD=0:PORTE=0
'--------------------------------------------------------------------------------
DEFINE LCD_DREG		PORTB	
DEFINE LCD_DBIT		4		
DEFINE LCD_RSREG	PORTB	
DEFINE LCD_RSBIT	2	
DEFINE LCD_EREG		PORTB	
DEFINE LCD_EBIT		3		
DEFINE LCD_BITS		4	
DEFINE LCD_LINES	4
'--------------------------------------------------------------------------------
ADCON1=%00000111                  'ADC KANALLARI DİJİTAL YAPILDI - ADC İPTAL
CMCON=7                                    'komparatör pinleri iptal hepsi giriş çıkış yapıldı.16F877 de yok.
'OPTION_REG.7=0                         'portB deki dahili PULL-UP lar DAHİL edildi.
'OPTION_REG =%00000111          'timer0 1/256 ayarlandı portb pulluplar kapalı 
OPTION_REG=%10000101   	     'Pull up dirençleri İPTAL- Bölme oranı 1/64.
INTCON=%10100000  
'TMR0=0 
'---------------------------değişkenler-----------------------------------------    
    symbol ROLE1=PORTC.0
    symbol ROLE2=PORTC.1
    symbol ROLE3=PORTC.2
    SYMBOL ROLE4=PORTC.3
    SYMBOL BUZER=PORTE.0
    SYMBOL ERLED=PORTD.7
SYMBOL BARTIR=PORTD.0
SYMBOL BAZALT=PORTD.2
SYMBOL CARTIR=PORTD.1
SYMBOL CAZALT=PORTD.3
SYMBOL SEC   =PORTD.4
'SYMBOL RST   =PORTD.6
SYMBOL RUN   =PORTD.5
SYMBOL MANUEL=PORTC.7

'-------------------'EKRAN ALTI SAAT DEĞİŞKENLERİ--------------------------------    
SYMBOL SCL  =PORTC.5'DS1307 TANIMLARI
SYMBOL SDA  =PORTC.6
'----------------------
SYMBOL SAATAYAR=PORTC.4
SAAT    VAR BYTE  
DAK     VAR BYTE  
SN      VAR BYTE  
ESKISN  VAR BYTE
AYGUN   VAR BYTE 
AY      VAR BYTE 
YIL     VAR BYTE  
HAFGUN  VAR BYTE 
SECOND  VAR BYTE
HOUR    VAR BYTE
MINUTE  VAR BYTE
WEEK    VAR BYTE
DAY     VAR BYTE
MONTH   VAR BYTE
YEAR    VAR BYTE
TEMP    VAR BYTE
SIRA    VAR BYTE
'--------------------------------------------------------------------------------
'ZAMAN ROLESİ DEĞİŞKENLERİ
BSAYAC  VAR BYTE
BSN     VAR BYTE 
BDAK    VAR BYTE
BSAAT   VAR BYTE:BSAAT=0
OK      VAR BYTE
CSAYAC  VAR BYTE:CSAYAC=0
CSN     VAR BYTE:CSN=0
CDAK    VAR BYTE:CDAK=0
CSAAT   VAR BYTE:CSAAT=0
CALIS   VAR BIT 'CALIŞ 1 OLUR İSE GERİ SAYIM KESMESİ ÇALIŞMAYA BAŞLAR. 0 OLUR İSE GERİ SAYIM KESMESİ DURUR
I       var WORD' for next döngüsünde ve delayda kullanılan deger 
'CLEAR
         
'-------------------------------------------------------------------------------
LCDOUT $FE,$40,0,4,12,31,31,12,4,0'SAĞDAN VE SOLDAN OK İŞARETLERİ
LCDOUT $FE,$48,0,4,6,31,31,6,4,0  'SAĞDAN VE SOLDAN OK İŞARETLERİ
CLEAR
'----------------------------EKRAN TEMİZLE--------------------------------------
PAUSE 100
LCDOUT $FE,1
PAUSE 100
'------------------------------------------------------------------------------- 
READ 0,BSN,BDAK,CSN,CDAK
gosub zamanoku  'ALT EKRAN SAATİNİ OKU 
gosub EKRAN_STANDBY'ALT EKRAN SAATİNİ EKRANA YAZ
'---------------------------PROGRAM-BASLA---------------------------------------
ERLED=1
PAUSE 200
ERLED=0
ON INTERRUPT GoTo KESME
'*******************************************************************************
'*******************************************************************************
'*******************************************************************************   
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

Bana kalırsa sorunun eksik yönleri mevcut. Açıklayayım.
Option_REG registeri 2-0 bitleri TMR0 veya WDT için bölme oranını belirler. Senin yazında TMR0 lafı hiç geçmiyor. Ne amaçla bölme oranı belirlenecek? buda belli değil.
Yine de soruna şöyle bir cevap verilebilir. Amaç burada TMR0 sayacının belirli bir zaman diliminde kesme oluşturmasını sağlamak ise ayar mekanzmasıda şöyle olmalıdır.
Örnekle devam edelim. Diyelimki her 1 ms de bir kesme oluşturacağız. 1 ms=1000us dir. Sayacımız 8 bitlik olduğu için 1000 us direk sayabilmesi mümkün değil çünki ancak 255us yi direk sayabilir.
Peki 1/2 bölme oranını kullanırsam ne olur? o zaman 510 us yi direk sayabilir. 1/4 bölme oranını kullanırsam 1.020us yi direk sayabilir. Ama işlemci 20 mhz de çalışınca bir clk çevrimi (adımı diyelim) 20/4=5 oda 1/5=0,2uslik bir zamanı kapsar. Bu durumda 1000/0,2=5.000 lik bir sayma değeri gerekiyor. Bunu 255'e bölersek net 19 çıkıyor. BU bölme oranımız olmalı. Ancak 19 diye bir bölme oranı yok. Standart bölme oranları 19 a en yakın olarak 16 veya 32 olabiliyor. Bu durumda 32 yi kullanacağız demektir. Peki 1/32 bölme oranını kullanırsak ve sayacı belirli bir değerden başlatmaz isek sayacımız 32 defa 0-255 arasını sayacağı için 255x32=8.160 sayacaktır.
Halbuki bize 5000 gerekiyor. O halde 8160-5000=3.160 fazlalık var. Bunu 32 ye bölersek 98,75 gibibir sayı buluruz. Bunu tamsayıya tamamlarsak 99 sayısını elde ederiz. O halde sayacımız saymaya 99 dan başlayacak ve her 32 clk palsinde bir sayarak 255-99=156 sayacak ve bunu 32 ile çarparsak 4992 gibi bir rakam elde ederiz ki komut gecikmeleri ile birlikte bu 5000 e çok yakın bir değer oalcaktır. Böylece ön yükleme değerimiz 99 olacak ve 1/32 lik bölme oranını kullanarak, 20 Mhz lik OSC frekansında her kesme aralığında 1000us=1ms lik bir gecikme yaratmış oluruz. BU hesaba göre kendi hesabını yaparsın artık.

Bu hesabı başka bir şekilde de yapabilirdik. Bize 1000 us lik bir gecikme gerekiyor. Ama komut çevrim süremiz 0,2us olduğundan 1000/0,2=5000 komut çevrimi gerekecektir.
Sayacımız 8 bitlik olduğu için bu sayaca 5000'i ancak bölme kullanarak saydırabiliriz. Bölme oranımız yaklaşık olarak 5000/255=19 olur. Standart bölme oranı olmadığı için bir üst standart değer olan 32 kullanacağız. 5000/32=156 çıktığı için sayacımız her seferinde 156 sayacaktır. Bunun için 255-156=99 ön yükleme değerinden saymaya başlayacak ve 255 den tekrar sıfıra geçerken 156 saymış olacaktır. Umarım anlamışsındır.

Ete
 

elektro77

#2
'-------------------------GERİ SAYIM saati---------------------------------------
DISABLE
KESME:
IF CALIS=1 THEN
IF BSN=0 AND BDAK=0 THEN 
CSAYAC=CSAYAC +1  
IF CSAYAC=61 then  
CSAYAC=0
CSN=CSN-1
 IF CSN>=59 THEN 
'    CSN=59
'      CDAK=CDAK -1  
'        IF CDAK>=59 THEN
'          CDAK=59
'           CSAAT=CSAAT-1
'             IF CSAAT>=23 THEN
'              CSAAT=0
'             CDAK=0
            CSN=0
             ENDIF
           ENDIF
         'ENDIF
      'ENDIF  
'--------------------------------------
ELSE 
'--------------------------------------
BSAYAC=BSAYAC+1  
IF BSAYAC=61 then  
   BSAYAC=0
    BSN=BSN-1
      IF BSN>=59 THEN 
         BSN=59
         BDAK=BDAK -1  
          IF BDAK>=59 THEN
             BDAK=59
'             BSAAT=BSAAT-1
'               IF BSAAT>=23 THEN
'              BSAAT=0
             BDAK=0
            BSN=0
          ENDIF
         ENDIF
       ENDIF  
    ENDIF
ENDIF
'ENDIF
'------------------------------------------------------------------------------- 
INTCON.2=0  
RESUME
ENABLE

Hocam öncelikle cevabınız için çok teşekkür ederim.

Yukarıdaki kodlarda olduğu gibi saniyede bir saymasını istediğim bir geri sayım kesmem var. İlk ve çalışan yazılımımda bu kesmenin saniyede bir geri sayması için, 4Mhz de, bölme oranını 1/64 alarak, tmr0 kesme önyükleme değerini 0 yaptım. Doğrumu yaptım bilmiyorum. Sizin gibi hassas hesaplamalar yapamıyorum. Genelde kütüphanemden faydalandığım için bu önyükleme ayarının 4Mhz de böyle olduğunu gördüm. Simülayonda istediğim gibi saniyede bir sayıyor gibi. Fakat gerçekte ne olur emin değilim. Bu hesapları sizin de cevaplarınız ile günden güne anlamaya çalışıyorum.
Ancak yazılımda diğer tüm kodlarınında, cihazın performansında oluşturduğu gecikmelerden azami kurtulmak için 20Mhz osc kullanarak,cihazı hız performansı açısından maximumda tutmaya çalışıyorum.
Yazdıklarınızdan anldığım kadarı ile aşağıdaki kodları oluşturdum doğruluğunu kontrol ederseniz sevinirim.

INTCON=%10100000             'bit.7=1»global kesmeler aktif,     bit5=1»TMR0 kesmesi aktif
OPTION_REG=%10000100           'bit.7=1»Pull up dirençleri İPTAL,     bit2..0=100»Bölme oranı 1/32.
TMR0=99      ' gerim sayım saati için 20Mhz de tmr0 önyükleme değeri 99 olamalı.

Birde şunu sormak isterim: TMR0 değeri programın başla satırından sonra da herhangibir yerde tekrar set edilmeli mi?
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

Amaç 1 sn lik sürelerin yakalanması ise hesap mantığın şöyle olmalı.
Öncelikle 1sn=1.000.ms=1.000.000 us olduğundan tek bir kesme ile bu sürenin yakalanması imkansız gözüküyor. Basit hesaplar yaparak bu sonuca ulaşabiliriz. Her bir komut cevrimi yani her clk palsi 0,2us tutuyor. Bize lazım olan 1.000.000us bunu 0,2 ye bölersek sayacağımız değerin 5.000.000 clk palsi olduğunu kolaylıkla görebiliriz. Enbüyük bölme oranı ise 256 olduğundan 5.000.000/256=19.531 saydığımızda aslında yaklaşık 5000.000us lik gecikme yaratmış olacağız. Ancak sayac 8 bitlik ve en fazla 255 e kadar sayabiliyoruz. Bize lazım olan 19.531 saydırma. Bunuda 255 e bölersek yaklaşık 76 kesme sayısını buluruz ki bu kadar kesme oluştuktan sonra geçen süre 1 sn olacaktır. İşte son hesap,
76 kesme x 255 x 256 =4.961.280 clk palsi ki buna komut gecikmemelerinde eklersek süre yaklaşık 1.000.000us olacaktır.

TMR0 ın tekrar set edilme ihtiyacına gelince. Şayet hesaplamalar sonucunda TMR0 belirli bir sayıdan başlayarak sayması gerekiyor ise başlangıçta o sayıya set edilmesi gerekir. Bu nedenle bazı kesmelerde (özellikle ekran taramalarında) TMR0 belirli bir sayıya set edilir. Onun dışında set edilmesi gerekmez. Şöyle bir genelleme yapabiliriz. Sayac 0 dan başlayıp 255 den sonra kesme oluşturacak ise set edilmesi gerekmez. Yukarıdaki 1n lik süre hesabında bu yöntem kullanılacak. Ama ince hesap sonucu sayac her seferinde bir değerden başlayacak ise set edilmesi gerekir.

Ete

Powered by EzPortal