Timer1 kesmesi ve Seri Haberleşme

Başlatan Extreme, 21 Aralık 2014, 09:58:06

Extreme

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 !
     }
}

hasankara

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.

Extreme

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.


Tagli

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.
Gökçe Tağlıoğlu

Extreme

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.



Tagli

İ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ı.
Gökçe Tağlıoğlu

Extreme

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.

Tagli

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.
Gökçe Tağlıoğlu

Extreme

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.