As an excercise I'm trying to write some code which uses a timing based method to detect the start bit of the NEC IR protcol.
The approach I have taken is to detect the pin going low and count how many chunks (counts) of 50us delays happens before the pin goes high again.
To detect the desired 9ms low pulse (before the 4.5ms space) I'm throwing out counts <8ms or >10ms
Heres the code snippet (the bottom half of the function is trimmed):
short read_data(void)
{
unsigned uint8_t count, i;
count = 0;
// Check 9ms pulse (remote control sends logic high, pin goes low).
while((RB4 == 0) && (count < 200))
{
count++;
__delay_us(50);
}
// Is initial low pulse <8ms or >10ms?
if( (count > 199) || (count < 160))
return 0; // Exit, not NEC protocol.
When I placed a breakpoint at the if statement, I noticed that the value for count was way out, it was 92 instead of approx 180 as it should be. I was using a 1Mhz clock at the time. I changed the clock speed to 8Mhz and noticed I captured a different result (163). This allowed the code to pass the check but was stlll approx 1ms out.
I then did some testing and tried every clock speed the PIC (PIC16F87) could run at and recorded the results:
_XTAL_FREQ OSCON speed count
--------------------------------------------------------------
31250 0x00000000 31.25 Khz 5
125000 0b00010000 125 Khz 20
250000 0b00100000 250 Khz 35
500000 0b00110000 500 Khz 60
1000000 0b01000000 1 Mhz 92
2000000 0b01010000 2 Mhz 121
4000000 0b01100000 4 Mhz 146
8000000 0b01110000 8 Mhz 163
I was under the impression that the _XTAL_FREQ macro would adjust __delay_us() call but it does seem like the error is coming from some kind of timing issue.
For more precision I tried changing the "chunk" size to 10us and the boundaries to >800 <1000, centering on a value of 900 but at 8Mhz I got a result of 485 [EDIT: I changed the uint8_t to uint16_t to cope with the higher number]. The IR demodulator is behaving correctly as the attached trace shows. I'm a bit stumped now and any ideas would be welcome.