![]() |
|||||||
Home |
This chapter describes how the software of my PIC IR Decoders works.
You can safely skip this chapter if you're not interested in the software's internals, though I do think reading this chapter might be educational for the assembly language novices.
It goes without saying that the software is written in my own SB-Assembler, which can be downloaded from this same site if you want to make alterations to the software. There is no need for the assembler if you only want to use the programs as they are, because all HEX files are included in the download package.
First of all let's make a list of all the tasks the software has to perform:
All these tasks are to be performed simultaneously, at least they should appear to be.
The first task is obvious, we need to receive and decode the IR messages because that's what we're here for.
Receiving IR signals is a time critical process and may not be disturbed by other tasks.
There is only one main program loop, which is a good start for most of our microprocessor adventures. We enter this main program loop right after initializing the machine and we'll stay there for ever, and ever, and ever, and ever..... Until the power is removed from the system. ;-----------------------------------------------------------------------------
;
; Main program loop
;
;-----------------------------------------------------------------------------
MAIN
;-----------------------------------------CALL THE IR RECEIVER STATE MACHINE--
CALL IR_MACHINE Call the IR receiver state machine
;-----------------------------------------------------SCAN DISPLAY EVERY 5MS--
DECF SCAN_DELAY,F Decrement scan delay counter
BTFSC STATUS,ZERO Only scan display if counter = 0
CALL SCAN_DISP
;-------------------------------------------------------SYNC MAIN WITH TIMER--
.SYNC BTFSC TMR0,7 Wait until bit 7 of TMR = 0
GOTO .SYNC Not 0 yet!
MOVLW TIMER_UPDATE Reload timer again
ADDWF TMR0,F
GOTO MAIN
Most of this snippet are comment lines.
If you delete the comments, there is hardly any code left.
That's good, because we have to be fast to be able to decode all supported protocols.
The first task is to call the IR Decoding routine IR_MACHINE.
Every protocol will get its own IR Decoding routine and will be described later.
Why didn't I use an interrupt driven timer? Simple, because we're in a hurry! An interrupt routine will take about 10 µs extra because of the call, the return and the necessary context switching that are involved. This time can be put to better use in this time critical application. The shortest execution time of the total main loop, excluding the time spent in the subroutines, is 11 micro seconds. The shortest execution time of the IR state machine is 6 µs, which makes a total of 17 µs for the entire loop. The .SYNC routine will eat away the rest of the time to complete the 50 µs. This ensures ample time for the other tasks, which rarely all occur at the same time.
The display is multiplexed, which means that there's only one of the four digits turned on at a given moment. Each digit is turned on for 5 ms, after which it is switched off to allow the other digits some time of their own. Thus the total scan cycle will take 4 x 5 ms = 20 ms, which makes the scan frequency 50 Hz.
The display scan routine is built around a state machine.
A what?
A state machine.
Every time the routine is called it updates a pointer to point to a routine that has to be executed the next time.
That way we execute a total of 4 different routines, one for each of the digits.
;-----------------------------------------------------------------------------
;
; Scan display routine
;
;-----------------------------------------------------------------------------
SCAN_DISP MOVLW MS5_COUNT Reload scan delay
MOVWF SCAN_DELAY
MOVLW %1111.1111 Switch off all Anode drivers
MOVWF PORTA during the switch
MOVF SCAN_STATE,W Jump to next display's routine
MOVWF PCL
The first part of the scan routine is common to all digits.
First of all the scan delay counter is reloaded.
This counter will ensure that the SCAN_DISP routine is called every 5 ms.
;-------------------------------------------------------------SCAN DISPLAY 1--
SCAN_DISP1 MOVF DIGIT1,W Get pattern of left most digit
MOVWF PORTB and send it out
MOVLW %1111.1110 Switch left most digit on
MOVWF PORTA
MOVLW #SCAN_DISP2 Next time do SCAN_DISP2
MOVWF SCAN_STATE
RETURN
I will use SCAN_DISP1 as an example.
The other 3 routines are basically the same.
So the state machine directed us here, which means that digit 1 has to be turned on now.
We simply get the pattern for DIGIT1 and copy it to PORTB, the segment outputs.
Then we drive the anode for digit 1 by loading PORTA with the proper bit pattern.
Finally we set the state machine pointer to the SCAN_DISP2 routine, which will be called the next time we have to scan the display.
I said that the other 3 state routines are basically the same. That is not entirely true because I abused two of them to do some extra tasks. ;-------------------------------------------------------------SCAN DISPLAY 2--
SCAN_DISP2 MOVF DIGIT2,W Get pattern of 2nd left digit
MOVWF PORTB and send it out
MOVLW %1111.1101 Switch 2nd left digit on
MOVWF PORTA
MOVLW #SCAN_DISP3 Next time do SCAN_DISP3
MOVWF SCAN_STATE
DECF DP_DELAY,F Decrement DP_DELAY every 20ms
BTFSS STATUS,ZERO
RETURN We're done if counter <> 0 !
BSF DIGIT2,7 Clear Digit 2's decimal point now
RETURN
SCAN_DISP2 is one of the states which differs slightly. The first 6 instructions should be very familiar to you. Yes they are very similar to the ones found in SCAN_DISP1. It's up to you to point out the 3 differences.
But the fun is at the end of this routine.
There a counter called DP_DELAY is decremented, and every time it reaches $00 bit 7 of DIGIT2 is set.
This piece of code's purpose is to switch off the decimal point that is used to indicate that a good IR message was received.
Remember that was one of the 4 original tasks of the software!
;-------------------------------------------------------------SCAN DISPLAY 4--
SCAN_DISP4 MOVF DIGIT4,W Get pattern of right most digit
MOVWF PORTB and send it out
MOVLW %1111.0111 Switch right most digit on
MOVWF PORTA
MOVLW #SCAN_DISP1 Next time do SCAN_DISP1 again
MOVWF SCAN_STATE
DECF CLR_DELAY,F Decrement CLR_DELAY every 20ms
BTFSS STATUS,ZERO
RETURN We're done if counter <> 0 !
MOVLW %1011.1111 Only display 4 dashes
MOVWF DIGIT1
MOVWF DIGIT2
MOVWF DIGIT3
MOVWF DIGIT4
RETURN
SCAN_DISP3 has no extra's and is identical to the SCAN_DISP1.
But SCAN_DISP4 does have some extra's too.
Again the first 6 instructions are similar to the ones found in SCAN_DISP1.
|