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 !
}
}
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.
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.
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 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.
İ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ı.
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.
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.
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.