📄 part3.asm
字号:
; 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 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:
call SHT11GetByte
movf SHT11Byte,W
movwf hi
call SendAck ;acknowledge the byte
; get the least sig byte:
call SHT11GetByte
movf SHT11Byte,W
movwf lo
call SendAck ;acknowledge the byte
call SHT11GetByte ; gets the checksum (not needed)
; Send the data as ASCII:
call SendAsciiNum
; Send the terminating CR and LF:
call SendCRLF
SHT11TXRXDone
return
;------end SHT11TXRX--------------------------------------------------
;------begin SHT11GetByte---------------------------------------------
;
; Gets a byte of data from the SHT11. Assumes that the data
; is ready to be sent by the SHT11. Also assumes that _SHT11_DAT has
; been set to input. Also assumes that _SHT11_SCK has been set to low.
; Returns the byte in SHT11Byte.
SHT11GetByte
; clear SHT11Byte:
clrf SHT11Byte
; set counter to get eight bits
movlw 8
movwf counter
SHT11GetByteLoop
bsf PORTA,_SHT11_SCK ;set the clock high to get the next bit
btfss PORTA,_SHT11_DAT ;is the next bit a one?
goto SHT11GetZeroBit ;no--it's a zero
bsf SHT11Byte,0 ;if it's a one, set the LSB in SHT11Byte
goto SHT11GotBit
SHT11GetZeroBit
bcf SHT11Byte,0 ;set the LSB to zero in SHT11Byte
SHT11GotBit
bcf PORTA,_SHT11_SCK ;set the clock line low again.
decfsz counter,F
goto SHT11GetNextBit
goto SHT11GetByteDone
SHT11GetNextBit
rlf SHT11Byte,F ;move the bits over to get the next bit
goto SHT11GetByteLoop
SHT11GetByteDone
return
;------end SHT11GetByte-----------------------------------------------
;------begin SendAck-------------------------------------------------
;
; send the ack. Set the data line as an output:
SendAck
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
; now send the ack. Take the data line low.
bcf PORTA,_SHT11_DAT
bsf PORTA,_SHT11_SCK
bcf PORTA,_SHT11_SCK
; now make the data line an input again.
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
return
;------end SendAck---------------------------------------------------
;------begin SendErrorCode-------------------------------------------
;
; send error code back to PC. Error code is 'e' plus a digit. Load
; ASCII value of digit into 'digit' register before calling.
SendErrorCode
movlw 'e'
movwf TXChar
call SendAChar
movf digit,W
movwf TXChar
call SendAChar
call SendCRLF
return
;------end SendErrorCode---------------------------------------------
;------begin TellTemperature-----------------------------------------
;This subroutine is called when the 't' command is received. Calls
;SHT11TXRX.
TellTemperature
movlw 3
movwf SHT11Byte
call SHT11TXRX
goto MainLoop
;------end TellTemperature-------------------------------------------
;------begin TellHumidity--------------------------------------------
;This subroutine is called when the 'h' command is received. Calls
;SHT11TXRX.
TellHumidity
movlw 5
movwf SHT11Byte
call SHT11TXRX
goto MainLoop
;------end TellHumidity----------------------------------------------
;------begin SendCRLF------------------------------------------------
;
; Send the terminating CR and LF:
SendCRLF
movlw 13
movwf TXChar
call SendAChar
movlw 10
movwf TXChar
call SendAChar
return
;------end SendCRLF--------------------------------------------------
;------begin SendAsciiNum--------------------------------------------
;
; load lo, hi with 16 bit unsigned num to send
SendAsciiNum
dodigit 10000
movf digit,W
movwf TXChar
call SendAChar
dodigit 1000
movf digit,W
movwf TXChar
call SendAChar
dodigit 100
movf digit,W
movwf TXChar
call SendAChar
dodigit 10
movf digit,W
movwf TXChar
call SendAChar
movf lo,w ; ls byte is already correct
addlw '0' ; convert to ascii
movwf TXChar
call SendAChar
return ; done
; "dosub" is called by the "dodigit" macro defined above.
; Subtract the number in shi/slo from hi/lo until the result
; is negative, incrementing the ascii equivelent each time.
dosub movlw '0'-1
movwf digit
moresub incf digit,F ; increment ASCII character
movf slo,w ; subtract current power of 10
subwf lo,f
movf shi,w
btfss STATUS,C
addlw 1
subwf hi,f
btfsc STATUS,C ; any carry?
goto moresub ; no, keep subtracting
movf slo,w ; reverse the last subtraction
addwf lo,f
movf shi,w
btfsc STATUS,C
addlw 1
addwf hi,f
return
;------end SendAsciiNum----------------------------------------------
;------begin ReportVersion-------------------------------------------
; send a string with the version in it. The string comes from EEPROM
; memory and is null-terminated. The null terminator is not sent. The
; protocol dictates that the string sent is terminated by a CR, which
; is sent. This subroutine is called when the 'v' command is received.
ReportVersion
bcf STATUS,RP0
clrf EEADR ;the string we want starts at the
;beginning of EEPROM memory.
GetNextVersionChar
bsf STATUS,RP0
bsf EECON1,RD
bcf STATUS,RP0
movf EEDATA,W
btfsc STATUS,Z ;if the character in W is null, don't
;send any more.
goto MainLoop
movwf TXChar
call SendAChar
incf EEADR,F
goto GetNextVersionChar
;------end ReportVersion---------------------------------------------
;------begin Idle----------------------------------------------------
;
; Idle should be called whenever the chip is waiting for something
; to happen (waiting for a character to be sent or received, for
; example). Here it's not doing anything.
Idle
return
;------end Idle------------------------------------------------------
;------Main Program--------------------------------------------------
Main
; set up the ports as inputs and outputs as needed.
bsf STATUS,RP0 ;switch to bank 1
movlw 0xFF
movwf TRISB ;make Port B input
movlw 0x00
movwf TRISA ;make Port A output
bcf STATUS,RP0
clrf PORTA
call SerSetup ;set up serial comm routines & int.
; this main program simply waits for characters to be received, then
; calls the handler for the command indicated by the received character.
MainLoop
call GetAChar ;wait for a character
movf RXBuff,W ;move the rx char into W
sublw 't' ;compare with 't' character
btfsc STATUS,Z
goto TellTemperature ;if t, report the temperature
movf RXBuff,W ;move the rx char into W
sublw 'h' ;compare with 'h' character
btfsc STATUS,Z
goto TellHumidity ;if h, report the humidity
movf RXBuff,W ;move the rx char into W
sublw 'v' ;compare with 'v' character
btfsc STATUS,Z
goto ReportVersion ;if v, report the version number
goto MainLoop
;------Version EEPROM------------------------------------------------
org 0x2100
de "WxPIC v0.3b (c) 2002 by NK0E",0x0D,0x0A,0x00 ; Version 0.3b
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -