Hello,

I have a technical question about PULSIN, any advice would be welcome.

I'm using a routine to get an IR signal.

The hardware is:

On the sending side: a PIC16F684 where RA5 is used as PWM output at 40KHz with a 30% duty cycle (code below). The pin is connected to a BC182L NPN general purpose transistor with the adequate resistor for the transistor. A TSAL6100 940 nm IR led is powered by 5V (from a 5V voltage regulator) with the appropriate current limiter resistor to have 1.6V at 100 mA.

On the receiving side: a PIC16F684. One input pin is connected to the DATA lead of a TSOP4840 infrared receiver-demodulator at 40KHz carrier.
When a signal is received it triggers an int on the receiver and the signal is decoded.
I'm using PULSIN to check the bits of 14 bits that are sent MSB to LSB
There is a header that is 2400 Us pulse (so it *pulls down* the pin which is default high with internal WPU!).
I use a loop to bypass the header that the pulsin wouldn't read anyway as it is already started when I get to the int handler.
A '1' bit is 1200 Us pulse and a '0' bot is a 600 Us pulse. Each bit is prefixed with a 600 Us pause.

When I read the PULSIN values stores in an array of 14 words I should normaly, for a 8 MHz internal oscillator (a 5Us resolution) have:

For a '0' bit I should have a lenght of 600/5 (=120) and for a '1' bit I should have a length of 1200/5 (=240).
I notice that the values for a '1' range from 221 to 266 while values for a '0' range from 109 to 153. Why is that so??????

Why?
Why??
Why???

I can imagine I may not have exacly either 120 or 240 values but such variation is very difficult to understand. It needs to be more accurate. How can I improve this?
Is this related to PULSIN or is it my hardware? Is this related to the duty cycle?

Snippet for settings for the PWM:

Code:


'*******************************************************************************
'PWM (single output mode) related registers for porta.5

T2CON = %00000100			'value:4, 1:1 postscale (unused), Timer2 is ON, Timer 2 Clock prescaler = 1
PR2 = %00110001			'value: 49, PWM Period: 40.0KHz
CCP1CON = %00000000		'capture/compare/PWM module OFF, no pwm signal on portc.5 at this time
CCPR1L = %00001111		'value: 15, PWM Duty Cycle 8 MSB of 10 bits (2 LSB in bits 5 and 4 of CCP1CON), total: 60d
'*******************************************************************************


OSCCON = %01110001
CMCON0 =  %00000111			'comparators OFF, val = 7
ANSEL = %00000000			'choose digital i/o, val = 0

OPTION_REG = %01111111 			'enable porta weak pullups (no weak pull-up available for porta.3), p12

The routine that gets the signal and decodes it:

Code:
area = 255

IF (PORTA.0 == 0) THEN
    FOR i = 0 to 15                     'get a sequence of incoming 16 bits (WITHOUT their prefixes which are 600us pause)
        PULSIN PORTA.0,0,ir_pulse[i]    ' Read 16 low-going pulses on RA.4, see pbp manual
    NEXT i
    area = 0                              ' Loop 16 times, record in 5us resolution pulse duration in the word variables array
    GOTO decode
ENDIF

IF (PORTA.1 == 0) THEN
    FOR i = 0 to 15                     'get a sequence of incoming 16 bits (WITHOUT their prefixes which are 600us pause)
        PULSIN PORTA.1,0,ir_pulse[i]    ' Read 16 low-going pulses on RA.4, see pbp manual
    NEXT i
    area = 1                              ' Loop 16 times, record in 5us resolution pulse duration in the word variables array
    GOTO decode
ENDIF

IF (PORTA.2 == 0) THEN
    FOR i = 0 to 15                     'get a sequence of incoming 16 bits (WITHOUT their prefixes which are 600us pause)
        PULSIN PORTA.2,0,ir_pulse[i]    ' Read 16 low-going pulses on RA.4, see pbp manual
    NEXT i
    area = 2                              ' Loop 16 times, record in 5us resolution pulse duration in the word variables array
    GOTO decode
ENDIF

IF (PORTA.3 == 0) THEN
    FOR i = 0 to 15                     'get a sequence of incoming 16 bits (WITHOUT their prefixes which are 600us pause)
        PULSIN PORTA.3,0,ir_pulse[i]    ' Read 16 low-going pulses on RA.4, see pbp manual
    NEXT i
    area = 3                              ' Loop 16 times, record in 5us resolution pulse duration in the word variables array
    GOTO decode
ENDIF

IF (PORTA.4 == 0) THEN
    FOR i = 0 to 15                     'get a sequence of incoming 16 bits (WITHOUT their prefixes which are 600us pause)
        PULSIN PORTA.4,0,ir_pulse[i]    ' Read 16 low-going pulses on RA.4, see pbp manual
    NEXT i
    area = 4                              ' Loop 16 times, record in 5us resolution pulse duration in the word variables array
    GOTO decode
ENDIF

IF (PORTA.5 == 1) THEN
    area = 5
    GOTO bypass
ENDIF

'--- ELSE ---
GOTO bypass      'invalid, area = 255
'------------


decode:


'databyte = $FF                    ' Start with all 1's and find each 0

'Ranges for LOW bit: 109 to 153
'Ranges for HIGH BIT: 221 to 266
'header length: 118 to 122

'we scan the words array we stored from MSB to LSB
databyte = 0  '%0000000000000000
FOR i = 0 TO 13                     ' Get 14 "data" bits
    LCDOUT $fe,1,#i,":",#ir_pulse[i]
    PAUSE 2000

    IF ((ir_pulse[i] < 275) && (ir_pulse[i] > 210)) THEN       '240*5us resolution at 8MHz = 1200 us  (usual length of a zero is about 127 - 145 and 242 to 266 fore a one)
        databyte.0(15-i) = 1               'clear the bit
        goto slip           'bypass
    ENDIF 
    IF ((ir_pulse[i] < 160) && (ir_pulse[i] > 105)) THEN       '240*5us resolution at 8MHz = 1200 us  (usual length of a zero is about 127 - 145 and 242 to 266 fore a one)
        databyte.0(15-i) = 0               'clear the bit
        GOTO slip           'bypass
    ENDIF
    LCDOUT $fe,1,#i,"!",#ir_pulse[i]
    PAUSE 2000
    GOTO bypass 'if any other value, abort
    slip:
NEXT i
'we fill "databyte" from MSB to LSB

The code that sends the IR signal:

Code:


'HEADER:

    'LCDOUT $fe,1,"header"
    'PAUSE 2000

    'HIGH PORTC.5
    CCP1CON = 12
    PAUSEus 2400				'HIGH pulse, 2400 uS on RC5, PWM
    CCP1CON = 0
    'LOW PORTC.5

'DATA:

    'LCDOUT $fe,1,"1stByte"
    'PAUSE 2000

'first byte, %00000000 (MT2 compatible)

firstbyte = %00000000

For i = 0 to 7          'send only 6 MSb
    pauseus 600     'bit prefix
    CCP1CON = 12
    PAUSEus 600      'min 600 us pause
    CCP1CON = 0
NEXT i

'second byte, example: %00|1110|-- (56) is for 75% dammages


    'LCDOUT $fe,1,"2ndByte"
    'PAUSE 2000

For i = 0 to 5          'send only 6 MSb
    pauseus 600     'bit prefix
    CCP1CON = 12
    IF (dammages.0(7-i) == 1) THEN
        PAUSEus 1200
    ELSE
        PAUSEUS 600
    ENDIF
    CCP1CON = 0
NEXT i