📄 16f84.asm
字号:
; check to see if we need to send the stop bit:
movf BitCount,F
btfsc STATUS,Z ;18th cycle
goto SendStopBit
; if we get to here, we're in the middle of sending. Send the next
; bit: (16 cycles to get to the next instruction from the start of
; the interrupt).
rrf TXChar,F ;doing rrf on TXChar puts the
btfss STATUS,C ;least significant bit in the
goto SendZero ;carry flag.
nop
bsf PORTA,_SER_OUT ;if carry is set, send a one.
goto EndDoBit ;PORTA,1 is set on the 24th cycle
SendZero
bcf PORTA,_SER_OUT ;otherwise, send a zero. (24th cycle)
nop ;nop's are for taking the same time
nop ;to get to reloading TMR0 as for when
;a one is sent.
; Decrement the bit counter.
EndDoBit
decf BitCount,F
; reload TMR0 for the next interrupt, and
; go to the end of the interrupt routine.
movlw _BitTxDelay
movwf TMR0 ;29th cycle
goto Restore
; Here we need to send the stop bit, turn off the TMR0 interrupt,
; turn on the external interrupt, and set the SerStatus register
; flags appropriately.
SendStopBit
nop
nop
nop
bsf PORTA,_SER_OUT ;no. Send the stop bit. (24th cycle)
bsf SerialReg,3 ;set the "sending stop bit" flag
; reload TMR0 for the next interrupt, and
; go to the end of the interrupt routine.
movlw _StopTxDelay
movwf TMR0 ;27th cycle
goto Restore
; we're completely done sending or receiving. Clean up.
Done movlw b'00010000' ;set bits in INTCON to enable
movwf INTCON ;external interrupt
movlw b'00000001'
andwf SerialReg,F ;clear the busy bits in SerialReg
goto Restore
;------end DoBit-----------------------------------------------------
;------Subroutine SendChar-------------------------------------------
;
; This is not called by the interrupt handler. Rather, it activates
; the interrupts needed to send it. Put the character to be sent in
; the TXChar file register before calling this subroutine.
;
SendChar
; send the start bit:
bcf PORTA,_SER_OUT
; set the SerStatus to indicate that the routines are busy sending
; a character:
movlw b'00000110'
movwf SerialReg
; load up TMR0 so it overflows at the right time.
nop ;for timing
movlw _BitTxDelay
movwf TMR0 ;5th cycle after write to PORTA
; clear the external interrupt flag, disable the external interrupt,
; and enable the TMR0 interrupt.
movlw b'10100000'
movwf INTCON
; set the BitCount for the eight bits to send:
movlw 8
movwf BitCount
return
;------end SendChar--------------------------------------------------
;------begin GetAChar------------------------------------------------
GetAChar
call Idle
btfss SerialReg,0 ;wait for a character to be received
goto GetAChar
bcf SerialReg,0
return
;------end GetAChar--------------------------------------------------
;------begin SendAChar-----------------------------------------------
SendAChar
call SendChar
WaitToFinish
call Idle
btfsc SerialReg,1 ;wait for the character to be sent
goto WaitToFinish
return
;------end SendAChar-------------------------------------------------
;------Subroutine WaitMS---------------------------------------------
;
; WaitMS is an approximate millisecond delay. It assumes a 4 MHz
; oscillator, meaning instructions are executed at a rate of 1 MHz.
; I got the timing info (number of cycles per instruction) from the
; Microchip PIC16F84 data sheet.
; the call to this subroutine takes 2 cycles to execute.
WaitMS
movlw 248 ;1 cycle
movwf MSDelay ;1 cycle
nop ;1 cycle--these nops are added to
nop ;1 cycle make the total number of
nop ;1 cycle instructions executed in
; the routine to be 1000.
;the nop instruction simply does
;nothing except take time to execute.
; The loop below takes four cycles for every time through except the
; last, when it takes five (including the time needed to execute the
; return). So, the total number of instructions executed in getting
; to and returning from this subroutine is:
;
; 2 to get here
; + 2 to set the MSDelay value
; + 3 for the nops
; + 247*4 for the first 247 times through the loop
; + 5 for the last time through the loop and to return
; --------
; = 1000
RepeatWaitMS
nop ;1 cycle
decfsz MSDelay,F ;1 cycle if not zero, 2 if zero
goto RepeatWaitMS ;2 cycles
return ;2 cycles
;------end WaitMS----------------------------------------------------
;------begin WaitDit-------------------------------------------------
;
; WaitDit is a delay loop which times dits.
WaitDit
movf DitLen,W
movwf DitLoopIndex
RepeatWaitDit
call WaitMS
decfsz DitLoopIndex,F
goto RepeatWaitDit
return
;------end WaitDit---------------------------------------------------
;------begin WaitDah-------------------------------------------------
;
; WaitDah is a delay loop which times dahs. Dahs are three times the
; length of dits.
WaitDah
call WaitDit
call WaitDit
call WaitDit
return
;------end WaitDah---------------------------------------------------
;------begin WaitWordDit---------------------------------------------
;
; WaitWordDit is a delay loop which times dits based on intercharacter
; spacing.
WaitWordDit
movf DitWordLen,W
movwf DitLoopIndex
RepeatWaitWordDit
call WaitMS
decfsz DitLoopIndex,F
goto RepeatWaitWordDit
return
;------end WaitWordDit-----------------------------------------------
;------begin WaitWordDah---------------------------------------------
;
; WaitWordDah is a delay loop which times dahs based on intercharacter
; spacing. WordDahs are three times the length of Worddits.
WaitWordDah
call WaitWordDit
call WaitWordDit
call WaitWordDit
return
;------end WaitWordDah-----------------------------------------------
;------begin SendCWDit-----------------------------------------------
;
; actually sends the dit over the LED
SendCWDit
bcf PORTA,_INVCW ; turn on LED
call WaitDit ; wait the appropriate amount of time
bsf PORTA,_INVCW ; turn off LED
call WaitDit ; wait for space between dits and dahs
return
;------end SendCWDit-------------------------------------------------
;------begin SendCWDah-----------------------------------------------
;
; actually sends the dah over the LED
SendCWDah
bcf PORTA,_INVCW ; turn on LED
call WaitDah ; wait the appropriate amount of time
bsf PORTA,_INVCW ; turn off LED
call WaitDit ; wait for space between dits and dahs
return
;------end SendCWDah-------------------------------------------------
;------begin SendCWDigit---------------------------------------------
;
; load CharToSend with the ASCII value of the character to be sent.
SendCWDigit
movlw 0x30 ;we'll subtract 48 from the ASCII value
;since we're only interested in characters
;starting with ASCII 48 (zero)
subwf CharToSend,F ;subtract 48 from the next character ASCII value
movlw HIGH Table ;preset the PCLATH for the computed goto
movwf PCLATH
movf CharToSend,W ;now put the value in W for table lookup
call Table ;return value will be the bit string to send
movwf CharToSend ;store the bit string in CharToSend
; find the Start bit. Start looking at bit 6 and continue down until a 1 is encountered.
; the rest of the bits to send will follow.
rlf CharToSend,F ; get rid of bit 7.
movlw 0x08 ; load the bit counter so we know when we're out of bits.
movwf CharBitCount
bcf STATUS,C
FindCWStartBit
decf CharBitCount,F ; count the bits we check.
rlf CharToSend,F ; look at the next bit. is it a 1? if so, that's our start bit.
btfss STATUS,C
goto FindCWStartBit
SendCWBit
decfsz CharBitCount,F ; check to see if we're out of bits to send.
goto SendNextCWBit
goto DoneSendingCWBits
SendNextCWBit
rlf CharToSend,F ; get the next bit. 1 is a dah, 0 is a dit.
btfss STATUS,C
goto SendADit
goto SendADah
SendADit
call SendCWDit ; send the dit
goto SendCWBit ; do the next dit or dah
SendADah
call SendCWDah ; send the dah
goto SendCWBit ; do the next dit or dah
DoneSendingCWBits
; wait a dah length for the next character.
call WaitWordDah ; use the intercharacter spacing
return
;------end SendCWChar------------------------------------------------
;------begin SendCWAsciiNum--------------------------------------------
;
; load lo, hi with 16 bit unsigned num to send. Sends the resulting
; ASCII sequence of digits in CW via the LED.
SendCWAsciiNum
dodigit 10000
movf digit,W
movwf CharToSend
call SendCWDigit
dodigit 1000
movf digit,W
movwf CharToSend
call SendCWDigit
dodigit 100
movf digit,W
movwf CharToSend
call SendCWDigit
dodigit 10
movf digit,W
movwf CharToSend
call SendCWDigit
movf lo,w ; ls byte is already correct
addlw '0' ; convert to ascii
movwf CharToSend
call SendCWDigit
return ; done
;------end SendCWAsciiNum----------------------------------------------
;------begin SHT11TXRX-----------------------------------------------
;
; Sends a byte command to the SHT11 temp/humidity sensor and retrieves
; a two-byte response. Sends the response back to the PC as an ASCII
; string representation of the number.
;
; Put the byte to send in SHT11Byte before calling this routine.
SHT11TXRX
;make _SHT11_DAT an output
bsf STATUS,RP0 ;switch to bank 1
bcf TRISA,_SHT11_DAT ;make Port A data line an output
bcf STATUS,RP0 ;switch back to bank 0
;send the Transmission Start sequence:
bsf PORTA,_SHT11_DAT ;set the data line high
bsf PORTA,_SHT11_SCK ;take the clock line high
bcf PORTA,_SHT11_DAT ;take the data line low
bcf PORTA,_SHT11_SCK ;take the clock line low
bsf PORTA,_SHT11_SCK ;take the clock line high again
bsf PORTA,_SHT11_DAT ;set the data line high again
;load up the counter to loop through the eight bits to send:
movlw 8
movwf counter
SHT11SendBitLoop
bcf PORTA,_SHT11_SCK ;take the clock line low
btfss SHT11Byte,7 ;is the next bit to send a one?
goto SHT11SendZero ;nope. Go send a zero.
bsf PORTA,_SHT11_DAT ;if it's a one, send it.
goto SHT11SendBit
SHT11SendZero
bcf PORTA,_SHT11_DAT ;set the data line to zero
SHT11SendBit
bsf PORTA,_SHT11_SCK ;take the clock line high to send
rlf SHT11Byte,F ;move the next bit into MSB
decfsz counter,F ;dec the counter and check for zero.
goto SHT11SendBitLoop ;if not zero, more bits to send
bcf PORTA,_SHT11_SCK ;take the clock line low
;no more bits to send. Set the data line to be an input and
;wait for the ack from the SHT11:
bsf STATUS,RP0 ;switch to bank 1
bsf TRISA,_SHT11_DAT ;make Port A data line an input
bcf STATUS,RP0 ;switch back to bank 0
; now look for an ack (SHT11 pulls data line low--should
; happen on the next rise of the SCK line). If it doesn't
; happen, return an 'e' and quit.
bsf PORTA,_SHT11_SCK
SHT11WaitAck
btfss PORTA,_SHT11_DAT
goto SHT11GotAck
;if we don't get an ack, quit, send an 'e1' for error and return.
movlw '1'
movwf digit
call SendErrorCode
goto SHT11TXRXDone
; we got an Ack. Get ready for the data to be returned. take
; the clock line low, and then wait for the data line to be
; pulled low again.
SHT11GotAck
bcf PORTA,_SHT11_SCK
; now wait for the data. It takes approximately 210 ms for
; the temperature measurement, or 55 ms for the humidity
; measurement, so we'll wait up to 255 ms before giving up.
movlw 255
movwf counter
SHT11WaitData
btfss PORTA,_SHT11_DAT
goto SHT11DataReady
call WaitMS
decfsz counter,F
goto SHT11WaitData
;if we don't get the data, quit, send an 'e2' error and return.
movlw '2'
movwf digit
call SendErrorCode
goto SHT11TXRXDone
SHT11DataReady
; get the most sig byte:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -