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.
(http://s3.postimg.cc/qyd60ns33/image.jpg) (http://postimg.cc/image/qyd60ns33/)
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{}
}
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
}
}
Hocam aslında hepsi aynı gibi.
(http://s28.postimg.cc/70vonpfc9/image.jpg) (http://postimg.cc/image/70vonpfc9/)
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;
}
}
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.
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.
(http://s7.postimg.cc/zcgqjxmvr/image.jpg) (http://postimg.cc/image/zcgqjxmvr/)
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.
Timer hesabı ve uygulaması olarak blogumda bir çalışma yapmıştım.
https://elektrokod.wordpress.com/2013/10/18/timer0-zamanlama-uygulamasi/ (https://elektrokod.wordpress.com/2013/10/18/timer0-zamanlama-uygulamasi/)
Faydalı olması dileğimle...
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);
}
}
İşte bu tür bug'ların saç baş yoldurmasını önlemek için debug yapıyoruz.
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.
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.
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.
}
}
Ö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.
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.
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.
Mesajları ayrıntılı olarak okumadan üstünkörü göz attım sadece. Anladığım kadarıyla seri iletişim (alma) kesme kullanılmadan yapılıyor, yani bir döngü içinde veri gelip gelmediği kontrol ediliyor (galiba kesme bayrağına bakılarak). Doğru anlamış mıyım?
Eğer durum böyle ise ilk iş bunun düzeltilmesi gerekir. Seri port üzerinden gelen veriyi kesme kullanmadan yakalamaya çalışmak yanlış bir yaklaşım. Gelen veri kesme tarafından bir tampon belleğe atılmalı ve gerektiğinde oradan çekilmeli.
Olayı yanlış anlamışsam bu mesajı yok sayabilirsiniz.
@ambar7 hocama katılıyorum, kesme rutunindeyken, başka bir kesme daha gelirse yeni gelen kesmeyi kaçırıyor. Çünkü interrupt önceliği yok bu seride. Bu yüzden timer1 ile seriport birlikte kullanılırsa illaki kaçırılan veriler olacaktır.
İlgili bölümün tüm kodlarını yayınladım.
tüm programda tek kesme timer1 bunu rahatlıkla söyleyebilirim. Diğer komutlar bunları kesinlikle etkileyemiyor. ben test ettim. onlar buton,led,lcd, eeprom v.s.
Tecrübeli arkadaşların yardımlarını bekliyorum.
https://www.picproje.org/index.php?topic=56853.msg437343#msg437343 (https://www.picproje.org/index.php?topic=56853.msg437343#msg437343)
Öğrenci arkadaşlarda seri haberleşme rutinlerini gönül rahatlığıyla kullanabilir.