El RTOS ejemplo "Alarma serie"
; The code segment lines 1-87 are explained in this paragraph.
; Line 4 tells the MPASM assembler which PICmicro you
; are using.
list p=16C54,t=ON,c=132
include "P16C5X.INC"
; The include file PICREG.H follows with the
; equates and assignments to make the code more
; readable and changeable. You should use equates that
; relate symbols to each other.
;
; The Constants lines 10-12 are the values to change
; for different Baud rates.
; Constants
INDIR equ 0 ;Indirect Register
OUT_BIT_TIME equ 33h ;9600 Baud, 104uS Bit Rate
IN_BIT_TIME equ 64h ;4800 Baud, 208uS Bit Rate
FUDGE_TIME equ 23h ;Current Time within a Fudge Factor
; They represent the Bit Times for the Baud rates divided
; by 2 minus some latency factor. You might have to
; adjust the “Fudge Factor” and other values to fine tune
; the performance. The value used for the “Fudge
; Factor” is related to the longest path of code.
;
; Lines 21-24 are an experiment that allows a simple
; name to be associated to a single bit.
; This allows for easily changeable assignments.
; PORTB Register Definitions
#define Level_Reset PORTB,0 ;Low will cause Past Level to reset
;RB.7 - RB.1 == Input from Sensors
RB_TRIS equ B'11111111' ;RB TRIS at INIT State == all input
RB_MASK equ B'00000000' ;What is High/Low for RB at INIT State
; A Register Definitions - Programmable Inputs
#define Serial_IN_1 PORTA,0 ;Serial Input #1 - 8 bits
#define LED PORTA,1 ;LED Output - Level/State Indicator
#define Serial_Out PORTA,2 ;Serial Output - 8 bits + passwords
#define Serial_IN_2 PORTA,3 ;Serial Input #2 - 8 bits
RA_TRIS equ B'11111001' ;RA TRIS at INIT State RA1,2 Output
RA_MASK equ B'00000000' ;What is High/Low for RA at INIT State
;
; Lines 30-54 are the variable assignments.
; Variables (lines 35-39) are used as time counters.
; They count the number of units of time, and are compared
; to literals to see if an Event has just happened.
;
; Register Files RAM
temp equ 07h ;Tempary holding register - PIC16C54/56
Timer_Bits equ 08h ;Indicates which Timer(s) are Active = 1
Flags equ 09h ;Error Flags
LED_Mode equ 0Ah ;(0-2)=Mode, 3=LED_B, (4-6)=Seq #, 7=NEW
OState equ 0Bh ;Serial Out State
T_5_M_LO equ 0Ch ;5 Min Timer Counter - Low
T_5_M_HI equ 0Dh ;5 Min Timer Counter - High
T_5_S_CO equ 0Eh ;5 Second Timer - lack of Serial Input
T_20_mS_CO equ 0Fh ;20 mS Timer - used for debouncing
LED_C equ 10h ;LED Counter
Last_TMR0 equ 11h ;Last value of the TMR0
First_TMR0_O equ 12h ;Starting time for next Output event
xmt_byte equ 13h ;Serial xmit byte - destroyed in use
Curnt_Cnt equ 14h ;256 * TMR0 time μs
RCV_Storage equ 15h ;Long term storage of rcv_byte #1 & 2
Old_RB equ 16h ;Oldest/Master copy of RB
Last_RB equ 17h ;Last copy of RB
IState1 equ 18h ;Serial In #1 State
First_TMR0_I1 equ 19h ;Starting time for next #1 Input event
nbti1 equ 1Ah ;Next Bit #1 In Time - variable time
rcv_byte_1 equ 1Bh ;Receive Serial #1 In byte
IState2 equ 1Ch ;Serial In #2 State
First_TMR0_I2 equ 1Dh ;Starting time for next #2 Input event
nbti2 equ 1Eh ;Next Bit #2 In Time - variable time
rcv_byte_2 equ 1Fh ;Receive Serial #2 In byte
; The bits defined in lines 57-64 are used as Binary Semaphores.
; They keep Critical Sections of data protected.
; We will see them in action later in the code.
; Indicates which Timer(s) are Active = 1 & Flags
#define OState_B Timer_Bits,0 ;Serial Out Active Bit
#define IState1_B Timer_Bits,1 ;Serial IN #1 Active Bit
#define IState2_B Timer_Bits,2 ;Serial IN #2 Active Bit
#define T_5_S_B Timer_Bits,3 ;5 Second Timer Active Bit
#define T_5_M_B Timer_Bits,4 ;5 Min Timer Active Bit
#define RCV_Got_One_B Timer_Bits,5 ;Got a NEW Received byte to send out
#define RB_NEW_B Timer_Bits,6 ;Indicates a change in RB input
#define S_5_S_B Timer_Bits,7 ;Serial In 5 secs of inactivity
; The bits defined in lines 67-73 are error flags.
; They define the current or last error states of the Serial
; routines, and whether data was lost coming in or out.
; Error Flags
#define FS_Flag_1 Flags,0 ;Serial #1 IN had a False Start Error
#define FE_Flag_1 Flags,1 ;Last Serial #1 IN had a Frame Error
#define FS_Flag_2 Flags,2 ;Serial #2 IN had a False Start Error
#define FE_Flag_2 Flags,3 ;Last Serial #2 IN had a Frame Error
#define RCV_Overflow Flags,4 ;Lost Serial Input Byte - too Slow
#define RB_Overflow Flags,5 ;Lost RB Input Byte - too Slow
#define S_5_S_Overflow Flags,6 ;Lost '5S Inactivity' msg - too Slow
;
; The section of equates in lines 76-85 are used to define
; the different LED activity. They are used by Task #7 to
; keep the LED blinking.
;
;Equates for LED Task #7
#define LED_B LED_Mode,3 ;LED is active
#define LED_NEW_B LED_Mode,7 ;LED has just changed Modes = 1
LED_OFF_MODE equ B'00001000' ;LED OFF
LED_SEQ1_MODE equ B'10001001' ;LED Sequence 1: .2s On, 1s Off
LED_SEQ2_MODE equ B'10001010' ;LED Sequence 2: 3x(.2s), 1s Off
LED_SEQ3_MODE equ B'10001011' ;LED Sequence 3: 5x(.2s), 1s Off
LED_SLOW_MODE equ B'10011100' ;LED Slow Pulsing - .3 Hz
LED_MEDIUM_MODE equ B'10011101' ;LED Medium Pulsing - 1 Hz
LED_FAST_MODE equ B'10011110' ;LED Fast Pulsing - 3 Hz
LED_ON_MODE equ B'10001111' ;LED ON Continuously
; In lines 89-94, we try to save the all important first 256
; bytes of any page.
; Clear Registers 7-1Fh
Clear_Regs
GOTO Do_Clear_Regs ;Save space in first 256 bytes
; Determine the Highest Error Level & Start Task #7 outputing the new Level
D_H_E_L
GOTO Do_D_H_E_L ;Save space in first 256 bytes
;
; Task #1 outputs a byte Asynchronously over the Serial
; Output pin. Task #1 is started at line 98.
; The time units used for Tasks #1-4 are 2μS.
; Task #1 - Asynchronous 9600 Baud Serial Output (LOW=0)
;
; When Tasks #1-4 are then allowed to run, they check the
; difference between the first sample and the current time.
; If the delta is greater than or equal to the delay,
; then that Event has just happened.
; We first check if the state of the Serial Output is zero.
; We then jump to OStateS to start the outputting of the
; “Start Bit”. Because any Serial Output timings must be
; rock solid, we use a trick in lines 101-116 that helps greatly.
; We check if we are within a certain amount of time BEFORE
; the deadline and then wait for the time to output another bit.
; This trick allows us to be within a certain ± amount of time
; within the expected time to output that bit. With this code,
; we are about <±8% accurate for the Serial Output.
; You can only use this trick on the most critical tasks,
; and only on one. In this section of code, we are constantly checking
; the delta of time from the “FIRST_TMR0_O” reading
; and the current reading of TMR0.
; When we are very close to the output time, we jump to line 117 (_0005).
;
Do_OState
MOVF OState, F ;if OState == 0
BTFSC STATUS, Z ;
GOTO OStateS ; then goto Output-Start-Bit
; We first sample the TMR0 and store the count.
MOVF TMR0, W ;Get current time
MOVWF temp ; & store in temporary variable
MOVF First_TMR0_O, W ;Get elapsed time; Time Unit = 2 uS
SUBWF temp, F ;Delta of Current Time & Orginal Time
MOVLW FUDGE_TIME ;Take in account processing time to do it
SUBWF temp,W ;Time within fudge factor ?
BTFSS STATUS, C
GOTO _0005 ;Not time yet to change States so return
; Check if we are within a certain amount of time BEFORE
; the deadline and then wait for the time to output another bit.
_0003 MOVLW OUT_BIT_TIME ;Past time for next out-bit ?
SUBWF temp,W
BTFSC STATUS, C ;Do some delaying until it is time
GOTO _0004 ;It is now time to out put a bit
MOVLW H'04' ;Account for loop delay
ADDWF temp, F
NOP ; make loop delay even
GOTO _0003 ;Wait for exact time to output bit
;******
; If we are not even close to the proper time, we exit back to the
; main loop, so we can check the other timers and tasks.
;
; Now look at Figure 4 for a description of the Output Pulses,
; the “Bit units of Time”, and the associated state numbers.
; Note that the activities are spread out over time.
; The timer Events help to define the different states and
; their associated output activities. Each Event is
; handled in a very short, well-defined set of code as Task #1.
; Lines 117-131, are a quick state jump table.
; State machine --- OState = state table Entry
_0004 MOVF OState, W ;Get (0-A) mode #
ANDLW H'0F' ;Get only mode #
ADDWF PCL, F ;jump to subroutine
GOTO OStateS ;Serial Start Bit
GOTO OState0_7 ;Bit 0
GOTO OState0_7 ;Bit 1
GOTO OState0_7 ;Bit 2
GOTO OState0_7 ;Bit 3
GOTO OState0_7 ;Bit 4
GOTO OState0_7 ;Bit 5
GOTO OState0_7 ;Bit 6
GOTO OState0_7 ;Bit 7
GOTO OStateE ;Serial Stop Bit
GOTO OStateL ;Last State
_0005 RETLW H'00'
; You need to break all Real-Time code into very short
; segments in and then out.
; Each segment is just a few lines long.
; You do your activity, save status, and increment to
; the next state.
; Notice that OState0_7 code is used several times to
; output all 8 bits.
; The state variable (OState) is used also to count the number
; of bits already outputted.
; The time to the next outputting of a bit is calculated
; and is adjusted to take out the accumulation of
; errors in lines 151-152.
OS_End MOVLW OUT_BIT_TIME ;Adjust out the cumulation of error
ADDWF First_TMR0_O, F
INCF OState, F ;increment to next state
RETLW H'00'
; We make sure of a full “Stop Bit” length in the OStateE code.
; In the OStateL code,
OStateL
CLRF OState ;Ready to send next byte out
BCF OState_B ;Serial Out not active
RETLW H'00'
; we reset the OState variable to zero, and tell the world
; that we are not outputting now in line 157.
; This is important because we use that bit (OState_B)
; to Signal that we need to protect the variable xmt_byte
; that changes over several states.
; We also use it to Signal that we are ready for another byte
; to output.
; Look at Task #4. See how it uses this Semaphore to full advantage.
; We have just explained a Critical Segment variable as
; outlined in the theory sections of this article.
;
; Task #2 starts at line 302.
; Task #2’s subroutines continue at line 363 and continue until line 423.
; This task reads the Serial Input #1 for Asynchronous data.
; Task #2 can be described as a State Machine for outputting
; a byte Serially.
; Task #2 reads the Serial Input line 1, running at 4800 Baud.
;****** ;Task #2 - Asynchronous 4800 Baud Serial Input (LOW=0)
Do_I1State
MOVF IState1, F ;if IState1 == 0
BTFSC STATUS, Z ; then Do Start Bit
GOTO I1StateS
MOVF TMR0, W ;Get current time
MOVWF temp
MOVF First_TMR0_I1, W ;Get elapsed time; Time Unit = 2 uS
SUBWF temp, F
MOVF nbti1, W ;Past time for next input bit ?
SUBWF temp, W
BTFSS STATUS, C
GOTO _0033
; State machine - IState1 = State table entry
MOVF IState1, W ;Get (0-B) mode #
ANDLW H'0F' ;Get only mode #
ADDWF PCL, F ;jump to subroutine
GOTO I1StateS ;State - Serial Start Bit
GOTO I1State2 ;State - 1/2 of Start Bit - see if False Start
GOTO I1State0_7 ;State - Bit 0
GOTO I1State0_7 ;State - Bit 1
GOTO I1State0_7 ;State - Bit 2
GOTO I1State0_7 ;State - Bit 3
GOTO I1State0_7 ;State - Bit 4
GOTO I1State0_7 ;State - Bit 5
GOTO I1State0_7 ;State - Bit 6
GOTO I1State0_7 ;State - Bit 7
GOTO I1StateE ;State - Serial Stop Bit
GOTO I1StateL ;Last State - End of Stop Bit
_0033
RETLW H'00'
;*** ;Subroutines for Task #2
I1StateS ;Start Bit - Setup timing variables
BSF IState1_B ;Serial Input Active
MOVF TMR0,W ;Store starting time
MOVWF First_TMR0_I1
MOVLW H'0D' ;Fudge again
SUBWF First_TMR0_I1, F
MOVLW H'32' ;Time delay = 1/2 bit time
MOVWF nbti1
INCF IState1, F ;Increment to next state
RETLW H'00'
I1State2 ;Check if still a Start Bit
BTFSS Serial_IN_1 ;False Start Error ?
GOTO FS_Error_1
BCF FS_Flag_1 ;Start Bit OK
MOVF nbti1, W ;Adjust out the error
ADDWF First_TMR0_I1, F
MOVLW IN_BIT_TIME ;Time Delay = full bit time
MOVWF nbti1
INCF IState1, F ;increment to next state
RETLW H'00'
I1State0_7 ;Bit 0 - 7
BTFSS Serial_IN_1 ;Move Input bit into C
BCF STATUS,C
BTFSC Serial_IN_1
BSF STATUS,C
RRF rcv_byte_1, F ;Move C into left most bit
MOVF nbti1,W
ADDWF First_TMR0_I1, F ;Adjust out the error
INCF IState1, F ;increment to next state
RETLW H'00'
I1StateE ;Check if we have a proper Stop Bit
BTFSC Serial_IN_1 ;Frame Error
GOTO F_Error_1
BCF FE_Flag_1 ;Stop Bit OK
CLRF T_5_S_CO ;Reset 5 Sec Timer - got a good byte
;Process the msg Here !
MOVF rcv_byte_1, W ;Make a copy of just received byte
MOVWF RCV_Storage
BTFSS RCV_Got_One_B ;Report Lost data
BCF RCV_Overflow
BTFSC RCV_Got_One_B
BSF RCV_Overflow
BSF RCV_Got_One_B ;We Now have a RB Value to go out
I1StateL
CLRF IState1 ;Ready to receive next byte
BCF IState1_B ;Serial In not currently active
RETLW H'00'
FS_Error_1 ;False Start - Shut Down Checking
BCF IState1_B ;Serial Input NOT Active
BSF FS_Flag_1 ;False Start Error
GOTO I1StateL ;Start All Over
F_Error_1 ;Frame Error - Wait for End of Stop Bit
MOVF nbti1,W ;Adjust out the error
ADDWF First_TMR0_I1, F
MOVLW H'32' ;Time Delay = 1/2 bit time
MOVWF nbti1
BSF FE_Flag_1 ;Frame Error for this Byte ?
INCF IState1, F ;Increment to next state
RETLW H'00'
; The code structure is very similar to that of Task #1 (Figure 3).
; Notice that there are more states than the Serial Output Task #1.
; Once the “Start Bit” is detected, we half step into the
; “Start Bit” to see if it was a “False Start” or not.
; We then sample and store theincoming bits to form an 8-bit byte
; just like Task #1.
; We sample the “Stop Bit” to see if it is a “Frame Error”.
; We delay another 1/2 bit to get to the end of the “Stop Bit”
; if there was an “Frame Error” before resetting Task #1’s
; state to 0. Otherwise, we reset Task #1’s state to 0, and
; Signal that we are ready for another “Start Bit”.
; The just received byte is stored in variable “RCV_Storage”.
; A check is made to see if we already sent out the last
; received byte before clobbering the old byte with the new byte.
;
; Task #3 reads the Serial Input line 2, running at 4800 Baud.
; The code structure is the same as Task #2
; Task #3 interrupts the code of Task #2 at line 333 and continues
; until line 362.
; Task #3’s subroutines continue at line 424 and continue until line 484
; is reached.
; The received byte is also put into the same
; storage variable as Task #2 - “RCV_Storage”.
; When either Task #2 or Task #3 receives a valid byte,
; Task #8’s counter is reset.
; You can up the Baud rate of Task #2 and 3 if you lower the output
; Baud rate of Task #1.
; Note that for reading the Serial Input Lines, you can be
; off by ±15% for each sampling, but not accumulatively
;****** ;Task #3 - Asynchronous 4800 Baud Serial Input (LOW=0)
Do_I2State
MOVF IState2, F ;if IState1 == 0
BTFSC STATUS, Z ; then Do Start Bit
GOTO I2StateS
MOVF TMR0, W ;Get current time
MOVWF temp
MOVF First_TMR0_I2, W ;Get elapsed time; Time Unit = 2 uS
SUBWF temp, F
MOVF nbti2, W ;Past time for next input bit ?
SUBWF temp, W
BTFSS STATUS, C
GOTO _0035
; State machine - IState2 = State table entry
MOVF IState2,W ;Get (0-B) mode #
ANDLW H'0F' ;Get only mode #
ADDWF PCL, F ;jump to subroutine
GOTO I2StateS ;State - Serial Start Bit
GOTO I2StateS2 ;State - 1/2 of Start Bit - see if False
Start
GOTO I2State0_7 ;State - Bit 0
GOTO I2State0_7 ;State - Bit 1
GOTO I2State0_7 ;State - Bit 2
GOTO I2State0_7 ;State - Bit 3
GOTO I2State0_7 ;State - Bit 4
GOTO I2State0_7 ;State - Bit 5
GOTO I2State0_7 ;State - Bit 6
GOTO I2State0_7 ;State - Bit 7
GOTO I2StateE ;State - Serial Stop Bit
GOTO I2StateL ;Last State - End of Stop Bit
_0035 RETLW H'00'
;
;*** ;Subroutines for Task #3
I2StateS ;Start Bit - Setup timing variables
BSF IState2_B ;Serial Input Active
MOVF TMR0, W ;Store starting time
MOVWF First_TMR0_I2
MOVLW H'0D' ;Fudge again
SUBWF First_TMR0_I2, F
MOVLW H'32' ;Time delay = 1/2 bit time
MOVWF nbti2
INCF IState2, F ;Increment to next state
RETLW H'00'
I2StateS2 ;Check if still a Start Bit
BTFSS Serial_IN_2 ;False Start Error ?
GOTO FS_Error_2
BCF FS_Flag_2 ;Start Bit OK
MOVF nbti2,W ;Adjust out the error
ADDWF First_TMR0_I2, F
MOVLW IN_BIT_TIME ;Time Delay = full bit time
MOVWF nbti2
INCF IState2, F ;increment to next state
RETLW H'00'
I2State0_7 ;Bit 0 - 7
BTFSS Serial_IN_2 ;Move Input bit into C
BCF STATUS, C
BTFSC Serial_IN_2
BSF STATUS, C
RRF rcv_byte_2, F ;Move C into left most bit
MOVF nbti2, W
ADDWF First_TMR0_I2, F ;Adjust out the error
INCF IState2, F ;increment to next state
RETLW H'00'
I2StateE ;Check if we have a proper Stop Bit
BTFSC Serial_IN_2 ;Frame Error
GOTO F_Error_2
BCF FE_Flag_2 ;Stop Bit OK
CLRF T_5_S_CO ;Reset 5 Sec Timer - got a good byte
;Process the msg Here !
MOVF rcv_byte_2, W ;Make a copy of just received byte
MOVWF RCV_Storage
BTFSS RCV_Got_One_B ;Report Lost data
BCF RCV_Overflow
BTFSC RCV_Got_One_B
BSF RCV_Overflow
BSF RCV_Got_One_B ;We Now have a RB Value to go out
I2StateL
CLRF IState2 ;Ready to receive next byte
BCF IState2_B ;Serial In not currently active
RETLW H'00'
FS_Error_2
BCF IState2_B ;False Start - Shut Down Checking
BSF FS_Flag_2 ;False Start Error
GOTO I2StateL ;Start All Over
F_Error_2 ;Frame Error - Wait for End of Stop Bit
MOVF nbti2,W ;Adjust out the error
ADDWF First_TMR0_I2, F
MOVLW H'32' ;Time Delay = 1/2 bit time
MOVWF nbti2
BSF FE_Flag_2 ;Frame Error for this Byte ?
INCF IState2, F ;Increment to next state
RETLW H'00'
;
; Task #4 starts at line 538 and finishes at line 561.
; Task #4 controls the feeding of Task #1 from several other tasks
; that want data to be outputted. It uses several Semaphores
; to make sure that Task #1 is not bothered until
; it is ready for another byte.
;
Task_4 ;Task #4 - Finds next Buffered Byte to Send Out through Task 1
BTFSC OState_B ;if outputing now then skip call
GOTO _0059
BTFSS RCV_Got_One_B ;Got a NEW Received byte to send
GOTO _0057
MOVF RCV_Storage, W ;Send just received byte
MOVWF xmt_byte
BCF RCV_Got_One_B ;Clear need to send old byte
BSF OState_B ;Start Task #1 & Lock Out Others
GOTO _0059
_0057 BTFSS RB_NEW_B ;Indicates a change in RB input
GOTO _0058
MOVF Old_RB, W ;Send New RB value
MOVWF xmt_byte
BCF RB_NEW_B ;Clear need to send out newest value
BSF OState_B ;Start Task #1 & Lock Out Others
GOTO _0059
_0058 BTFSS S_5_S_B ;Serial In 5 secs of inactivity
GOTO _0059
MOVLW H'FF' ;Tell of inactivity of Serial In
MOVWF xmt_byte
BCF S_5_S_B ;Clear need to send msg
BSF OState_B ;Start Task #1 & Lock Out Others
;Heart Beat - Time unit = 512 uS for Tasks #5 & #6
_0059 MOVF TMR0,W ;Step-up time units * 512
MOVWF temp
MOVF Last_TMR0, W ;Test to see if it overflowed
SUBWF temp, W
BTFSS STATUS, C
GOTO Inc_Time
MOVF temp, W ;unit error = < |+-512 uS|
MOVWF Last_TMR0
GOTO Task_1 ;Serial Output
Inc_Time
MOVF temp, W ;Save current TMR0 into Last_TMR0
MOVWF Last_TMR0
; Task #4 finds the next buffered byte to send out through Task #1.
; Task #4 also controls the order of which byte
; goes first over another less important byte of data.
; It can be said that Task #1 Blocks Task #4 from running.
; You can think of the Serial Output Line as a Shared Resource.
; The use of Semaphores here allow the Synchronization of data
; and actions.
;
; Task#5 runs through lines 576-581, and is very short.
Task_5 ; - Monitor Level Reset Input Line - Always Running !
BTFSC Level_Reset
GOTO Task_6 ; Debounces sensors input lines
MOVLW LED_OFF_MODE ;Lowest Level Indicator output
MOVWF LED_Mode
; Task #5 monitors the Level Reset Input Line and will
; reset the LED state variable if the line ever goes low.
; This task is always in the Ready State. This task is said
; to simply “pole the input line” when ever it can.
;
; Task #6 debounces the seven sensor input lines,
; running every 20 ms. Lines 582-611 represent Task #6.
; The variable “T_20_mS_CO” is incremented every 512 μs (Clock Tick)
; and is compared to the count needed to equal 20 ms. If it is time,
; the subroutine QCheck_T123 is called to see if Tasks
; #1-3 are in the Ready State.
Task_6 ;Task #6 - Debounce 8 bit Input Sensors - Runs every 20 mS
INCF T_20_mS_CO, F ;Inc Counter - Time Unit = 512 uS
MOVLW H'27' ;Used to debounce the input
SUBWF T_20_mS_CO, W
BTFSS STATUS, Z
GOTO _0065
CLRF T_20_mS_CO ;Reset T_20_mS_CO to start over again
CALL QCheck_T123 ;Quick Check of Tasks #1, #2 and #3
MOVF PORTB,W ;Last copy of RB same as Current ?
SUBWF Last_RB,W
BTFSC STATUS, Z
GOTO _0062
MOVF PORTB, W ; Store Current RB - diff from Last
MOVWF Last_RB
GOTO _0063
_0062 MOVF Last_RB, W ;New Old RB <- same value over 20 mS
MOVWF Old_RB
_0063 MOVF Old_RB, F ;See if RB is now 0
BTFSC STATUS,Z ;RB == 0 ? then keep timer running
GOTO _0064
CLRF T_5_M_LO ;Reset 5 Min Timer
CLRF T_5_M_HI ; still not zero yet
_0064 CALL D_H_E_L ;Determine the Highest Error Level
BTFSS RB_NEW_B ;Check for Lost Data Error
BCF RB_Overflow
BTFSC RB_NEW_B
BSF RB_Overflow
BSF RB_NEW_B ;Every 20 mS send Old_RB out
;Heart Beat - Time unit = 131072 uS for Tasks #7, #8 & #9
_0065 MOVLW H'F9' ;RA TRIS - refresh RA=1001
TRIS 5
MOVLW H 'FF' ;RB TRIS - refresh
TRIS 6
DECFSZ Curnt_Cnt, F ;Step-up time units * 256
GOTO Task_1 ;Serial Output
;
; If any of the Tasks #1-3 are ready, they are ran and we then
; continue with Task #6.
; We compare the current value of the input Port_B to
; see if it stayed the same from the last reading 20 ms back.
; If the two readings are the same, then Port_B is
; considered to be stable and the possibly new value is
; placed in the variable “Old_RB” to be outputted by Task#1.
;
; The subroutine D_H_E_L is called to determine the new LED state.
; We then check if Task #1 was too busy to output the last sensor
; status byte, if so then that error is recorded.
;
; Do_D_H_E_L determines the LED’s next state based
; on the 7 sensor input status.
; This subroutine checks each bit to see if it is active and then
; checks if a change in the LED’s current state needs changing.
;****
Do_D_H_E_L
; Determine the Highest Error Level & Start Task #7
; - Output Highest Level Indication on LED
MOVLW H'07' ;Check top 7 bits
MOVWF temp
MOVF Old_RB, W ;Get copy of 7 debounced Sensor Input
MOVWF Last_RB
_0070 RLF Last_RB, F ;Put top bit into C bit
BTFSC STATUS, C ;Check if C bit is set
GOTO _0072
DECFSZ temp, F ;Continue to check lesser bits
GOTO _0070
_0071 MOVF PORTB, W ;Restore current value of RB
MOVWF Last_RB
RETLW H'00'
_0072 ; Implimentation off missing instruccion SUBLF L, RAM-Reg
MOVF LED_Mode, W ;Get current Level Indicator
ANDLW H'07' ;Get only " "
MOVWF Last_RB ;Store into a tempary register
MOVF temp, W ;Check if already at this Level
SUBWF Last_RB, W
; end implementation
BTFSC STATUS, C
GOTO _0071
MOVLW H'88' ;Start to build LED_Mode
IORWF temp, W ;Put new Level Indicator into reg
MOVWF LED_Mode ;Store new LED Mode
GOTO _0071
; Task #7 outputs the Highest Severity Level Indicationon the LED.
; Task #7’s main code is lines 621-628.
;
; Do_LED starts at line 161, and continues to 276.
; This task is also broken into small time units of code.
; It is constantly checking to see if it is time to switch the
; on/off condition of the LED.
; The time units for Task #7 are regulated by the code in lines 613-619.
; 131072 μS = time unit for Tasks #7-9.
; Task #7 has many state jump tables so it is included in the
; first 256 bytes of the first page.
; Lines 168-175 explain the on and off sequences and offs that
; represent levels of severity of the input status lines.
; The variable “LED_Mode” has both Task #7’s current state number
; and the sub-state-number for that state’s output sequence.
;
; Task #8 is a 5 second lack of input from either of the two
; Serial input timers. Tasks #2 and #3 will reset the time
; counter for Task #8, when either receives a full byte.
; If the time counter “T_5_S_CO” equals 5 secs, then the
; LED’s state is bumped to the highest, and a special
; byte is sent down the line to the next “Remote Alarm” unit.
; The counter variable is reset, and count starts all over.
; We then check if Task #1 was too busy to output
; the last special status byte, if so then that error is recorded.
;
; Task #9 measures 5 minutes of calm on the 7 sensor
; lines and then resets the LED’s state.
; Lines 646-663 compose Task #9.
Task_9 ; - 5 Min. Lack of Severe Error from Sensors Reset Timer
BTFSS T_5_M_B ;5 Min Timer Active ?
GOTO Task_A
; 16-bit increment
INCF T_5_M_LO, F ;Inc LO Counter; Time Unit = 131072 uS
BTFSC STATUS,Z ; See if carry needs to be passed on ?
INCF T_5_M_HI, F ;Inc HI Counter; Time Unit = 131072 uS
; end of 16-bit increment
MOVLW H'08' ;#2288< Check T_5_M_HI if time
SUBWF T_5_M_HI, W
BTFSS STATUS, Z
GOTO Task_A
MOVLW H'F0' ;#2288> Check T_5_M_LO if time
SUBWF T_5_M_LO, W
BTFSS STATUS, Z
GOTO Task_A
CLRF T_5_M_LO ;Reset T_5_M_LO
CLRF T_5_M_HI ;Reset T_5_M_HI
MOVLW LED_OFF_MODE ;Lowest Level Indicator output
MOVWF LED_Mode
Task_A
GOTO Task_1 ; Loop Forever
; Task #9 needs 16 bits of counter power to record 5 minutes of time.
; The counter variables are reset after being triggered.
; Subrutie Do_Clear_Regs clears registers 7-1Fh.
; It leaves the FSR register zeroed out.
; This is very important for the PIC16C57 chip.
Do_Clear_Regs ; Limpia Registros RAM 07h-1Fh
MOVLW H'1F' ;Write the base (First regs to clear)
MOVWF FSR ; into FSR
Loop_C CLRF INDIR ; Limpia el registro apuntado
DECF FSR, F ; y apunta al siguiente registro
; Con el PIC16F54, en el reg FSR, solo podemos cambiar los bits 4 -> 0
; cuando estan en 1 1111 e incrementamos FSR este pasa a 0 0000 sin afectar
; los bits 5,6 & 7.
MOVLW H'E7' ;Vemos si ya alcanzamos el limite bajo
SUBWF FSR, W ; de RAM el cual es 07h pero como los
; bits 5, 6, y 7 de
; FSR estan ajustados a 1 ... debemos
; subtraer E7h
BTFSC STATUS, C ;
GOTO Loop_C ; No: Regresa hasta que se alcanze
CLRF FSR ; Si: Limpia el reg FSR
RETLW H'00' ; y regresa
; The main or starting code is started at line 485.
; From that line to line 515, all variables are initialized, and all tasks
; are initialized at this time also.
;****** ;Code Starting point
Main
; Configura Puertos y TMR0
MOVLW H'00' ;What is High/Low for RA at INIT State
MOVWF PORTA
MOVLW H'00' ;What is High/Low for RB at INIT State
MOVWF PORTB
MOVLW H'F9' ;RA TRIS at INIT State
TRIS 5
MOVLW H'FF' ;RB TRIS at INIT State
TRIS 6
MOVLW H'00' ; Set TMR0/2
; bit5-Clock source = Internal bit4-Edge =low-to-high transition
; bit3-Prescaler on TMR0 bit210- Prescaler = 1:2
OPTION
CALL Clear_Regs ;Clear Registers 7-1F - Same Memory Page
CLRF TMR0 ;Start timers
;Initialize Tasks
;Task #1 waits for byte to output
;Asynchronous 9600 Baud Serial Output
;
;Task #2 waits for Serial IN Start Bit
;1st Asynchronous 4800 Baud Serial Input
;
;Task #3 waits for Serial IN Start Bit
;2nd Asynchronous 4800 Baud Serial Output
;
;Task #4 runs when Task 1 is Not
; Finds next Buffered Byte to Send Out
; through Task 1
;
;Task #5 is always running
; Monitor Level Reset Input Line
;
;Task #6 - Runs every 20 mS
; Debounce 8 bit Input Sensors
MOVF PORTB, W ;Task #6 is Initialized here
MOVWF Old_RB
MOVF Old_RB, W ;Make all the same initial value
MOVWF Last_RB
BSF RB_NEW_B ;Tell Task #4: RB byte ready to output
;
;Task #7 - Runs every 20 mS
; Output Highest Level Indication on LED
MOVLW LED_OFF_MODE
MOVWF LED_Mode ;Task #7 is Started
;
;Task #8 - Runs every 20 mS
; 5 Second Serial Input Lack of
; Activity Timer
BSF T_5_S_B ;Task #8 is Started here
;
;Task #9 - 5 Min. Lack of Severe Error
; from Sensors Reset Timer
BSF T_5_M_B ;Task #9 is Started here
; The Main Loop is started at line 516 and ends at line 665.
; This is where the real action is done.
; Each task checks the time to see if the conditions are correct for it to run.
; The tasks that are not Blocked, and have a job to do now are in a Ready State.
; In the Main Loop, we check the current state of
; each task in order of Priority (1-9). If ready, we do a
; very simple Task Switch and place that task in the
; Executing State/Running State. Several time unit
; changes take place in the Main Loop.
; Handle Task & Timer activities - Main Loop
Task_1 ;Task #1 - Asynchronous 9600 Baud Serial Output (LOW=0)
BTFSS OState_B ;if not outputing now then skip call
GOTO Task_2
CALL Do_OState ;Go Do Task #1
Task_2 ;Task #2 - Asynchronous 4800 Baud Serial Input (LOW=0)
BTFSC IState1_B ;if already started then call
GOTO _0053
BTFSC Serial_IN_1 ;if Start bit ? then call
GOTO _0053
GOTO Task_3
_0053 CALL Do_I1State ;Go Do Task #2
Task_3 ;Task #3 - Asynchronous 4800 Baud Serial Input (LOW=0)
BTFSC IState2_B ;if already started then call
GOTO _0055
BTFSC Serial_IN_2 ;if Start bit ? then call
GOTO _0055
GOTO Task_4
_0055 CALL Do_I2State ;Go Do Task #3
Task_4 ;Task #4 - Finds next Buffered Byte to Send Out through Task 1
BTFSC OState_B ;if outputing now then skip call
GOTO _0059
BTFSS RCV_Got_One_B ;Got a NEW Received byte to send
GOTO _0057
MOVF RCV_Storage, W ;Send just received byte
MOVWF xmt_byte
BCF RCV_Got_One_B ;Clear need to send old byte
BSF OState_B ;Start Task #1 & Lock Out Others
GOTO _0059
_0057 BTFSS RB_NEW_B ;Indicates a change in RB input
GOTO _0058
MOVF Old_RB, W ;Send New RB value
MOVWF xmt_byte
BCF RB_NEW_B ;Clear need to send out newest value
BSF OState_B ;Start Task #1 & Lock Out Others
GOTO _0059
_0058 BTFSS S_5_S_B ;Serial In 5 secs of inactivity
GOTO _0059
MOVLW H'FF' ;Tell of inactivity of Serial In
MOVWF xmt_byte
BCF S_5_S_B ;Clear need to send msg
BSF OState_B ;Start Task #1 & Lock Out Others
;Heart Beat - Time unit = 512 uS for Tasks #5 & #6
_0059 MOVF TMR0,W ;Step-up time units * 512
MOVWF temp
MOVF Last_TMR0, W ;Test to see if it overflowed
SUBWF temp, W
BTFSS STATUS, C
GOTO Inc_Time
MOVF temp, W ;unit error = < |+-512 uS|
MOVWF Last_TMR0
GOTO Task_1
;Serial Output
Inc_Time
MOVF temp, W ;Save current TMR0 into Last_TMR0
MOVWF Last_TMR0
Task_5 ;Task #5 - Monitor Level Reset Input Line - Always Running !
BTFSC Level_Reset
GOTO Task_6
MOVLW LED_OFF_MODE ;Lowest Level Indicator output
MOVWF LED_Mode
Task_6 ;Task #6 - Debounce 8 bit Input Sensors - Runs every 20 mS
INCF T_20_mS_CO, F ;Inc Counter - Time Unit = 512 uS
MOVLW H'27' ;Used to debounce the input
SUBWF T_20_mS_CO, W
BTFSS STATUS, Z
GOTO _0065
CLRF T_20_mS_CO ;Reset T_20_mS_CO to start over again
CALL QCheck_T123 ;Quick Check of Tasks #1, #2 and #3
MOVF PORTB,W ;Last copy of RB same as Current ?
SUBWF Last_RB,W
BTFSC STATUS, Z
GOTO _0062
MOVF PORTB, W ; Store Current RB - diff from Last
MOVWF Last_RB
GOTO _0063
_0062 MOVF Last_RB, W ;New Old RB <- same value over 20 mS
MOVWF Old_RB
_0063 MOVF Old_RB, F ;See if RB is now 0
BTFSC STATUS,Z ;RB == 0 ? then keep timer running
GOTO _0064
CLRF T_5_M_LO ;Reset 5 Min Timer
CLRF T_5_M_HI ; still not zero yet
_0064 CALL D_H_E_L ;Determine the Highest Error Level
BTFSS RB_NEW_B ;Check for Lost Data Error
BCF RB_Overflow
BTFSC RB_NEW_B
BSF RB_Overflow
BSF RB_NEW_B ;Every 20 mS send Old_RB out
;Heart Beat - Time unit = 131072 uS for Tasks #7, #8 & #9
_0065 MOVLW H'F9' ;RA TRIS - refresh RA=1001
TRIS 5
MOVLW H'FF' ;RB TRIS - refresh
TRIS 6
DECFSZ Curnt_Cnt, F ;Step-up time units * 256
GOTO Task_1 ;Serial Output
Task_7 ;Task 7 - Output Highest Level Indication on LED
BTFSS LED_B ;Is LED active ?
GOTO Task_8
CALL QCheck_T123 ;Quick Check of Tasks #1, #2 and #3
CALL Do_LED ;Handle LED timing
Task_8 ;Task #8 - 5 Second Serial Input Lack of Activity Timer
BTFSS T_5_S_B ;5 Sec Timer Active ?
GOTO Task_9
INCF T_5_S_CO, F ;Inc Counter - Time Unit = 131072 uS
MOVLW H'26' ;Check T_5_S_CO if time
SUBWF T_5_S_CO, W
BTFSS STATUS, Z
GOTO Task_9
CLRF T_5_S_CO ;Reset T_5_S_CO
MOVLW LED_ON_MODE ;Highest Level Indicator output
MOVWF LED_Mode
BTFSS S_5_S_B ;Check if Lost Data Error
BCF S_5_S_Overflow
BTFSC S_5_S_B
BSF S_5_S_Overflow
BSF S_5_S_B ;Send notice of 5 seconds of inaction
Task_9 ;Task #9 - 5 Min. Lack of Severe Error from Sensors Reset Timer
BTFSS T_5_M_B ;5 Min Timer Active ?
GOTO Task_A
; 16-bit increment
INCF T_5_M_LO, F ;Inc LO Counter; Time Unit = 131072 uS
BTFSC STATUS,Z ; See if carry needs to be passed on ?
INCF T_5_M_HI, F ;Inc HI Counter; Time Unit = 131072 uS
; end of 16-bit increment
MOVLW H'08' ;#2288 < Check T_5_M_HI if time
SUBWF T_5_M_HI, W
BTFSS STATUS, Z
GOTO Task_A
MOVLW H'F0' ;#2288 > Check T_5_M_LO if time
SUBWF T_5_M_LO, W
BTFSS STATUS, Z
GOTO Task_A
CLRF T_5_M_LO ;Reset T_5_M_LO
CLRF T_5_M_HI ;Reset T_5_M_HI
MOVLW LED_OFF_MODE ;Lowest Level Indicator output
MOVWF LED_Mode
Task_A
GOTO Task_1 ; Loop Forever