![]() |
|||||
Home |
The Philips RC-5 protocol allows control over 32 different devices with 64 different commands per device.
Later this protocol was extended to RC-5X, which allows up to 128 different commands per device.
Therefore I had to decide to show the IR messages in hexadecimal values, after all we've got only 4 digits on the display.
A particular property of the RC-5 protocol is its Toggle bit.
This bit will change polarity every time you press a key and will remain unchanged as long as you hold the key.
That enables the receiver to detect released keys, which helps eliminate key bounces.
In my knowledge base you can read that the RC-5 protocol uses bi-phase modulation of the IR carrier to transmit a total of 14 bits. A bi-phase modulated bit can be thought of as two separate bits which are always the inverse of each other. A logical zero is represented by a "01" pattern on the IR input, while a logical one is represented by a "10" pattern. That is basically what we're going to use to decode the received message.
The IR decoding software relies on a state machine.
We've seen a state machine in action in the main software where it was used to multiplex the displays, so we are a bit familiar with it already.
Here we use the power of the state machine to break down the entire problem of decoding an IR signal into a few well defined states.
Each state has only a limited amount of decisions to make, which greatly simplifies the decoding of the IR signal.
;-----------------------------------------------------------------------------
;
; IR receiver state machine
;
;-----------------------------------------------------------------------------
IR_MACHINE MOVF IR_STATE,W Jump to present state
MOVWF PCL
Here we go!
The IR_MACHINE routine is called every 50 µs by the main program loop.
This reasonable accurate interval can be used to time our steps along the decoding process.
;---------------------------------------STATE 0, WAIT FOR BEGIN OF START BIT--
IR_STATE_0 BTFSC PORTA,4 Input still high?
RETURN Yes! Nothing to do
MOVLW HALF_TIME/2-1 Wait until we're in the center of the
MOVWF BIT_TIMER start pulse
MOVLW IR_STATE_1 Next stop is state 1
MOVWF IR_STATE
RETURN
IR_STATE_0 is called whenever the IR decoder is idle, which means that we are waiting for the start of a new message.
This start is signalled by a falling edge on the IR input at PORTA bit 4.
So, as long as PORTA pin 4 remains high, there is nothing for us to do but return to the main program loop.
;---------------------------STATE 1, START BIT DETECTED, CHECK IF IT IS REAL--
IR_STATE_1 DECFSZ BIT_TIMER Wait until center of start pulse
RETURN Time's not up yet!
BTFSC PORTA,4 Is the input still low?
GOTO IR_ERROR_1 Nope! Exit with error
MOVLW HALF_TIME Set interval to the center of the
MOVWF BIT_TIMER first half of the next bit
MOVLW %0000.1000 Prepare the shift register
MOVWF IR_SHIFT
CLRF IR_SHIFT+1
MOVLW IR_STATE_2 Prepare for next stop
MOVWF IR_STATE
RETURN
At this state we've detected a falling edge on the IR input, and now we want te be sure that it is a valid starting pulse.
We decrement BIT_TIMER until it has reached 0, which brings us right in the center of the starting pulse.
There is nothing for us to do as long as BIT_TIMER hasn't reached 0, so we simply return to the main program loop.
If the start bit was valid we set BIT_TIMER to half a bit time, which will be right in the center of the first half of the first real bit.
Then the shift register is prepared.
This shift register will hold the complete IR message after receiving a total of 26 half-bits or 13 real bits.
Remember that the start bit has already past us at this stage, so there are only 13 bits of the message left to be handled.
;-----------------------------------IR STATE 2, WAIT FOR FIRST HALF OF A BIT--
IR_STATE_2 DECFSZ BIT_TIMER Wait until center of first half of bit
RETURN Keep waiting!
MOVLW IR_STATE_3 Next state is 3 if input is high
BTFSS PORTA,4
MOVLW IR_STATE_4 Input is low, next state is 4
MOVWF IR_STATE
MOVLW HALF_TIME Restart bit timer
MOVWF BIT_TIMER
RETURN
We're waiting for the the center of the first half of a bit when we enter this state.
The BIT_TIMER is decremented until 0 again.
We may return to the main program loop if BIT_TIMER hasn't reached 0 yet.
;---------------IR STATE 3, FIRST HALF WAS HIGH NOW IT MUST BE LOW FOR A "1"--
IR_STATE_3 DECFSZ BIT_TIMER Wait until center of 2nd half of bit
RETURN Keep waiting!
BTFSC PORTA,4 Is input high now?
GOTO .ERROR Nope! It's an error!
BSF STATUS,CARRY A 1 was received, shift it in result
RLF IR_SHIFT,F
RLF IR_SHIFT+1,F
MOVLW HALF_TIME Restart bit timer
MOVWF BIT_TIMER
MOVLW IR_STATE_2 In case we need some more bits
BTFSC STATUS,CARRY We're done when Carry is 1
MOVLW IR_STATE_5 Carry is 1, received entire message
MOVWF IR_STATE
RETURN
.ERROR MOVLW IR_ERROR_0 Wait until input gets high before
MOVWF IR_STATE returning to state 0
RETURN
I think you already know what the first two lines of this state are for because we've seen them twice before.
Then we check the IR input which must be high now, because it was low during IR_STATE_2!
If it is not we change the state machine to IR_ERROR_0, where we will wait until the IR input is high again before we can reset the state machine to IR_STATE_0 and start all over again.
;---------------IR STATE 4, FIRST HALF WAS LOW NOW IT MUST BE HIGH FOR A "0"--
IR_STATE_4 DECFSZ BIT_TIMER Wait until center of 2nd half of bit
RETURN Keep waiting!
BTFSS PORTA,4 Is input high now?
GOTO IR_ERROR_1 Nope! It's an error!
BCF STATUS,CARRY A 0 was received, shift it in result
RLF IR_SHIFT,F
RLF IR_SHIFT+1,F
MOVLW HALF_TIME Restart bit timer
MOVWF BIT_TIMER
MOVLW IR_STATE_2 In case we need some more bits
BTFSC STATUS,CARRY We're done when Carry is 1
MOVLW IR_STATE_5 Carry is 1, received entire message
MOVWF IR_STATE
RETURN
IR_STATE_4 is almost identical to IR_STATE_3.
The main differences are the expected polarity of the IR input and the polarity of the received bit.
This time the IR input must be high to be valid, in which case we received a "0" bit.
;--------------------------IR STATE 5, MESSAGE RECEIVED, START PROCESSING IT--
IR_STATE_5 MOVLW CLR_TIME Set display clear timer
MOVWF CLR_DELAY
MOVLW DP_TIME Flash receive LED
MOVWF DP_DELAY
MOVF IR_SHIFT,W Get IR command
ANDLW %0011.1111 The command is only 6 bits wide
BTFSS IR_SHIFT+1,4 Copy inverted extended bit to b6 of
IORLW %0100.0000 command
RLF IR_SHIFT,F Shift the entire IR address in
RLF IR_SHIFT+1,F 2nd byte of shift register
RLF IR_SHIFT,F
RLF IR_SHIFT+1,F
MOVWF IR_SHIFT Save cleaned up hex IR command number
MOVLW IR_STATE_6 We've done enough in this state
MOVWF IR_STATE Let's do the rest in state 6
RETURN
We have received the complete IR message now, but we're not done yet.
The message must be made presentable for those stupid humans, who are not too good at reading binary data.
;------------------------------IR STATE 6, CONVERT HEX MESSAGE TO 7 SEGMENTS--
IR_STATE_6 SWAPF IR_SHIFT+1,W Work from left to right
ANDLW %0000.0001 Address is only 5 bits wide
CALL HEX2SEGMENTS
MOVWF DIGIT1
MOVF IR_SHIFT+1,W Do the same with 2nd digit
CALL HEX2SEGMENTS
ANDLW %0111.1111 Flash dot of this digit
MOVWF DIGIT2
SWAPF IR_SHIFT,W And with the 3d digit
CALL HEX2SEGMENTS
MOVWF DIGIT3
MOVF IR_SHIFT,W And finally with the last digit
CALL HEX2SEGMENTS
BTFSC IR_SHIFT+1,5 Was the T bit set?
ANDLW %0111.1111 Light the dot of this digit if it was
MOVWF DIGIT4
MOVLW IR_STATE_7 Done enough for now. Let's finish it
MOVWF IR_STATE in the last state
RETURN
We're almost done.
IR_SHIFT+1 holds the received IR address at this point, while IR_SHIFT holds the received IR command.
All we need to do now is convert these 2 hex values to 4 seven segment patterns and we can call it a day.
;----------------------------------IR STATE 7, WAIT FOR INPUT TO RETURN HIGH--
IR_STATE_7
IR_ERROR_0 MOVLW IR_STATE_0 Reset state machine only if input is
BTFSC PORTA,4 high
MOVWF IR_STATE
RETURN
IR_STATE_7 and IR_ERROR_0 are handled by the same routine. The purpose of this state is to wait for the IR input to return high before the state machine can be reset to IR_STATE_0. ;-----------------------------------------------------------IR ERROR STATE 1--
IR_ERROR_1 MOVLW IR_STATE_0 Return to IR state 0
MOVWF IR_STATE
RETURN
This is not a state of the IR_MACHINE. We arrive here because one of the states has detected an error while the IR input was high. Because the IR input is already high it is OK te reset the state machine to IR_STATE_0 to start all over again. |