Picproje Elektronik Sitesi

DERLEYİCİLER => Microchip XC Serisi => Microchip XC8 => Konuyu başlatan: Extreme - 21 Aralık 2014, 09:58:06

Başlık: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Extreme - 21 Aralık 2014, 09:58:06
Merhaba Forum üyeleri.

Seri haberleşme ve timer1 kesmesini birlikte kullanmam gerekiyor. Bu kesin ve net ve 2 pic içinde timer süresi değiştirilmemesi gerekiyor. bunlar belirlendi.

tüm programda tek kesme timer1 ve Diğer komutlar bunları kesinlikle etkileyemez. ben test ettim. Tüm programda yer alan diğer bloklar buton,led,lcd, eeprom v.s.

Aklınıda bu şüphe kalmasın.

Seri haberleşmeyi sorunsuz kullanabiliyorum. Timer1 taşma bitini sıfırlamayıp bypass edersem. yada timer1siz kodları yazarsam aynı şey farketmez.

Fakat timer1 kesmesi içinde kullanmam gerektiğinde tamamen hatalı sonuçlar alıyorum. Durmadan oerr hatası alıyor.

İlgili bölümün kodlarını yayınlıyorum.  Çözüm için tecrübeli arkadaşların önerilerini bekliyorum.



Master.asm >> kodları yollayan bölüm (16f887)

slave.c >> kodları alan bölüm (18f4620)


master.asm



  LIST   P=PIC16F887
              include "p16f887.inc"
errorlevel -302

__CONFIG _CONFIG1, _HS_OSC & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOR_OFF & _IESO_ON & _FCMEN_ON & _LVP_OFF

__CONFIG _CONFIG2, _BOR40V & _WRT_OFF

DelayCounter1 EQU    0x28
DelayCounter2 EQU    0x29
DelayCounter3 EQU    0x2A
w_temp EQU    0x2B
status_temp EQU    0x2C
pclath_temp EQU    0x2D
serial_reg EQU    0x2F
DEVICE_STATUS  EQU    0x30

;DEVICE_STATUS
serial_control EQU    0x00

;**********************************************************************
;*****      Program Baslangici   ****
;**********************************************************************
   ORG     0x0000        ; processor reset vector
  GOTO    baslangic          ; go to beginning of program
;**********************************************************************
;*****   Interrupt bölümü *****
;**********************************************************************
ORG      0x0004             ; interrupt vector location
MOVWF    w_temp             ; copy w to temp register
MOVF   STATUS,w           ; move status to be saved into W
    CLRF    STATUS          ; Bank0, reagardless of current bank, Clears IRP,RP0,RP1
MOVWF   status_temp        ; save status to bank 0 register
MOVF    PCLATH,w           ; only required if using pages 1, 2 or 3
MOVWF    pclath_temp        ; save pclath
CLRF    PCLATH          ; page 0
;***** Interrupt rutini baslangici  *****
BANKSEL PIR1
BCF      PIR1,TMR1IF       ; interrupt flagını temizle
MOVLW    0xFC
MOVWF    TMR1H             ;Set timer 1 to 312,5us timeout period (315,6)
MOVLW    0xFD
MOVWF    TMR1L
;=======================================================================
BTFSS PIR1,TXIF ;test if TXREG empty
GOTO serial_out1

BTFSC serial_reg,7
GOTO veri_gonder_7

veri_gonder_0;giris
BTFSC serial_reg,0
GOTO veri_gonder_1
MOVLW D'21'
MOVWF TXREG
BSF     serial_reg,0
GOTO serial_out1
veri_gonder_1
BTFSC serial_reg,1
GOTO veri_gonder_2
MOVLW D'22'
MOVWF TXREG
BSF     serial_reg,1
GOTO serial_out1
veri_gonder_2
BTFSC serial_reg,2
GOTO veri_gonder_3
MOVLW D'23'
MOVWF TXREG
BSF     serial_reg,2
GOTO serial_out1
veri_gonder_3
BTFSC serial_reg,3
GOTO veri_gonder_4
MOVLW D'24'
MOVWF TXREG
BSF serial_reg,3
GOTO serial_out1
veri_gonder_4
BTFSC serial_reg,4
GOTO veri_gonder_5
MOVLW D'25'
MOVWF TXREG
BSF     serial_reg,4
GOTO serial_out1
veri_gonder_5
BTFSC serial_reg,5
GOTO veri_gonder_6
MOVLW D'26'
MOVWF TXREG
BSF serial_reg,5
GOTO serial_out1
veri_gonder_6
BTFSC serial_reg,6
GOTO veri_gonder_7
MOVLW D'27'
MOVWF TXREG
MOVLW B'10000000'
MOVWF serial_reg
GOTO serial_out1
veri_gonder_7
BTFSC serial_reg,0
GOTO veri_gonder_8
MOVLW D'28'
MOVWF TXREG
BSF     serial_reg,0
GOTO serial_out1
veri_gonder_8
BTFSC serial_reg,1
GOTO veri_gonder_9
MOVLW D'29'
MOVWF TXREG
BSF serial_reg,1
GOTO serial_out1
veri_gonder_9
BTFSC serial_reg,2
GOTO veri_gonder_10
MOVLW D'30'
MOVWF TXREG
BSF serial_reg,2
GOTO serial_out1
veri_gonder_10
BTFSC serial_reg,3
GOTO veri_gonder_11
MOVLW D'31'
MOVWF TXREG
BSF serial_reg,3
GOTO serial_out1
veri_gonder_11
BTFSC serial_reg,4
GOTO veri_gonder_12
MOVLW D'32'
MOVWF TXREG
BSF serial_reg,4
GOTO serial_out1
veri_gonder_12
BTFSC serial_reg,5
GOTO veri_gonder_13
MOVLW D'33'
MOVWF TXREG
BSF serial_reg,5
GOTO serial_out1
veri_gonder_13
BTFSC serial_reg,6
GOTO veri_gonder_14
MOVLW D'34'
MOVWF TXREG
BSF serial_reg,6
GOTO serial_out1
veri_gonder_14
BCF DEVICE_STATUS,serial_control
CLRF serial_reg
serial_out1
interrupt_sonu
;=====================  Interrupt rutini sonu =========================
;======================================================================
    BANKSEL pclath_temp ;1,8us
MOVF    pclath_temp,w      ; restore pclath
MOVWF   PCLATH             ;
    MOVF    status_temp,w    ; to set to original bank state
MOVWF   STATUS             ; restore STATUS
MOVF    w_temp,w           ; restore pre-isr W register contents
RETFIE   
baslangic
;PORT SETUP ===========================================================

BANKSEL ANSEL
MOVLW   B'00000000'      ;All digital IO
MOVWF   ANSEL 

    BANKSEL ANSELH
MOVLW   B'00000000'      ;All digital IO
MOVWF   ANSELH 

BANKSEL PORTA
CLRF PORTA

BANKSEL TRISA
MOVLW B'00000000'
MOVWF   TRISA             ;port A all input
    MOVLW    B'00000000'       ;
    MOVWF   TRISB
MOVLW   B'10000000'       ;
MOVWF   TRISC
MOVLW   B'0000000'       ;
MOVWF   TRISD
MOVLW   B'00000000'       ;
MOVWF   TRISE

BANKSEL PORTA
CLRF PORTA



;REGISTER SETUP ===========================================================
BANKSEL OPTION_REG
MOVLW   B'11011111'    ;Ext int on rising edge
MOVWF   OPTION_REG   ;prescaler assigned to WDT,rate 1:8 8*18ms=144ms

BANKSEL WPUB
MOVLW   B'00000000'      ;weak pull-ups enabled.
MOVWF   WPUB   

BANKSEL IOCB
MOVLW   B'00000000'      ;No Any INTERRUPT-ON-CHANGE PORTB REGISTER
MOVWF   IOCB       

BANKSEL PIE1
    MOVLW    B'00000001'       ;timer1 enabled
MOVWF PIE1

BANKSEL PIR1
    BCF      PIR1,TMR1IF       ;CLR timer1 interrupt flag

BANKSEL INTCON
MOVLW    B'11000000'       ;General int enable and Peripheral int enable
    MOVWF    INTCON

BANKSEL PCON
MOVLW    B'00000000'       ;Ultra Low-Power Wake-up,BOR,Power-on Reset,Brown-out Reset disabled
    MOVWF    PCON

BANKSEL T1CON
    MOVLW B'00000000' ;1/1 prescaler value
    MOVWF T1CON
   
BANKSEL SPBRG
MOVLW D'64' ;2400 baudrate
MOVWF SPBRG

BANKSEL SPBRGH
MOVLW D'0' ;2400 baudrate
MOVWF SPBRGH

BANKSEL TXSTA
MOVLW    B'10100010'       ;2400 baud transmitter ready
    MOVWF    TXSTA

    BANKSEL RCSTA
    MOVLW    B'10010000'       ;2400 baud receiver ready
    MOVWF    RCSTA
   
BCF DEVICE_STATUS,serial_control

CLRF serial_reg
CLRF PORTA
CLRF PORTB

CALL bekle_100ms
;SETUP TIMER1 ========================================================
MOVLW    0xFC
    MOVWF    TMR1H            ;Set timer 1 to (0,3084ms) timeout period
  MOVLW    0xFD
MOVWF    TMR1L
BSF      T1CON,0          ;Timer1'i çalistir
;MAIN PROGRAM LOOP ===================================================
TIMER1_RB0_INT_BEKLE
NOP
NOP
NOP
GOTO TIMER1_RB0_INT_BEKLE
;=====================================================================

bekle_100ms
movlw 0x03
movwf DelayCounter1
movlw 0x18
movwf DelayCounter2
movlw 0x02
movwf DelayCounter3
Delay_0
decfsz DelayCounter1, f
goto $+2
decfsz DelayCounter2, f
goto $+2
decfsz DelayCounter3, f
goto Delay_0

;3 cycles
goto $+1
nop
RETURN
;========================



slave.c (seri haberleşme + timer ) == çalışmıyor

#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 char z=0;

unsigned char GelenVeri1=0;
unsigned char GelenVeri2=0;
unsigned char GelenVeri3=0;
unsigned char GelenVeri4=0;
unsigned char GelenVeri5=0;
unsigned char GelenVeri6=0;
unsigned char GelenVeri7=0;
unsigned char GelenVeri8=0;
unsigned char GelenVeri9=0;
unsigned char GelenVeri10=0;
unsigned char GelenVeri11=0;
unsigned char GelenVeri12=0;
unsigned char GelenVeri13=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;

    //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;  //T?MER1 AKT?F ET
    TMR1 = 40000;


    while(1)
    {
        __delay_us(2);
        __delay_us(2);
        __delay_us(2);
    }

}


void interrupt isr(void)
{
     if (PIR1bits.TMR1IF && PIE1bits.TMR1IE)
     {
    TMR1 = 40000;
    if(RCIF==0){ goto SerFinished;}
    if(FERR==1){z=RCREG; goto SerFinished;}
    if(OERR==1){CREN=0;__delay_us(1);CREN=1; goto SerFinished;}   

        Rx_reg++;
           switch(Rx_reg)
        {
                case 1:
                    GelenVeri1=RCREG;
                    break;

                case 2:
                    GelenVeri2=RCREG;
                    break;

                case 3:
                    GelenVeri3=RCREG;
                    break;

                case 4:
                    GelenVeri4=RCREG;

                    break;

                case 5:
                    GelenVeri5=RCREG;
                    break;

                case 6:
                    GelenVeri6=RCREG;
                    break;

                case 7:
                    GelenVeri7=RCREG;
                    break;

                case 8:
                    GelenVeri8=RCREG;
                    break;

                case 9:
                   GelenVeri9=RCREG;
                    break;

                case 10:
                    GelenVeri10=RCREG;
                    break;

                case 11:
                    GelenVeri11=RCREG;
                    break;

                case 12:
                    GelenVeri12=RCREG;
                    break;

                case 13:
                    GelenVeri13=RCREG;
                    break;

                case 14:
                    GelenVeri14=RCREG;
                    Rx_reg=0;
                    break;
        }

    PIR1bits.TMR1IF = 0; // bu satiri silersem timer1 bypass edilip seri haberleşme sorunsuz çalışıyor !
     }
}
Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: hasankara - 21 Aralık 2014, 10:20:56
timer1 kesmeye girene kadar defalarca veri geliyormuş ki sende oerr hatası alıyorsun. timer1 ile bir süre belirleyip verinin gelip gelmediğini o sıklıkta kontrol etmek istiyorsun ama sen önceki veriyi RCREG den okumadan yeni bir veri gelirse denetleyici oerr hatası verir. yani sen sadece RCREG sfr sini okuduğunda uart modülü bunu fark ediyor sonraki veri geldiğinde oerr vermiyor.

çözüm önerileri; 1. uart kesmesini kullanman, yada 2. timer1 kesme süresini kısaltman, yada 3. iletişim hızını düşürmen, yada 4. veri kayıpları önemsizse main içerisinde rutin olarak RCREG in içeriğini başka bir registere eşitlemen.
Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Extreme - 21 Aralık 2014, 11:38:31
yorumunuz için teşekkürler hasan hocam.

çözüm cevaplarım
1_bu yöntemi bilmiyorum araştırıyorum. elinizde kod bloku varsa timer1 + usart kesmesi gibi bir kod paylaşırmısınız

2_kısalttım master.asm ile aynı yaptım. tüm döngüleri bu süreye göre tasarladım taşmaması için. sonuç biraz daha pozitif ama oerr hataları ferr hataları var.

3_zaten çok yavaş kullanıyoruz 2400 . ama denedim pozitif sonuç yok.

4_veri kayıpları önemli . denedim pozitif sonuç yok.

Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Tagli - 21 Aralık 2014, 12:05:16
Diğer başlıkta da bahsetmiştim ama tekrar sorayım:

Ben hala seri port kesme kodunu göremiyorum. Ana kesme kodu içinde sadece TMR1 kesmesi var gibi.

Bir yerlerde (if (PIR1bits.TMR1IF && PIE1bits.TMR1IE) ile aynı seviyede) benzer şekilde if (RCIF && RCIE) gibi bir blok olması gerekiyor.
Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Extreme - 21 Aralık 2014, 12:28:24
Gökçe hocam,

RCIF kodunun bir olduğuna bakıyor ama RCIE bakmıyor.

RCIF=1 ise seri haberleşmeye devam ediyor, RCIF=0 ise devam etmiyor.

...
Sizin dediğiniz gibi uygulayarak. aslında tersden yaazarak ikisinden biri sıfır ise sona git komutuyla.

if(RCIF==0) olan satırı if((RCIF==0)||(RCIE==0)) yaptım fakat bu seferde hep haberleşmeyi kesti.


Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Tagli - 21 Aralık 2014, 15:14:26
İyi de sen bu şartı timer kesmesi kodunun içinde kontrol ediyorsun. Diyelim ki seri port kesmesi önce geldi. Ortada timer kesmesi yok, gelmemiş henüz. O zaman zaten gelen byte'ı işleme alamayacak ki.

void interrupt isr(void) {
    if (PIR1bits.TMR1IF && PIE1bits.TMR1IE) {
        // Gereğini yap
    }
    if (RCIF && RCIE) {
        //Gereğini yap
    }
}



Yukarıdaki gibi olmalı.
Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Extreme - 21 Aralık 2014, 20:31:35
void interrupt isr(void) {
    if (PIR1bits.TMR1IF && PIE1bits.TMR1IE) {
        // Gereğini yap
      TMR1IF=0;
    }
    if (RCIF && RCIE) {
        //Gereğini yap
      RCIF=0;
    }
}


Tam olarak böyle mi gökçe hocam ?

net olarak sonuç verdi. fakat timer1 iki katdan biraz fazlaca yavaşdı.

Mantık yürütürsek bence RCIF alma sırasında timer1 de yavaşlamaya yol açıyor. biri bitmeden diğerine geçmiyor gibi düşünüyorum.

Kodlar yukarıdaki gibidir.
Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Tagli - 21 Aralık 2014, 20:59:00
Doğru, bir kesmenin işi bitmeden diğerine geçemez. Bu sebeple, kesmede elini çabuk tutup kısa sürede çıkman gerekir. Bir başka mesajımda, seri port kesmesinde gelen veriyi tampon belleğe atma önerimin sebebi de buydu. Yani kesme sadece veriyi çekip başka bir yere depolayacak. Depolanan verinin işlenmesi ana programın işi olacak.

Timer kesmesi de yukarıda anlattığım mantıkla kullanılabilir. Ayrıca, son olarak bahsettiğin sorunun sebebi tahminimce timer'ın ön yükleme değeri ile (40000) kullanıyor olman. Bu sebeple, timer kesmesine giriş gecikince, hassasiyet de sapıyor. Bu şekilde bir kullanımı önermem.

Timer ile ilgili yapılabilecek iki şey var:

Birincisi, timer1'i tam değeri ile (65535) ile kullan, yani önyükleme yapma. Prescaler ve postscaler'i öyle bir ayarla ki yaklaşık olarak senin istediğin zamanda taşsın. Zamanı tam tutturman mümkün değil ama timer'ı kendine uyduramıyorsan sen ona uyacaksın mecburen. Örneğin sen 40000'den başlatıyorsun. demek ki kabaca 25000 sayıyor. Prescaler ve postscaler ile uygun şekilde oynayarak bu 25000 saymayı mesela 65536/2'ye indirebilirsin. Bu durumda elbette süre uzar, atıyorum 100 ms yerine 130 ms bekleme yaparsın.

İkinci seçenek timer2 kullanman. Bunun taşma değerini yani son sınırını PR2 ile ayarlayabiliyorsun. Böylece önyükleme kullanmadan hassas zamanlama yapabilirsin.Ama bu timer'ın özellikleri işini görür mü bilmiyorum.

16 bit PIC'lerde tüm timer'larda taşma değeri belirlenebiliyor. Bu önemli bir özellik.

Şimdi aklıma gelen bir üçüncü seçenek ise şu: Yine önyükleme yapacağız ama sabit bir sayı ile değil. Timer kesmesi başında timer değerine bakacağız. Örneğin 3500. O halde 40000 değil 43500 yükleyeceğiz. Ama bence yine de pek sağlıklı bir yöntem değil. Önyükleme olayını genel olarak sevmiyorum ve tehlikeli buluyorum.
Başlık: Ynt: Timer1 kesmesi ve Seri Haberleşme
Gönderen: Extreme - 26 Aralık 2014, 09:32:51
Bilgilendirme için teşekkürler gökçe hocam,

ilk kullandığım yöntemden performans olarak daha doğru sonuçlar aldım.

Şimdilik onu kullanmaya devam edeceğim.