Требуется программист в Зеленограде
- обработка данных с датчиков; ColdFire; 40 тыс. e-mail:jobsmp@pochta.ru |
.CR 16CXXX Use the PIC 16CXXX cross (16F84)
.TF PIC-NEC.HEX,INT
;-----------------------------------------------------------------------------
; Special function file register definition
;-----------------------------------------------------------------------------
INDF .EQ $00 Indirect register
TMR0 .EQ $01 Timer 0 value
PCL .EQ $02 Lower order 8 bits of PC
STATUS .EQ $03 Status flag register
FSR .EQ $04 File select register
PORTA .EQ $05 I/O port A
PORTB .EQ $06 I/O port B
EEDATA .EQ $08 EEPROM data register
EEADR .EQ $09 EEPROM address register
PCLATCH .EQ $0A Upper 5 bits of PC
INTCON .EQ $0B Interrupt control
OPTION .EQ $81 Option flag register
TRISA .EQ $85 Output direction register A
TRISB .EQ $86 Output direction register B
EECON1 .EQ $88 EEPROM control register 1
EECON2 .EQ $89 EEPROM control register 2
;-----------------------------------------------------------------------------
; Special function bit location definition
;-----------------------------------------------------------------------------
; STATUS register
CARRY .EQ 0 Carry flag
DCARRY .EQ 1 Decimal carry flag
ZERO .EQ 2 Zero flag
PD .EQ 3 Inverted power down bit
TO .EQ 4 Inverted time out bit
RP0 .EQ 5 Register bank pointer 0
RP1 .EQ 6 Register bank pointer 1
IRP .EQ 7 Indirect register bank pointer
; OPTION register
PS0 .EQ 0 Pre-scaler value 0
PS1 .EQ 1 Pre-scaler value 1
PS2 .EQ 2 Pre-scaler value 2
PSA .EQ 3 Pre-scaler assign bit
T0SE .EQ 4 Timer 0 source edge select bit
T0CS .EQ 5 Timer 0 clock source select bit
INTEDG .EQ 6 Interrupt edge select bit
RBPU .EQ 7 Port B pull up enable bit
; INTCON register
RBIF .EQ 0 RB port change interrupt flag bit
INTF .EQ 1 External interrupt flag bit
T0IF .EQ 2 Timer 0 overflow interrupt flag bit
RBIE .EQ 3 RB port change interrupt enable bit
INTE .EQ 4 INT interrupt enable bit
T0IE .EQ 5 Timer 0 interrupt enable bit
EEIE .EQ 6 EE write complete interrupt enable bit
GIE .EQ 7 Global interrupt enable bit
;-----------------------------------------------------------------------------
; File register declarations
;-----------------------------------------------------------------------------
SCAN_STATE .EQ $0C Scan state pointer
DIGIT1 .EQ $0D Pattern of left most digit
DIGIT2 .EQ $0E
DIGIT3 .EQ $0F
DIGIT4 .EQ $10 Pattern of right most digit
SCAN_DELAY .EQ $11 Scan delay counter (5ms pace)
CLR_DELAY .EQ $12 Display clear delay counter
DP_DELAY .EQ $13 Decimal point delay counter
IR_STATE .EQ $14 IR receiver state machine
BIT_TIMER .EQ $15 Bit timer
IR_SHIFT .EQ $16,$17,$18,$19 IR shift register
;-----------------------------------------------------------------------------
; Constants
;-----------------------------------------------------------------------------
TIMER_UPDATE .EQ -50+3 Timer update value (2 dead cycles)
MS5_COUNT .EQ 100 Number of counts to 5ms
CLR_TIME .EQ 100 Display clear timeout (20ms/count)
DP_TIME .EQ 3 Decimal point timeout (20ms/count)
BIT_TIME .EQ 1100/50 Basic bit time in 50us units
PULSE_MAX .EQ 650/50 Maximum pulse width
;-----------------------------------------------------------------------------
; Reset vector
;-----------------------------------------------------------------------------
RESET GOTO INIT Get the system going
;-----------------------------------------------------------------------------
; Segment patterns
;-----------------------------------------------------------------------------
HEX2SEGMENTS ANDLW %0000.1111 Use only lower nibble
ADDWF PCL,F Add offset to current PC
SEGMENTS RETLW %1100.0000 0
RETLW %1111.1001 1
RETLW %1010.0100 2
RETLW %1011.0000 3
RETLW %1001.1001 4
RETLW %1001.0010 5
RETLW %1000.0010 6
RETLW %1111.1000 7
RETLW %1000.0000 8
RETLW %1001.0000 9
RETLW %1000.1000 A
RETLW %1000.0011 B
RETLW %1100.0110 C
RETLW %1010.0001 D
RETLW %1000.0110 E
RETLW %1000.1110 F
;-----------------------------------------------------------------------------
; 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
;-------------------------------------------------------------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
;-------------------------------------------------------------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 DISPLAY 3--
SCAN_DISP3 MOVF DIGIT3,W Get pattern of 2nd right digit
MOVWF PORTB and send it out
MOVLW %1111.1011 Switch 2nd right digit on
MOVWF PORTA
MOVLW #SCAN_DISP4 Next time do SCAN_DISP3
MOVWF SCAN_STATE
RETURN
;-------------------------------------------------------------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
;-----------------------------------------------------------------------------
; IR receiver state machine
;-----------------------------------------------------------------------------
IR_MACHINE MOVF IR_STATE,W Jump to present state
MOVWF PCL
;---------------------------------------STATE 0, WAIT FOR FIRST FALLING EDGE--
IR_STATE_0 BTFSC PORTA,4 Input still high?
RETURN Yes! Nothing to do here
CLRF IR_SHIFT Prepare shift register
CLRF IR_SHIFT+1
CLRF IR_SHIFT+2
MOVLW %1000.0000
MOVWF IR_SHIFT+3
CLRF BIT_TIMER Clear bit timer
MOVLW IR_STATE_1 Next stop is state 1
MOVWF IR_STATE
RETURN
;-------------------------IR STATE 1, LET'S SEE IF THIS IS THE 9MS PRE-PULSE--
IR_STATE_1 INCF BIT_TIMER Increment bit timer
BTFSC PORTA,4 Input still low?
GOTO .HIGH Nope!
MOVLW 9900/50*-1 Longer than 9ms + 10% low?
ADDWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN No, OK!
MOVLW IR_ERROR_0 Wait until input returns high
MOVWF IR_STATE and then start all over again
RETURN
.HIGH MOVLW 8100/50*-1 See if length was at least 9ms - 10%
ADDWF BIT_TIMER,W
BTFSS STATUS,CARRY Carry will be set if it was
GOTO IR_ERROR_1 Exit with error if it wasn't
MOVLW IR_STATE_2 Next stop measure the length of the
MOVWF IR_STATE gap between pre-pulse & message
CLRF BIT_TIMER
RETURN
;--------------------------STATE 2, PRE-PULSE DETECTED, NOW MEASURE GAP TIME--
IR_STATE_2 INCF BIT_TIMER Increment bit timer
BTFSS PORTA,4 Input still high?
GOTO .LOW Nope!
MOVLW 4950/50*-1 Longer than 4.5ms + 10% high?
ADDWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN No, OK!
GOTO IR_ERROR_1 We give up!
RETURN
.LOW MOVLW 3350/50*-1 See if it was a long or short pause
ADDWF BIT_TIMER,W
MOVLW IR_STATE_4 Let's get the message if it was a long
BTFSS STATUS,CARRY one (if Carry is set)
MOVLW IR_STATE_3 It was a short one! It's a repetition!
MOVWF IR_STATE
CLRF BIT_TIMER
RETURN
;----------STATE 3, REPETITION DETECTED, LET'S SEE IF DISPLAY IS STILL VALID--
IR_STATE_3 MOVLW IR_STATE_8 Next state will be 8 anyway, so let's
MOVWF IR_STATE set it now
MOVLW %1011.1111 See if display time still valid
XORWF DIGIT1,W
BTFSC STATUS,ZERO
RETURN No! Forget about the repetition then
MOVLW CLR_TIME Restart display stimer
MOVWF CLR_DELAY
MOVLW DP_TIME And also flash the DP
MOVWF DP_DELAY
BCF DIGIT2,7
RETURN
;--------------------------------STATE 4, INPUT IS LOW, MUST BE A PULSE THEN--
IR_STATE_4 INCF BIT_TIMER Increment bit timer
BTFSC PORTA,4 Input still low?
GOTO .HIGH No! Pulse is over now.
MOVLW PULSE_MAX See if max pulse width reached
XORWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN Not yet!
MOVLW IR_ERROR_0 Wait until pulse goes high again
MOVWF IR_STATE before accepting new command
RETURN
.HIGH MOVLW IR_STATE_5 Input is now high
MOVWF IR_STATE Next stop is state 2
RETURN
;-------------STATE 5, WAIT FOR PULSE TO GO LOW AGAIN, THEN MEASURE INTERVAL--
IR_STATE_5 INCF BIT_TIMER Increment bit timer
MOVLW BIT_TIME*3 Should we keep waiting?
XORWF BIT_TIMER,W
BTFSC STATUS,ZERO
GOTO IR_ERROR_1 No, we've waited 3 bit times already!
BTFSC PORTA,4
RETURN Keep waiting while input remains high
MOVLW BIT_TIME/2+BIT_TIME*-1 Use 1.5 bit time as threshold
ADDWF BIT_TIMER,W Carry is 1 if more than 1.5 times
RRF IR_SHIFT+3,F Roll carry into result
RRF IR_SHIFT+2,F
RRF IR_SHIFT+1,F
RRF IR_SHIFT,F
CLRF BIT_TIMER Restart bit timer
MOVLW IR_STATE_4 Return to state 1 if not done yet
MOVWF IR_STATE
BTFSS STATUS,CARRY See if we're done
RETURN Not done yet, continue with state 1
MOVLW IR_STATE_6 Message received, but wait 3ms longer
MOVWF IR_STATE to see if nothing follows.
CLRF BIT_TIMER
RETURN
;-------------------STATE 6, RECEIVED MESSAGE, WAIT 3MS TO ENSURE IT WAS NEC--
IR_STATE_6 INCF BIT_TIMER Increment bit timer
BTFSC PORTA,4 Input still low?
GOTO .HIGH No! Pulse is over now.
MOVLW PULSE_MAX See if max pulse width reached
XORWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN Not yet!
MOVLW IR_ERROR_0 Wait until pulse goes high again
MOVWF IR_STATE before accepting new command
RETURN
.HIGH MOVLW IR_STATE_7 Input is now high
MOVWF IR_STATE Continue with 3ms delay
RETURN
;---------------------------STATE 7, INPUT MUST REMAIN HIGH FOR AT LEAST 3MS--
IR_STATE_7 INCF BIT_TIMER Increment bit timer
BTFSS PORTA,4 Has the input gone low now?
GOTO .ERROR Yes! This is not good!
MOVLW BIT_TIME*3 Have we waited long enough now?
XORWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN Not yet!
MOVLW CLR_TIME Set display clear timer
MOVWF CLR_DELAY
MOVLW DP_TIME Flash receive LED
MOVWF DP_DELAY
SWAPF IR_SHIFT,W Work from left to right
CALL HEX2SEGMENTS
MOVWF DIGIT1
MOVF IR_SHIFT,W Do the same with 2nd digit
CALL HEX2SEGMENTS
ANDLW %0111.1111 Flash dot of this digit
MOVWF DIGIT2
SWAPF IR_SHIFT+2,W And with the 3d digit
CALL HEX2SEGMENTS
MOVWF DIGIT3
MOVF IR_SHIFT+2,W And finally with the last digit
CALL HEX2SEGMENTS
MOVWF DIGIT4
MOVF IR_SHIFT,W Compare normal and inserted codes
ADDWF IR_SHIFT+1,F
INCF IR_SHIFT+1,F
MOVF IR_SHIFT+2,W
INCF IR_SHIFT+3,F
ADDWF IR_SHIFT+3,W
IORWF IR_SHIFT+1,W Result should be 0 now!
BTFSS STATUS,ZERO Did the checksum match?
BCF DIGIT4,7 Light right DP if it didn't
MOVLW IR_STATE_0 We're done! Let's get some rest
MOVWF IR_STATE
RETURN
.ERROR MOVLW IR_ERROR_0 Wait until input gets high again
MOVWF IR_STATE before returning to state 0
RETURN
;-------------------------------------STATE 8, WAIT FOR INPUT TO RETURN HIGH--
IR_STATE_8
IR_ERROR_0 MOVLW IR_STATE_0 Reset state machine only if input is
BTFSC PORTA,4 high
MOVWF IR_STATE
RETURN
;-----------------------------------------------------------IR ERROR STATE 1--
IR_ERROR_1 MOVLW IR_STATE_0 Return to IR state 0
MOVWF IR_STATE
RETURN
;-----------------------------------------------------------------------------
; Get started
;-----------------------------------------------------------------------------
INIT MOVLW #$0D Clear memory
MOVWF FSR
MOVLW #35 Clear a total of 36 RAM addresses
MOVWF $0C
.CLRMEM CLRF INDF Clear this address
INCF FSR Increment pointer
DECFSZ $0C Decrement counter
GOTO .CLRMEM Repeat until done
BSF STATUS,RP0 Select bank 1 of register file
MOVLW #%1101.1111 Timer mode without pre-scaler
MOVWF OPTION
MOVLW #%0001.0000 Only PA4 is an input
MOVWF TRISA
MOVLW #%0000.0000 All Port B are outputs
MOVWF TRISB
BCF STATUS,RP0 Select bank 0 of register file
MOVLW #%0000.0000 Disable all interrupts
MOVWF INTCON
MOVLW IR_STATE_0 Init IR receiver state machine
MOVWF IR_STATE
MOVLW #SCAN_DISP1 Init display scan state
MOVWF SCAN_STATE
CLRF PCLATCH All indirect jumps are on page 0!
MOVLW TIMER_UPDATE Get the timer started
MOVWF TMR0
MOVLW MS5_COUNT Start 5ms counter for display scan
MOVWF SCAN_DELAY
MOVLW %1010.1011 Show NEC on display
MOVWF DIGIT1
MOVLW %1000.0110
MOVWF DIGIT2
MOVLW %1010.0111
MOVWF DIGIT3
MOVLW %1111.1111
MOVWF DIGIT4
MOVLW 200 Set clear time-out to 4 seconds
MOVWF CLR_DELAY
;-----------------------------------------------------------------------------
; 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
;-----------------------------------------------------------------------------
; Configuration word
;-----------------------------------------------------------------------------
.OR $2007
.CW XT
; .LI OFF