|
|
View previous topic :: View next topic |
Author |
Message |
kara_kalem
Joined: 15 Oct 2006 Posts: 1
|
sony ir receiver |
Posted: Sat Jul 04, 2009 3:35 am |
|
|
Code: | /
#include <16f877.h> // Kullanılacak denetleyicinin başlık dosyası tanıtılıyor.
// Denetleyici konfigürasyon ayarları
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000) // Gecikme fonksiyonu için kullanılacak osilatör frekansı belirtiliyor.
#use fast_io(a) //Port yönlendirme komutları A portu için geçerli
#use fast_io(c) //Port yönlendirme komutları C portu için geçerli
#include<lcd.c>
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
#ignore_warnings none
#zero_ram
/* TIMER0 configuration */
#define TIMER0_CONFIG RTCC_INTERNAL | RTCC_DIV_1
/* Interrupt rate: */
/* 4/32000000*65536*1 = 8.192 ms */
/* 4/4000000*65536*1 = 65,53 ms */
/* Start: 3.0 ms (ignored) */
/* "1": 1.8 ms (1800) */
/* "0": 1.2 ms (1200) */
#define one_min 1675 //no of counts to safely detect bit1
#define one_max 1925 //optimal @4 MHz is 1800
#define zero_min 1075 //no of counts to safely detect bit0
#define zero_max 1325
/* irframes[0] (start) will be garbage, ignore it... */
int16 irframes[13];
int8 ircount = 0;
int1 irdone = FALSE;
#int_ext
void ext_isr() {
if (irdone) return;
irframes[ircount++] = get_timer0();
if (ircount >= 13)
irdone = TRUE;
ircount++;
set_timer0(0);
enable_interrupts(INT_TIMER0);
}
#int_timer0
void timer0_isr() {
disable_interrupts(INT_TIMER0);
}
#separate
int1 decode_ir(int8 &addr, int8 &cmd) {
int8 i;
int8 mask;
int8 bits[13];
addr = 0;
cmd = 0;
for (i=1; i<=12; i++) {
if ((ONE_MIN <= irframes[i]) && (irframes[i] <= ONE_MAX))
bits[i] = 0x01;
else
if ((ZERO_MIN <= irframes[i]) && (irframes[i] <= ZERO_MAX))
bits[i] = 0x00;
else // Error
return FALSE;
}
mask = 0x01;
for (i=1; i<=7; i++) {
if (bits[i])
cmd = cmd | mask;
mask <<= 1;
}
mask = 0x01;
for (i=8; i<=12; i++) {
if (bits[i])
addr = addr | mask;
mask <<= 1;
}
return TRUE;
}
void start_ir() {
memset(irframes, 0x00, sizeof(irframes));
ircount = 0;
irdone = FALSE;
set_timer0(0); //++
}
/********* ANA PROGRAM FONKSİYONU********/
void main ( )
{
int duty;
int8 addr, cmd;
int1 ok;
delay_ms(100);
set_tris_c(0b11111011); // PIN_C2 used for the LED
setup_spi(FALSE);
//set_tris_a(0x03); // RA0 ve RA1 pinleri giriş
set_tris_c(0x00); // C portu komple çıkış
lcd_init();
output_bit(PIN_C2, 0);
delay_ms(100);
lcd_putc("\fWaiting...");
setup_psp(PSP_DISABLED); // PSP birimi devre dışı
setup_spi(SPI_SS_DISABLED); // SPI birimi devre dışı
setup_adc_ports(NO_ANALOGS); // ANALOG giriş yok
setup_adc(ADC_OFF); // ADC birimi devre dışı
setup_timer_1(T1_DISABLED);
setup_timer_0(TIMER0_CONFIG);
setup_timer_2(T2_DISABLED, 255, 1);
ext_int_edge(0, L_TO_H);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
start_ir();
//#ignore_warnings 203
while(TRUE) {
//#ignore_warnings NONE
if (irdone) {
ok = decode_ir(addr, cmd);
printf(lcd_putc, "\fCmd %3u\nAddr %3u", cmd, addr);
if (!ok)
lcd_putc(" ERROR");
else
output_bit(PIN_C2, 1);
delay_ms(50);
output_bit(PIN_C2, 0);
start_ir();
}
}
} |
i use in my project 16f877 and 4Mhz crystal, but i think wrong some think at TIMER0's timing. Can any one help me? |
|
|
Ttelmah Guest
|
|
Posted: Sat Jul 04, 2009 4:45 am |
|
|
Several comments:
First, after setting the interrupt edge, and _before_ enabling the interrupt, _clear_ INT_EXT. Whenever you change the active edge on an interrupt, it can result in the interrupt being set. This is in the data sheet.
Second, why on earth are you enabling int_timer0?. This just potentially results in a 'wasted' call to the timer handler.... You are not using timer0, as an interrupt at all, but just as a counter, to 'time' the period from one edge to the next.
The third problem is that you increment ircount, _twice_ in each ISR... This is a killer.
Then you have the problem of timing. It takes _time_ to get into the ISR. perhaps 30 counts of timer0. Then it takes time to write the value to an array (perhaps another 20 instructions). The test a few more instructions. When you set timer0, back to zero, you are effectively losing, perhaps 30+ counts from the time between the edges.
Better, to clear timer0, _once_ on the first edge. Then just record it's values. Even better, use the CCP, to allow the value on the timer to be accurately recorded, at the moment the edge goes high.
Your code really needs to ensure the IR line _is_ low, before starting counting edges, or it'll never resynchronise if an edge is missed. You could even use the timer interrupt, as a 'timeout'.
A search here will find posts about using an interrupt flag, without using an interrupt handler, as a faster way of performing this type of handling.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|