Haberler:

Eposta uyarılarını yanıtlamayınız ( ! ) https://bit.ly/2J7yi0d

Ana Menü

XC8 Timer1 Sorunu

Başlatan Extreme, 01 Aralık 2014, 20:48:28

Extreme

Merhaba,

PIC=16f887
osilatör frekansım=10mhz
fclock=2 500 000 Hz

Timer1 istediğim değere set edemedim. pic timer1=0 olarak algılıyor.

timer1süresi=(65536-61681)*1/2500000
timer1süresi=1542 us

timer1i lcdye yazdırdığımda gelen görüntü 28 000 lerde sayı geliyor ?

timer1=0dan başlatıyor.
fakat benim ayarlamama göre timer1=61681'den başlatması gerekiyor.



timer1=0 olarak kuruyorum. Bu seferde lcd inanılmaz yavaş oluyor fakat lcd timer1 değeri aynı görüntüsü aynı oluyor.

Bug olduğunu düşünüyorum fikri olan ?

NOT:SİMÜLASYON VE BREAD BOARD AYNI SONUÇLAR.

#include <stdio.h>
#include <stdlib.h>

#define _XTAL_FREQ 10000000

#include <xc.h>
#include "Lcd416.h"

#pragma config FOSC = HS/*dahili osilator calisma icin seciliyor*/
#pragma config WDTE = OFF       /*Watch-dog timer resetlemesi engelleniyor*/
#pragma config PWRTE = ON      /*Power-On reset,sistem ilk enerjilendiginde belli bir sure resetlenmesi engelleniyor*/
#pragma config MCLRE = ON       /*MCLR pini aktif hale getiriliyor*/
#pragma config CP = ON         /* Program kod korumasi kapatiliyor*/
#pragma config CPD = ON        /*Veri kod korumasi kapatiliyor*/
#pragma config BOREN = OFF      /*Besleme voltaji dalgalandiginda resetlenme kapatiliyor*/
#pragma config IESO = ON     /*Ic osilatorden baslayip dis osilatore aktarim izni veriliyor*/
#pragma config FCMEN = ON     /*Saat kaynaginin stabilligi kontrolu kapatiliyor*/
#pragma config LVP = OFF        /* Dusuk voltajla programlanma kapatiliyor*/
#pragma config BOR4V = BOR40V
#pragma config WRT = OFF        /*Flash hafizaya program icinden ulasilma aciliyor*/

unsigned int lcdsayac=1;
unsigned int lcdcount=0;

void main(void)
{
    
    ANSEL=0;
    ANSELH=0;
    TRISA = 0b00000000;
    TRISB = 0b10011111;
    TRISC = 0b10000000;
    TRISD = 0b00000000;
    RC1=0; RD0=0;  RD1=0; RD2=0; RD3=0; //lcd fazla pinleri
     
    Lcd_Init();
    Lcd_Clear();
    __delay_ms(300);

    OPTION_REG=0b11011010;  //timer0 off, wdt prescaler 1:4
    WPUB=0b00000000;        //weak pull-ups disabled
    IOCB=0b00000000;        //No Any INTERRUPT-ON-CHANGE PORTB REGISTER

    PIE1=0b00000001;     //timer1 overflow interrupt aç.
    PIR1bits.TMR1IF=0;  //timer1 ta?ma yapmad?
    INTCON=0b11000000; //interrupt control register
    T1CON=0b00000000;  //timer1 control register

    TMR1=61681;
    T1CONbits.TMR1ON=1;
    timer1loop:
    goto timer1loop;
 }
void interrupt   kesme  (void)        // interrupt function

{
    TMR1 = 61681;
    PIR1bits.TMR1IF=0;// reload the timer - 250uS per interrupt

    lcdsayac=lcdsayac-1;
    if(lcdsayac==0)
    {
        Lcd_Clear();
        __delay_us(10000);
        lcdcount=lcdcount+1;
        lcdsayac=100;
        Lcd_Set_Cursor(2,1);
        printf("sayac= %d ",lcdcount);
        Lcd_Set_Cursor(3,1);
        printf("TİMER1=%d",TMR1);
    }
    else{}
 }


Gökhan BEKEN

#1
16f886 için şöyle bir örnek yapmıştım:
void timer1init(void) {
    T1CON = 0x01; //Configure Timer1 interrupt
    PIE1bits.TMR1IE = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;
    PIR1bits.TMR1IF = 0;

    T1CONbits.T1CKPS = 0b00; // 1:1 Prescale Value
}


void interrupt t1_int(void) {
    if (TMR1IE && TMR1IF) {
        TMR1 = 0xFFF0; //TMR1 On Yukleme Degeri

        sayac2 ^= 1; //tersle;
        PORTA = sayac2;
        TMR1IF = 0; //Timer1 Interrupt Flag Sifirlaniyor
    }
}
Özel mesaj okumuyorum, lütfen göndermeyin.

Extreme

Hocam aslında hepsi aynı gibi.



nasıl oluyor da timer1 negatif oluyor.

#include <stdio.h>
#include <stdlib.h>

#define _XTAL_FREQ 10000000

#include <xc.h>
#include "Lcd416.h"

#pragma config FOSC = HS/*dahili osilator calisma icin seciliyor*/
#pragma config WDTE = OFF       /*Watch-dog timer resetlemesi engelleniyor*/
#pragma config PWRTE = ON      /*Power-On reset,sistem ilk enerjilendiginde belli bir sure resetlenmesi engelleniyor*/
#pragma config MCLRE = ON       /*MCLR pini aktif hale getiriliyor*/
#pragma config CP = ON         /* Program kod korumasi kapatiliyor*/
#pragma config CPD = ON        /*Veri kod korumasi kapatiliyor*/
#pragma config BOREN = OFF      /*Besleme voltaji dalgalandiginda resetlenme kapatiliyor*/
#pragma config IESO = ON     /*Ic osilatorden baslayip dis osilatore aktarim izni veriliyor*/
#pragma config FCMEN = ON     /*Saat kaynaginin stabilligi kontrolu kapatiliyor*/
#pragma config LVP = OFF        /* Dusuk voltajla programlanma kapatiliyor*/
#pragma config BOR4V = BOR40V
#pragma config WRT = OFF        /*Flash hafizaya program icinden ulasilma aciliyor*/

unsigned int lcdsayac=1;
unsigned int lcdcount=0;

void main(void)
{
    
    ANSEL=0;
    ANSELH=0;
    TRISA = 0b00000000;
    TRISB = 0b10011111;
    TRISC = 0b10000000;
    TRISD = 0b00000000;
    RC1=0; RD0=0;  RD1=0; RD2=0; RD3=0; //lcd fazla pinleri
     
    Lcd_Init();
    Lcd_Clear();
    __delay_ms(300);

    OPTION_REG=0b11011010;  //timer0 off, wdt prescaler 1:4
    WPUB=0b00000000;        //weak pull-ups disabled
    IOCB=0b00000000;        //No Any INTERRUPT-ON-CHANGE PORTB REGISTER

    PIE1=0b00000001;     //timer1 overflow interrupt aç.
    PIR1bits.TMR1IF=0;  //timer1 ta?ma yapmad?
    INTCON=0b11000000; //interrupt control register
    T1CON=0b00000000;  //timer1 control register
    TMR1=10000;
    T1CONbits.TMR1ON=1;
    while(1);
 }
void interrupt   kesme  (void)        // interrupt function

{
    if (TMR1IE && TMR1IF) 
    {
    
    TMR1 = 10000;
    lcdsayac=lcdsayac-1;
    if(lcdsayac==0)
    {
        Lcd_Clear();
        __delay_us(10000);
        lcdcount=lcdcount+1;
        lcdsayac=100;
        Lcd_Set_Cursor(1,1);
        printf("Ekran yenileme");
        Lcd_Set_Cursor(2,1);
        printf("sayisi= %d ",lcdcount);
        Lcd_Set_Cursor(3,1);
        printf("TIMER1=%d",TMR1);
    }
    else{}
    
    TMR1IF=0;
   }
 }

 


Gökhan BEKEN

Projenizin yapısal sorunları var.
Timer veya herhangi bir kesme bu şekilde kullanılmaz. Kesmeye girince sadece bir veya bir kaç değişkeni(bayrağı) set edersiniz.
Main fonksiyonu içinde timer'e girildiğini bu bayrak(lar) sayesinde anlarsınız(çünkü sonsuz döngü içinde sürekli kontrol edersiniz)
ve anladığınızda işlemleri orda yaparsınız, bahsettiğim bayrakları sıfırlama işi yine main fonksiyonunda yapılır. Yoksa sizin işlemler timer süresini aşarsa bayraklar beklenmedik değerler alabilir.
Timer içinde 10000us bekleme yapmışsınız bu hiç iyi değil. Denemelerinizi LCD olmadan sadece led ile denerseniz emin olabileceğiniz sonuçlar alabilirsiniz.
Özel mesaj okumuyorum, lütfen göndermeyin.

Extreme

hocam timer1de 10ms bekleme yapmam göstermek için aşağıdaki kodlara bakınız .

TMR1 = 53036; Buda benim değerlerime göre her timer1 kesmesi 5ms

2ms bekleme koydum . şimdi ben timer1 değerini lcdde 53036 ile 65536 görmeyi bekliyorum.





Gökhan BEKEN

Timer değerlerini görmek için proteusta pin çıkışına osiloskop bağlarsanız kesin zaman ölçümü yapabilirsiniz. Tabi bunu yapmanız için timerin içinde led yakmaktan başka birşey yapmayın. Her girişinde sayaç değerini 1 artırsın, tek rakamlarda LOW, çift rakamlarda HIGH yapın.
Özel mesaj okumuyorum, lütfen göndermeyin.

selimkoc

Timer hesabı ve uygulaması olarak blogumda bir çalışma yapmıştım.

https://elektrokod.wordpress.com/2013/10/18/timer0-zamanlama-uygulamasi/

Faydalı olması dileğimle...

Extreme

Kodlarda sıkıntı yok. Neden istediğim görüntü alamadığımı buldum.
(Not negatif olmaya takılmayın %d yerine %u yazmak gerekiyordu)

Nedir timer1 kesmesinin mantığını.

1.Timer1 süresini tamamlamak için timer1 boş döngüsünde beklemek. Bu sayede belirli cycle sürelerinde işlem yapmak.
(Bu madde tamam çalışıyor)

2.Timer1 kesme döngüsünde bir yerlerde tıkanıp kalsa bile 65536 olduğunda timer1 kesme döngüsünü tekrardan başlatmak.
(Bu madde çalışmıyor)


Şimdi bu aşağıdaki kodları denedim tmr1 doğru süreyi veriyor.

yalnız 65536yı geçirirsem bir tur daha atıp devam ediyor.bu her seferinde böyle devam ediyor.Madde 2 yi geçersiz kılmış.

Umarım anlatabilmişimdir.


#include <stdio.h>
#include <stdlib.h>

#define _XTAL_FREQ 10000000

#include <xc.h>
#include "Lcd416.h"

#pragma config FOSC = HS
#pragma config WDTE = OFF      
#pragma config PWRTE = ON      
#pragma config MCLRE = ON     
#pragma config CP = ON
#pragma config CPD = ON     
#pragma config BOREN = OFF     
#pragma config IESO = ON     
#pragma config FCMEN = ON    
#pragma config LVP = OFF        
#pragma config BOR4V = BOR40V
#pragma config WRT = OFF

unsigned int lcdcounter1=1;

void main(void)
{
    
    ANSEL=0;
    ANSELH=0;
    TRISA = 0b00000000;
    TRISB = 0b10011111;
    TRISC = 0b10000000;
    TRISD = 0b00000000;
    RC1=0; RD0=0;  RD1=0; RD2=0; RD3=0; //lcd fazla pinleri
     
    Lcd_Init();
    Lcd_Clear();
    __delay_ms(200);

    PIE1=0b00000001;    
    PIR1bits.TMR1IF=0;  
    INTCON=0b11000000; 
    T1CON=0b00000000;  
    TMR1 = 65000;
    T1CONbits.TMR1ON=1;
    while(1);
 }
void interrupt   kesme  (void)        // interrupt function

{

    TMR1IF=0;
    TMR1 = 65000;
    lcdcounter1=lcdcounter1-1;
    if(lcdcounter1==0)
    {
        Lcd_Clear();
        __delay_ms(2);
        lcdcounter1=100;
        Lcd_Set_Cursor(1,1);
        printf("TIMER1=%u",TMR1);
    }
 }

 

Gökhan BEKEN

İşte bu tür bug'ların saç baş yoldurmasını önlemek için debug yapıyoruz.
Özel mesaj okumuyorum, lütfen göndermeyin.

Extreme

#9
Biraz geç oldu ama yaptığım incelemer sonunda kesinlikle timer1 de bug olmadığını söyleyebilirim.

timer1 kullanmadığımda seri haberleşme stabil olarak çalışıyor.

timer1 kullandığımda çalışmıyor. ( Timer1 kullanmak yerine 0.5 saniye bile gecikme olsa fonksiyonun sonunda çalışmıyor.)

seri haberleşmede bir eksiğim olabilir . Çözemezsem yakında forumda konuyu paylaşırım.

hasankara

#10
Kesme bölümüne ait asm kodlarını paylaşabilirsen eğer inceleyip ona göre daha ayrıntılı bir şeyler söyleyebiliriz. Daha önce dikkat etmedim ama xc8 derleyicisi kesme rutinine girdiğinde GIE bitini temizliyor olabilir ve çıkarken de tekrar açıyor olabilir.

Zaten kesmeye çok bel bağlamazsanız bu tarz sorulara cevap aramak ihtiyacı duymazsınız. Tıpkı meftun un söylediği gibi, ancak yaptırmak istediğiniz işlemin çok kritik kısımlarını kesmede yaptırmayı deneyin.

Mesela son söylediğine benzer olarak; uarttan veri okuyorsun ve karakter geldiği sıra kesme oluşuyor. Kesme içerisinde, gelen karakteri kayıt edip main içerisinde kontrol edilmek üzere kendi belirlediğiniz bir registerin bir bitini set edersiniz, fazlasını yapmazsınız. main içerisinde de lcd e birşeyler yazıp, devamında bu kendi belirlediğiniz biti kontrol ediyorsunuz. Kontrol sonucu olumlu ise yine özel olarak belirlemiş olduğunuz registerin içinde bekleyen karakteri burada değerlendiriyorsunuz ve bu biti tekrar temizliyorsunuz. Yani bir kuyruk sistemi kurmuş oluyorsunuz aslında. Tıpkı hastanelerde, bankalarda sıramatikten fiş almak gibi. Her yeni karakter ise yeni bir müşteri yada hasta gibi. Sıramatik algoritmasını kurmak istersen ayrıca yardım istersin yazı uzamasın diye devam etmeyeyim.

Mesela daha gelişmiş mikrodenetleyicilerde bu anlattığım yapı, uart için bulunuyor. Örnek olarak, donanımsal olarak 8 adet veri kayıt edebilen , uarta özgü fifo yapısı kurulmuş. sen hiç okumasan da yeni alınan veriler fifo de yığılmaya başlıyor ve sen sadece rxreg registerini okuduğun zaman fifo çözülmeye başlıyor, sırasıyla yığılan verileri sana çıkartıyor. Bu özelliğin olmadığı denetleyicilerde kesme ile buna benzer yapılar kurmak mümkün.

not.: düzeltme fifo yerine stack yazmışım.

Extreme

#11
 sorunum hakkında daha net bilgiler vermeye calisicam.Daha fazla bilgi gerekiyorsa ilgili bölümleri paylaşabilirim.
Kodları en sade haline getirmeye calistim.

--Öncelikle şunu belirtiyim ki kodlar timer1 olmadan calisiyor. fakat timer1 bana çok gerekli. çünkü belirli cycle larda hassas işlemler yapıyoruz.
--asm ve xc8 kodları aynı sonuçları veriyor. bunda sıkıntı yok. özzelikle asm kodlar yıllardır bu şekilde sorunsuz kullanılıyor. fakat timer1 bypass edilmiş gibi gözüküyor.
--Kodları gönderen pice "master" kodları alan pice "slave" ismini verelim. aşağıda slave kodları var.
--Masterda kodları yollayan bölüm
BTFSS	PIR1,TXIF 	;
			GOTO		sona_git
         goto  veri_gönder

--timer1 taşmasını bekleme süresi seri haberleşmeyi çok olumsuz etkiliyor. durmadan oerr hatası alıyor.

    while(1)
    {
         //timer1 taşmasını bekle
    }



Tespit1: timer1 kapalı. normal yazılımda 5ms gibi bir gecikme olursa calismiyor.
Tespit2:  timer1 kapalı. sonsuz döngüde herhangi bir gecikme yok sağlıklı calisiyor.
Tespit3:  timer1 açık timer1 değeri fark etmiyor. timer1 kesme fonksiyonu sonunda "PIR1bits.TMR1IF = 0; kod satırı yazılmazsa çalışıyor. çünkü timer1 by pass ediyor..


#define _XTAL_FREQ 10000000

//Headers
#include <pic18f4620.h>
#include <pic18.h>
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "18F_420Lcdv12.h"
#include "18FConfig.h"

//Variables
unsigned int lcdsayac=1;
unsigned int lcddisplay=0;
unsigned int lcddisplay2=0;

unsigned char MenuTimer=0;
signed char Menu=0;
bit     EepromFlag=0;
bit     MenuFlag=0;
bit     lcdclear=0;
bit     ComErrorFlag=0;

unsigned char Enter=0;
signed char Down=0;

//Serial com variables
unsigned char Rx_reg=0;
unsigned char Tx_reg=0;
unsigned char SerialFlag=0;

unsigned int InputVolt_1=0;
unsigned char Fr_digit1_1=0;

unsigned long True8=0;
unsigned long False8=0;
unsigned long errorFERR=0;
unsigned long errorOERR=0;
unsigned long errorRCIF=0;

unsigned long comerrorcounter=0;

void main(void)
{
    __delay_us(10);
    TRISA = 0b00000000;
    TRISB = 0b10011111;
    TRISC = 0b10000000;
    TRISD = 0b00000000;
    TRISE = 0b00000000;

    ADCON1 = 0x0F;  //deactivate A-D conveter
    CMCON = 0x07;   //deactivate comparator module
    INTCON2bits.RBPU=1; //portb pull-ups disabled.

    LATA=0x00;
    LATB=0x00;
    LATC=0x00;
    LATD=0x00;
    LATE=0x00;

    LATC5=1;

    Lcd_Init();
    Lcd_Clear();
    __delay_ms(10);

    //Serial Com Settings
    SPBRG=64;
    TXSTA=0b00100010;
    RCSTA=0b10010000;

    //Timer 1 Settings
    PIE1=0b00000001;  //Only Enables timer1 overflow interrupt
    PIR1bits.TMR1IF=0;  // TMR1 register did not overflow
    INTCON=0b11000000;  // Enables all unmasked interrupts
    T1CON=0b00000000;

    TMR1ON=1;  
    TMR1 = 40000;
    while(1)
    {
         //timer1 taşmasını bekle
    }

}


void LcdWrite(void)
{
    lcdsayac=lcdsayac-1;
    if(lcdsayac==0)
    {lcdsayac=5;  

    Lcd_Set_Cursor(1,1);
    printf("8Pc=%4u",True8);
    Lcd_Set_Cursor(2,1);
    printf("8Fc=%4u",False8);
    break;

    Lcd_Set_Cursor(3,1);
    if(ComErrorFlag==0){printf("Rx=%2u",Rx_reg);}
    else                        { printf("Error Code: 001");}
}

void SerialCom(void)
{
   if(RCIF==0)
     {
         comerrorcounter++;if(comerrorcounter==5000){comerrorcounter=1000;}
         errorRCIF++; goto SerFinished;
     }
    if(FERR==1){z=RCREG; errorFERR++; goto SerFinished;}
    if(OERR==1){CREN=0;__delay_us(1);CREN=1;errorOERR++; goto SerFinished;}
    RCIF=0;
    {
        Rx_reg++;
        switch(Rx_reg)
        {
                case 1:
                    InputVolt_1=RCREG;
                    if(InputVolt_1==21){comerrorcounter=0;} else{Rx_reg--;}
                    break;

                case 2:
                    Fr_digit1_1=RCREG;
                    if(Fr_digit1_1==28){True8=True8+1;}    else{False8=False8+1;}
                    break;
    }

            SerFinished:

       if(ComErrorFlag==0)
 {if(comerrorcounter>=1000){lcdclear=1; ComErrorFlag=1;}}

       if(ComErrorFlag==1)
 {if(comerrorcounter<1000){lcdclear=1; ComErrorFlag=0;}}
}

void interrupt isr(void)
 {
     if (PIR1bits.TMR1IF && PIE1bits.TMR1IE) {
    TMR1 = 40000;
    SerialCom();
    LcdWrite();
   PIR1bits.TMR1IF = 0;//burasi olursa gecikmeye yol açtığı için seri haberleşme calismiyor.
     }
}

hasankara

Öncelikle çok ayrıntılı bakamadım ama genel olarak baktığımda; denetleyici asıl zamanlarını boş geçiriyor ve kesme olduğu anda bir anda yoğun bir şekilde çalışmaya başlıyor. Lcd içerisindeki printf komutları, zaten orası da ölü zamanlarla dolu. Tüm sene boyunca sınavlara çalışmayıp sınav gecesi yoruldum deyip sabaha kadar çay molası vermek benzetimini yapabiliriz.

Çok basit bir hamle olarak lcd e bir şeyler yazma kısmını main içinde sonsuz döngü içerisine alıp sonuçları gözlemleyebilirsiniz. illede sırasına uygun olsun diyorsan da bit kontrollü yap. interrupt içinde bit set edilsin, main içinde bit kontrol edilsin set konumunda ise clear edilip lcd yazdırmaya başlansın. bit senin belirlediğin bir değişken aslında.

Bu arada asm kodundan kastım c derleyicisinin çıktı olarak verdiği asm kodları idi. Anladığım kadarı ile asm de ayrıca yazılmış ve sen o yazılan kodlardan bir kısmını paylaştın. Mplabx kullanıyorsan, window/output/dissassembly listing file a tıklayarak asm çıktısını görebilirsin. tabi asm symbol çıktısı aktif değil ise pencerede uyarı mesajı verir.

Yada main içerisinde kontrol et yeni veri gelip gelmediğini. Sonuç olarak main i boş bırakma. Böyle bir şeye neden ihtiyacın olduğunu bilmediğimden dolayı da net bir şey de söyleyemiyorum.

Extreme

#13
Hocam şöyle söyliyim kodları neden istediğimi anlatsam çok ayrıntılı olur. belirli şeyler yüzünden zamanı kontrol ediyoruz.

Şu kesinki timer1 ve seri haberleşme birlikte çalışmalı.

sadece seri haberleşmeyi sorunsuz çalıştıyorum.

timer1 + seri haberleşme calismiyor.


Aslında açık ve net timer1 main loopda olan gecikme seri haberleşmede oerr hatasına yol açıyor.


Az önce paylaştığım kodlar yetersiz gibi sanırım bir kaç güne sadece haberleşme rutinlerinin ve timer rutinlerinin olduğu blokları paylaşacağım

eeprom,lcd,buton,led v.s. iptal ederek yayınlıyorum hem ticari olduğu için hemde kafamız daha fazla karışmaması adına.


Kabil ATICI

Bu kadar bilgi ile belki yaptığım hatalı bir tespit ama kullandığınız serinin bu iş için uygun olmadığını düşünüyorum.
Buradaki sıkıntı 2 tane kesme aynı anda gelirse veya bir kesmede iken 2. kesme gelirse ne olur sorusuna cevap veremeyen bir yapı.
Programın geri kalanını görmedim, belki  daha fazla kesme var.
ambar7