;******************************************
;* 2 in 1 SPEEDO-ODO-METER PIC 16F873 *
;******************************************
;=====================================================================================
; 10 MHz quartz crystal
; sensor 6 pulses per meter
list p=16F873
#include
__config _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF
; constants
RCSwitch equ 1 ; RC1
RCPower equ 0 ; RC0
RCButton equ 3 ; RA3
RCPoint equ 4 ; RA4
; variables
; Number of active segment
INDNO equ 0x20
; Buffer display odometer digits in the form of combinations of segments
IND01 equ 0x21
IND02 equ 0x22
IND03 equ 0x23
IND04 equ 0x24
IND05 equ 0x25
IND06 equ 0x26
; Speedometer display buffer
INDS1 equ 0x27
INDS2 equ 0x28
INDS3 equ 0x29
; the main counter of the total range
tot_prev equ 0x2A
tor_k001 equ 0x2B
tot_k010 equ 0x2C
tot_k100 equ 0x2D
tot_001k equ 0x2E
tot_010k equ 0x2F
tot_100k equ 0x30
tot_001t equ 0x31
tot_010t equ 0x32
tot_100t equ 0x33
; an additional daily run counter
aux_prev equ 0x34
aux_k001 equ 0x35
aux_k010 equ 0x36
aux_k100 equ 0x37
aux_001k equ 0x38
aux_010k equ 0x39
aux_100k equ 0x3A
IPM equ 0x3B
SCR_MODE equ 0x3C
BTN_MODE equ 0x3D
BTN_CNTR equ 0x3E
BTN_STAT equ 0x3F
cntr2 equ 0x40
iHCNT equ 0x41
iLCNT equ 0x42
cHCNT equ 0x43
cLCNT equ 0x44
PreDIG equ 0x45
EspDIG equ 0x46
DspDIG equ 0x47
HspDIG equ 0x48
; BTN_MODE - describes what happened to the button
; 00 - the button is located at the top
; 01 - push (move down)
; 11 - at the bottom
; 10 - drop (move up)
; SCR_MODE - specifies the procedure FILL_VB, than fill the video buffer
; 0 - total range of
; 1 - daily
; 2 - empty
; 3 - the word RESET
; program
org 0x00
goto START
; recoding digits in the code 7-segment display
SEG7 ; in the counters is not the value itself, and (10 value)
sublw d'010' ; calculated value of
andlw 0x0F ; just in case
addwf PCL,f
; ebfdacg zero bit in the segment lights
retlw b'00000011' ; 0
retlw b'10111011' ; 1
retlw b'00100101' ; 2
retlw b'10100001' ; 3
retlw b'10011001' ; 4
retlw b'11000001' ; 5
retlw b'01000001' ; 6
retlw b'10110011' ; 7
retlw b'00000001' ; 8
retlw b'10000001' ; 9
retlw b'11110111' ; 10
retlw b'10111111' ; 11
retlw b'11111011' ; 12
retlw b'11101111' ; 13
retlw b'01111111' ; 14
retlw b'11011111' ; 15
; enable calculation of the bit level to the number of active anode
ANOD_C
andlw 0x07 ;just in case
addwf PCL,f
; 123465 unit at the bit level lights
retlw b'00000000' ; 0
retlw b'10000000' ; 1
retlw b'01000000' ; 2
retlw b'00100000' ; 3
retlw b'00010000' ; 4
retlw b'00000100' ; 5
retlw b'00001000' ; 6
retlw b'00000000' ; 7
; enable calculation of the bit level to the number of active anode
ANOD_A
andlw 0x03 ;just in case
addwf PCL,f
; 321 unit in the category of 1 bit of lights and hundreds of dozens of 2-3-units
retlw b'00010000' ; 0
retlw b'00010001' ; 1
retlw b'00010010' ; 2
retlw b'00010100' ; 3
START
bcf STATUS, RP0 ; bank 0
bcf STATUS, RP1
clrf T2CON
clrf TMR0
clrf TMR2
clrf INTCON
clrf PORTA
clrf PORTB
clrf PORTC
bsf STATUS, RP0 ; bank 1
movlw 0x06 ; And on all legs tsirfu??????
movwf ADCON1
movlw b'00001000'
movwf TRISA ; RA3 - button, the rest of the output
movlw b'00000001'
movwf TRISB ; RB0 - sensor, the other output
movlw b'00000001'
movwf TRISC ; RC0 - ignition, the other output
; include pull-up resistors, TMR0 to the internal clock with prescaler 16 (4 ms in the figure)
movlw b'01000011'
movwf OPTION_REG
; include TIMER2
clrf PIE1
movlw d'249' ; with quartz 10 mhz system??? clock = Fosc/4 = 2,5 MHz, 0.4 ms
movwf PR2 ; period register TIMER2 = 250 clock = 100 microseconds per cycle
; cycle = 100 ms * 1(PRE) * 1 (POST) = 100 ms
bcf STATUS,RP0 ; bank 0
movlw b'00000100' ; none:7 (POST-1):6-3 On/Off:2 PRE: 1-0
movwf T2CON ; b0000 = 1:1 1=On b00 = 1
clrf PIR1
bsf PORTC, RCSwitch
call READ_EEPROM
movlw d'10'
movwf HspDIG
movwf DspDIG
movwf EspDIG
; ***
movlw 1 ; was 8
movwf PreDIG
movlw 9
movwf INDNO
clrf TMR0
bcf INTCON,T0IF ; reset the timer
call PROLOG
clrf BTN_MODE
clrf SCR_MODE
call FILL_VB
call FILL_SPD
; ***
movlw d'23' ; was d'37 'to 30 pulses / m
movwf iHCNT
; ***
movlw d'112' ; was d'128 'for 30 pulses / m
movwf iLCNT
clrf cHCNT
movlw 1
movwf cLCNT
MAIN_LOOP
; check the power
btfss PORTC,RCPower; Off we go around, if 1
goto PowerDown
PowerRise
; dimensional check the timer
btfsc PIR1,TMR2IF ; if 0 (no signal from TIMER2), by bypassing
call DO_TICK ; and if 1, then go to increase the counter
; check the sensor
btfsc INTCON,INTF ; if 0 (no signal from the sensor), from the bypass
call DO_INCR ; and if 1, then go to increase the counter
; duplicate the state of the sensor
; btfsc PORTB,0
; bsf PORTA,5
; btfss PORTB,0
; bcf PORTA,5
; check the timer for dynamic display
btfss INTCON,T0IF ; If the timer has finished counting, you're going to change the discharge
goto MAIN_LOOP ; otherwise, repeat the test in a loop
; anything below is executed 1 time 1.6 ms (at 10MHz)
call ChkButton ; treatment of buttons
call ChAnod ; switch the indicator bits
bcf INTCON,T0IF ; reset the timer
goto MAIN_LOOP
; check button, and respond
ChkButton
rlf BTN_MODE,f ; each time BTN_MODE shift by 1 bit to the left
bcf BTN_MODE,0 ; and Write the bits
btfss PORTA, RCButton ; 0, if the button at the top
bsf BTN_MODE,0 ; 1, if the bottom
movf BTN_MODE,w ; then cut out the lower two bits
andlw 3 ; and from them select the treatment option
addwf PCL,f ;
goto Btn_UpUp ; 00 - button has been and remains at the top (always depressed)
goto Btn_UpDn ; 01 - moved from the top down (pressed)
goto Btn_DnUp ; 10 - moved from the bottom up (released)
goto Btn_DnDn ; 11 - has been and remains at the bottom (always pressed)
Btn_UpDn ; CLICK
clrf BTN_CNTR ; when you click
clrf BTN_STAT ; zero out counters retention time
goto Btn_UpUp
Btn_DnDn ; HOLD continue to increase the counter
incfsz BTN_CNTR,f ; when the counter reached the count of 256 (0.4 seconds)
goto TestSTATUS
incf BTN_STAT,f ; reactions modify the code to lift buttons
TestSTATUS ; depending on the retention time
btfss BTN_STAT,2 ; 0, 1 , 2, 3 (0.4 to 0.8 to 1.2 to 1.6 sec)
goto Btn_UpUp
decf BTN_STAT,f ; if the code has reached 4, then return it to the three
bsf SCR_MODE,1 ; change the display mode data in the display
call FILL_VB ; Now for the WHOLE screen NOTHING
goto Btn_UpUp ; for daily on-screen word RESET
Btn_DnUp ; RELEASED
btfss SCR_MODE,1 ; if there was a short jab
goto SwitchMode ; we're going to switch the display mode
TestReset
bcf SCR_MODE,1 ; Kicks for a long???
btfss SCR_MODE,0 ; returned to normal operating mode indicator FULL / DAILY
goto ODOmode
movf IPM,w ; and for the daily addition
movwf aux_prev ; did reset discharges 000.00
movlw d'10'
movwf aux_100k
movwf aux_010k
movwf aux_001k
movwf aux_k100
movwf aux_k010
movwf aux_k001
goto ODOmode
SwitchMode ; switching mode indicator FULL / DAILY
movlw 1
xorwf SCR_MODE,f
ODOmode ; restoration of the buffer indicator
call FILL_VB
Btn_UpUp ; if the button is always on top, there's nothing else to do
return
FILL_SPD ; portable numbers skrosti??? previous measurement in the video buffer
movf HspDIG,w
call SEG7 ; the output of hundreds of
movwf INDS1 ;
movf DspDIG,w
call SEG7 ; withdrawal of tens of
movwf INDS2
movf EspDIG,w ; output units are always
call SEG7
movwf INDS3
call CLR_LEAD0 ; repay the zeros
return
; filling the video buffer code segments
FILL_VB
movfw SCR_MODE ; choose than to fill the buffer indicator
andlw b'00000011' ; depending on the value of SRC_MODE
addwf PCL,f
goto Fill_ODOM
goto Fill_TRIP
goto Fill_NONE
goto Fill_TEXT
Fill_ODOM ; fill the buffer
movfw tot_100t ; figures the total range
call SEG7
movwf IND01
movfw tot_010t
call SEG7
movwf IND02
movfw tot_001t
call SEG7
movwf IND03
movfw tot_100k
call SEG7
movwf IND04
movfw tot_010k
call SEG7
movwf IND05
movfw tot_001k
call SEG7
movwf IND06
return
Fill_TRIP ; numbers of daily run
movlw b'11111111' ; significant bit of the dark
movwf IND01
movfw aux_100k
call SEG7
movwf IND02
movfw aux_010k
call SEG7
movwf IND03
movfw aux_001k
call SEG7
movwf IND04
movfw aux_k100
call SEG7
movwf IND05
movfw aux_k010
call SEG7
movwf IND06
bcf IND04,0 ; put a sign "point of need" for the second discharge
return
Fill_TEXT ; the word RESET
; ebfdacg zero lights
movlw b'11111111'
movwf IND01
movlw b'01000111' ; С?
movwf IND02
movlw b'01000001' ; B?
movwf IND03
movlw b'00010101' ; Р?
movwf IND04
movlw b'00000011' ; 0?
movwf IND05
movlw b'01000111' ; С?
movwf IND06
return
Fill_NONE ; put out all the bits
movlw b'11111111' ; a prolonged retention
movwf IND01 ; button in the full path
movwf IND02
movwf IND03
movwf IND04
movwf IND05
movwf IND06
return
ChAnod
;Service indication (after each complete cycle of the reference clock 1.6 ms x 6 bits = 100 Hz)
movlw IND01-1
movwf FSR
movlw 0x03
andwf PORTC,f ; switched off discharge
movlw 0xF8
andwf PORTA,f
bsf PORTA, RCPoint
movlw 9 ; calculation of the numbers next level
decfsz INDNO,f ; cyclically
movfw INDNO ; 9 8 7 6 5 4 3 2 1 and around 9 8 7 6 5 ...
movwf INDNO
addwf FSR,f ; load combination of cathodes
movfw INDF ; to the next level
movwf PORTB
movfw INDNO
sublw 6
btfss STATUS,C
goto ANOD_SPD
btfss INDF,0 ; if the sign of "point of need" is reset, then turn round
bcf PORTA, RCPoint ; including the point
movfw INDNO
call ANOD_C
iorwf PORTC,f ; include the following anode discharge
return
ANOD_SPD
call ANOD_A
iorwf PORTA,f ; include the following anode discharge
return
; came from the tick timer dimensional (was 100 ms)
DO_TICK
bcf PIR1,TMR2IF ; reset the interrupt flag
decfsz cLCNT,f
return
; over the next small counter
movf cHCNT,f ; check the big count
btfsc STATUS,Z ; if cHCNT=0
goto ResetCNTS ; it goes counter to initialize a new count
movf iLCNT,w
decfsz cHCNT,f ; cHCNT=cHCNT-1
movlw 0 ; if <>0, то cLCNT=256
movwf cLCNT ; =0, =iLCNT
return
ResetCNTS
movf iHCNT,w
movwf cHCNT ; cHCNT=iHCNT
clrf cLCNT ; cLCNT=256
call FILL_SPD
; call FILL_VB
; reset for the new measurement
movlw d'10'
movwf HspDIG
movwf DspDIG
movwf EspDIG
; ***
movlw 1 ; was 8
movwf PreDIG
return
; Increment counters
DO_INCR ; 123 456 789 10
movlw d'10' ; 10 bits for a full run 999,999 kilometers (see). 999 m + IPM (not visible)
movwf cntr2
movlw tot_prev-1
call CH_CNTR ; 123 45 6 7
movlw 7 ; 7 places to 999 km daily .99 (visible) 9m + IPM (not visible)
movwf cntr2
movlw aux_prev-1
call CH_CNTR
movlw 4 ; first 3 digits speedometer
movwf cntr2
movlw PreDIG-1
movwf FSR
; ***
movlw 1 ; was 8
call CH_LOOP
call FILL_VB ; updated codes cathodes in the buffer indicator
; call FILL_SPD
bcf INTCON,INTF ; external interrupt flag is dropped
return
CH_CNTR
movwf FSR
movf IPM,w ; for pre-Meter IPM (impacts per meter)
CH_LOOP
incf FSR,f
decfsz INDF,f
return
movwf INDF
movlw d'10' ; for all the other bits of the counter
decfsz cntr2,f
goto CH_LOOP
return
PowerDown
call WRITE_EEPROM ; write counters in non-volatile memory
; WRITE the word in the buffer indicator
; ebfdacg zero bit in the segment lights
movlw b'10100001' ; 3?
movwf IND01
movlw b'00010001' ; A?
movwf IND02
movlw b'00010011' ; П?
movwf IND03
movlw b'00001011' ; И?
movwf IND04
movlw b'01000111' ; С?
movwf IND05
movlw b'01001001' ; Ь?
movwf IND06
SDeadLoop
movlw D'255'
movwf cntr2
bcf INTCON,T0IF ; reset the timer
DeadLoop
btfss INTCON,T0IF
goto DeadLoop
call ChAnod
decfsz cntr2,f
goto DeadLoop-1
; goto SDeadLoop
btfsc PORTC,RCPower ; If power is not restored (0), bypassing the return
goto PWRRestoted ; If you restore (1), then return
; disconnect all power
bcf PORTC,RCSwitch
goto SDeadLoop
PWRRestored
call FILL_VB
bsf PORTC,RCSwitch ; will again include
goto PowerRise
READ_EEPROM ; load counters from the non-volatile memory
movlw d'18'
movwf cntr2
movlw tot_prev
movwf FSR
RD_LOOP
movfw FSR
addlw -tot_prev
bsf STATUS,RP1 ; bank 2 - at the inlet bank 0
movwf EEADR
bsf STATUS,RP0 ; bank 3
bcf EECON1,EEPGD
bsf EECON1,RD
bcf STATUS,RP0 ; bank 2
movfw EEDATA
bcf STATUS,RP1 ; bank 0
movwf INDF
incf FSR,f
decfsz cntr2,f
goto RD_LOOP
return
WRITE_EEPROM ; preservation of the counters in the nonvolatile memory
movlw d'17'
movwf cntr2 ; cntr2 = 15
movlw tot_prev
movwf FSR ; FSR = @tot_prev = RAM address registers
WR_LOOP
movfw FSR
addlw -tot_prev ; W = 0, 1, ... , 14 = EEPROM address registers
; The procedure for writing bytes to the EEPROM
bsf STATUS,RP1 ; bank 2
movwf EEADR ; Transferring the W in EEADR
bcf STATUS,RP1 ; bank 0
movfw INDF ; Write the contents of W register RAM
bsf STATUS,RP1 ; bank 2
movwf EEDATA ; Из W в EEDATA???????
bsf STATUS,RP0 ; bank 3
bcf EECON1,EEPGD; choose EEPROM
bsf EECON1,WREN ; allow entry
movlw h'55' ; ** Compulsory **
movwf EECON2 ; ** procedure **
movlw h'AA' ; ** without **
movwf EECON2 ; ** comments **
bsf EECON1,WR ; The command to start recording
btfsc EECON1,WR ; loop, waiting for the completion of recording
goto $-1 ; repeat
bcf EECON1,WREN
bcf STATUS,RP1
bcf STATUS,RP0 ; bank 0
incf FSR,f ; FSR = @tot_prev +1, +2, ..., + 15
decfsz cntr2,f
goto WR_LOOP ; repeat 17 times
return
CLR_LEAD0
movf HspDIG,w
sublw d'10'
btfss STATUS,Z
return
movlw b'11111111'
movwf INDS1
movf DspDIG,w
sublw d'10'
btfss STATUS,Z
return
movlw b'11111111'
movwf INDS2
return
PROLOG
clrf IND01
clrf IND02
clrf IND03
clrf IND04
clrf IND05
clrf IND06
clrf INDS1
clrf INDS2
clrf INDS3
clrf cLCNT
movlw 3
movwf cHCNT
PRO_LOOP
btfss INTCON,T0IF
goto PRO_LOOP
call ChAnod
bcf INTCON,T0IF ; reset the timer
decfsz cLCNT,f
goto PRO_LOOP
decfsz cHCNT,f
goto PRO_LOOP
return
org 0x2100
; numbers by default (remain in place! order is important!)
; in the EEPROM are stored as a 10-s
; total range of
; ***
eet_prev de d'06' ; preliminary invisible
eet_k001 de d'10'-0
eet_k010 de d'10'-0
eet_k100 de d'10'-0 ; displayed below the level
eet_001k de d'10'-0 ; 1 км
eet_010k de d'10'-0
eet_100k de d'10'-0
eet_001t de d'10'-5
eet_010t de d'10'-9
eet_100t de d'10'-0 ; 100 000 км
;daily mileage
; ***
eea_prev de d'06' ; preliminary invisible
eea_k001 de d'10'-0
eea_k010 de d'10'-0 ; 10 м
eea_k100 de d'10'-0
eea_001k de d'10'-0 ; 1 км
eea_010k de d'10'-0
eea_100k de d'10'-0 ; 100 км
; the number of pulses at 1 meter
; ***
eeIPM de d'06'
end ;end of program