Beruflich Dokumente
Kultur Dokumente
The purpose
; of this project is to provide a hardware interface which
measures
; temperature, wind speed, wind direction, humidity, and pressure
; and communicates it to a PC via serial communications when
; requested. Note that the data collected and transmitted must be
; processed by the PC in order to obtain the actual measurement
; values (i.e. no calibration is done in the PIC code).
;
; The hardware circuit makes use of two major components: the
; PIC16F84 itself and a MAX232 TTL-RS232 level converter.
; The MAX232 converts the TTL signals from the PIC to RS232
levels
; for the PC (and vice versa).
;
; The PIC16F84 pin assignments are as follows:
;
; RA1: serial out to PC
; RA2: clock out to SHT11 temp/humid sensor
; RA3: data in/out for SHT11 temp/humid sensor
; RB0: serial in from PC (generates interrupt)
;
; This software implements the following command set:
;
; Received Reply Description
;-----------------------------------
; 't' 12345 CR LF Get the temperature raw data. Five
digits
; or e1 CR LF are always returned, with leading zeroes
; or e2 CR LF if necessary, followed by a carriage
return
; and line feed. See the SHT11 data sheet
; for instructions on computing the
temperature.
; A return of e1 indicates that the SHT11
didn't
; acknowledge the request. A return of e2
; indicates that no data was returned by
the SHT11
; within the wait period (255 ms).
; 'h' 12345 CR LF Get the humidity raw data. Five digits
; or e1 CR LF are always returned, with leading zeroes
; or e2 CR LF if necessary, followed by a carriage
return
; and line feed. See the SHT11 data sheet
for
; instructions on computing the humidity.
; A return of e1 indicates that the SHT11
didn't
; acknowledge the request. A return of e2
; indicates that no data was returned by
the SHT11
; within the wait period (255 ms).
; 'v' version info Gets the version number of the firmware.
; returns an ASCII string followed by a
; carriage return and line feed.
;
; Written using Microchip MPLAB v5.40
;
; Please direct any questions, comments, or suggestions to the
; author: David Ek
; nk0e@earthlink.net
;
; History:
;
; Rev 1 (23 Jul 2002):
; Creation. Returns dummy temperature data. This version used
; for installment 2 of the PIC WX articles in QQ.
; Rev 2 (26 Sep 2002):
; Added code for the Sensirion SHT11 temperature/humidity
sensor
; for installment 3 of the PIC WX articles in QQ.
;
;----------------------------------------------------------------
list p=16f84
radix dec
__config _CP_OFF & _WDT_OFF & _XT_OSC
include "p16f84.inc"
; defines:
; These are used by the serial comm routines for timing. Note
that
; slower speeds may not work well because the delays might be
larger
; than 255, requiring the use of the prescalar.
; memory locations:
cblock 0x0C
endc
org 0x00
goto Main
org 0x04
;----------------------------------------------------------------
----
;-----Serial Communication
Routines----------------------------------
;----------------------------------------------------------------
----
;
; The serial comm routines generate 1 start bit, 8 data bits, 1
stop bit,
; no parity. The baud rate is determined by the delay programmed
; into the onboard timer. The sending and receiving is interrupt
driven,
; meaning other tasks can be carried on while the characters are
being
; sent and received.
;
;-----Main Interrupt
Routine-----------------------------------------
;
; for timing: 4 cycles from interrupt time to get here.
Int
movwf WSave
swapf STATUS,W ;use swapf to prevent any
movwf SSave ;status flags from being changed
btfsc INTCON,T0IE
goto DoBit ;we're in the middle of sending or
;receiving
retfie
SerSetup
clrf TMR0
bsf STATUS,RP0
clrwdt ;set bits in OPTION_REG to
movlw b'10001000' ;enable internal clock counting,
movwf OPTION_REG ;disable watchdog timer.
bcf STATUS,RP0 ;switch to bank 0
movlw b'00000001'
movwf PORTB
clrf SerialReg
return
;------end
SetSetup--------------------------------------------------
;------Subroutine
StartRX--------------------------------------------
;
; This subroutine is called by the main interrupt routine when an
; external interrupt on RB0 occurs. This means we're receiving
the
; start bit for a character. We want to enable the external TMR0
; interrupt and prepare to receive the character.
StartRX
btfsc PORTB,_SER_IN
goto Restore
movlw _BitRxDelay
movwf TMR0 ;4 cycles from read of PORTB
movlw b'00100000'
movwf INTCON
movlw b'00000010'
movwf SerialReg
; initialize BitCount:
movlw 8
movwf BitCount
goto Restore
;------end
StartRX---------------------------------------------------
;------
DoBit---------------------------------------------------------
;
; sends or receives the next bit. Bits are sent/received from
least
; to most significant bit.
DoBit
bcf INTCON,T0IF
; Are we receiving?
btfsc SerialReg,2
goto Sending
movf BitCount,F
btfsc STATUS,Z
goto GetStopBit
decf BitCount,F
movlw _BitRxDelay
movwf TMR0 ;21 cycles from start of interrupt
goto Restore
GetStopBit
btfss PORTB,_SER_IN ;is the RX line low? If so, it's not
goto Done ;the stop bit. Otherwise, set the
movlw b'00000001' ;SerialReg to show a character has
movwf SerialReg ;been received
movf RXChar,W ;copy the received character to RXBuff
movwf RXBuff
goto Done
Sending
btfsc SerialReg,3
goto Done
movf BitCount,F
btfsc STATUS,Z ;18th cycle
goto SendStopBit
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.
EndDoBit
decf BitCount,F
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
movlw _StopTxDelay
movwf TMR0 ;27th cycle
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
bcf PORTA,_SER_OUT
movlw b'00000110'
movwf SerialReg
movlw b'10100000'
movwf INTCON
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.
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
movlw 8
movwf counter
SHT11SendBitLoop
bcf PORTA,_SHT11_SCK ;take the clock line low
SHT11SendZero
bcf PORTA,_SHT11_DAT ;set the data line to zero
SHT11SendBit
bsf PORTA,_SHT11_SCK ;take the clock line high to send
;no more bits to send. Set the data line to be an input and
;wait for the ack from the SHT11:
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
SHT11GotAck
bcf PORTA,_SHT11_SCK
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
call SHT11GetByte
movf SHT11Byte,W
movwf hi
call SendAck ;acknowledge the byte
call SHT11GetByte
movf SHT11Byte,W
movwf lo
call SendAck ;acknowledge the byte
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
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
bcf PORTA,_SHT11_DAT
bsf PORTA,_SHT11_SCK
bcf PORTA,_SHT11_SCK
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-----------------------------------------
TellTemperature
movlw 3
movwf SHT11Byte
call SHT11TXRX
goto MainLoop
;------end
TellTemperature-------------------------------------------
;------begin
TellHumidity--------------------------------------------
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
;------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
clrf PORTA
MainLoop
call GetAChar ;wait for a character
goto MainLoop
;------Version
EEPROM------------------------------------------------
org 0x2100
de "WxPIC v0.3b (c) 2002 by NK0E",0x0D,0x0A,0x00 ;
Version 0.3b
end