LIST ; P16F84.INC Standard Header File, Version 1.00 Microchip Technology, Inc. NOLIST ; This header file defines configurations, registers, and other useful bits of ; information for the PIC16F84 microcontroller. These names are taken to match ; the data sheets as closely as possible. ; Note that the processor must be selected before this file is ; included. The processor may be selected the following ways: ; 1. Command line switch: ; C:\ MPASM MYFILE.ASM /PIC16F84 ; 2. LIST directive in the source file ; LIST P=PIC16F84 ; 3. Processor Type entry in the MPASM full-screen interface ;========================================================================== ; ; Revision History ; ;========================================================================== ;Rev: Date: Reason: ;1.00 10/31/95 Initial Release ;========================================================================== ; ; Verify Processor ; ;========================================================================== ; IFNDEF __16F84 IFNDEF __16F84 MESSG "Processor-header file mismatch. Verify selected processor." ENDIF ;========================================================================== ; ; Register Definitions ; ;========================================================================== W EQU H'0000' F EQU H'0001' ;----- Register Files------------------------------------------------------ INDF EQU H'0000' TMR0 EQU H'0001' PCL EQU H'0002' STATUS EQU H'0003' FSR EQU H'0004' PORTA EQU H'0005' PORTB EQU H'0006' EEDATA EQU H'0008' EEADR EQU H'0009' PCLATH EQU H'000A' INTCON EQU H'000B' OPTION_REG EQU H'0081' TRISA EQU H'0085' TRISB EQU H'0086' EECON1 EQU H'0088' EECON2 EQU H'0089' ;----- STATUS Bits -------------------------------------------------------- IRP EQU H'0007' RP1 EQU H'0006' RP0 EQU H'0005' NOT_TO EQU H'0004' NOT_PD EQU H'0003' Z EQU H'0002' DC EQU H'0001' C EQU H'0000' ;----- INTCON Bits -------------------------------------------------------- GIE EQU H'0007' EEIE EQU H'0006' T0IE EQU H'0005' INTE EQU H'0004' RBIE EQU H'0003' T0IF EQU H'0002' INTF EQU H'0001' RBIF EQU H'0000' ;----- OPTION Bits -------------------------------------------------------- NOT_RBPU EQU H'0007' INTEDG EQU H'0006' T0CS EQU H'0005' T0SE EQU H'0004' PSA EQU H'0003' PS2 EQU H'0002' PS1 EQU H'0001' PS0 EQU H'0000' ;----- EECON1 Bits -------------------------------------------------------- EEIF EQU H'0004' WRERR EQU H'0003' WREN EQU H'0002' WR EQU H'0001' RD EQU H'0000' ;========================================================================== ; ; RAM Definition ; ;========================================================================== __MAXRAM H'AF' __BADRAM H'07', H'30'-H'7F', H'87' ;========================================================================== ; ; Configuration Bits ; ;========================================================================== _CP_ON EQU H'3FEF' _CP_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FFF' _PWRTE_OFF EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' TITLE "templog" LIST P=PIC16F84 ; define processor type ;************************************************************ ; I cut and pasted the I2C software from a microchip apnote ;************************************************************ ; Register Definitions ;************************************************************ bitcnt equ 0x0C ; count used for 8 bit rotation of serial data temp equ 0x0D ; temporary variable input equ 0x0E ; value read from serial port eeprom equ 0x0F ; bit buffer tmpad equ 0x10 ; address of temp sensor 0,2,4,6,8,10,12,14 datai equ 0x11 ; data input register datao equ 0x12 ; data output register txbuf equ 0x13 ; transmit buffer count equ 0x14 ; bit counter templ equ 0x15 ; temperature low byte temph equ 0x16 ; temperature high byte adcnt equ 0x17 ; counter for different temperature sensors hunds equ 0x18 ; hundreds digit for BCD conversion tens equ 0x19 ; tens digit for BCD conversion ones equ 0x1A ; ones digit for BCD conversion sign equ 0x1B ; ascii value for sign (space = +,neg = -) ptone equ 0x1C ; ascii value for tenths of a degree ;************************************************************ ; Bit Definitions ;;************************************************************ ; PORT A ackf equ 2 ; acknowledge fail LED (RA2, pin 1) ; PORT B AC equ 1 ; bit #1 used to read if AC unit is on TX equ 2 ; bit #2 used to receive data from serial port (RB2, pin 8) RX equ 3 ; bit #3 used to send data to serial port (RB3, pin 9) led1 equ 4 ; used to turn on led led2 equ 5 ; used to turn on led sclk equ 6 ; serail clock line (RB6, pin 12) sdata equ 7 ; serial data line (RB7, pin 13) do equ 6 ; eeprom output bit di equ 7 ; eeprom input bit ; use a 2.4576MHz XTAL and no prescaler on timer0 org 0 goto start org 0x30 ;************************************************************** ; Start Bit Subroutine ; this routine generates a start bit ; (Low going data line while clock is high) ;************************************************************** ; BSTART bsf PORTB,sdata ; make sure data is high ; movlw b'00111111' ; tris PORTB ; set data and clock lines for output bsf STATUS,RP0 ; bank 1 bcf TRISB,sdata ; set data for output bcf TRISB,sclk ; set clock for output bcf STATUS,RP0 ; bank 0 bcf PORTB,sclk ; make sure clock is low nop bsf PORTB,sclk ; set clock high nop nop nop nop nop bcf PORTB,sdata ; data line goes low during ; high clock for start bit nop nop nop nop nop ; timing adjustment bcf PORTB,sclk ; start clock train nop nop retlw 0 ;************************************************************ ; Stop Bit Subroutine ; This routine generates a stop bit ; (High going data line while clock is high) ;************************************************************ BSTOP ; movlw b'00111111' ; ; tris PORTB ; set data/clock lines as outputs bsf STATUS,RP0 ; bank 1 bcf TRISB,sdata ; set data for output bcf TRISB,sclk ; set clock for output bcf STATUS,RP0 ; bank 0 bcf PORTB,sdata ; make sure data line is low nop nop nop bsf PORTB,sclk ; set clock high nop nop nop bsf PORTB,sdata ; data goes high while clock high ; for stop bit nop nop bcf PORTB,sclk ; set clock low again nop nop nop retlw 0 ;************************************************************* ; BITOUT routine takes one bit of data in 'do' and ; transmits it to the serial EE device ;************************************************************* BITOUT ; movlw b'00111111' ; set data,clock as outputs ; tris PORTB bsf STATUS,RP0 ; bank 1 bcf TRISB,sdata ; set data for output bcf TRISB,sclk ; set clock for output bcf STATUS,RP0 ; bank 0 btfss eeprom,do ; check for state of data bit to xmit goto bitlow ; bsf PORTB,sdata ; set data line high goto clkout ; go toggle the clock bitlow bcf PORTB,sdata ; output a low bit clkout bsf PORTB,sclk ; set clock line high nop nop nop nop bcf PORTB,sclk ; return clock line low retlw 0 ;************************************************************** ; BITIN routine reads one bit of data from the ; serial EE device and stores it in 'di' ;************************************************************** BITIN bsf eeprom,di ; assume input bit is high ; movlw b'10111111' ; make sdata an input line ; tris PORTB bsf STATUS,RP0 ; bank 1 bcf TRISB,sclk ; set clock for output bsf TRISB,sdata ; set data for input bcf STATUS,RP0 ; bank 0 bsf PORTB,sdata ; set sdata line high (input) bsf PORTB,sclk ; set clock line high nop ; just sit here a sec nop nop nop nop btfss PORTB,sdata ; read the data bit bcf eeprom,di ; input bit was low bcf PORTB,sclk ; set clock line low retlw 0 ;**************************************************************** ; Transmit Data Subroutine ; This routine takes the byte of data stored in the ; 'datao' register and transmits it to the serial EE device. ; It will then send 1 more clock to the serial EE for the ; acknowledge bit. If the ack bit from the part was low ; then the transmission was sucessful. If it is high, then ; the device did not send a proper ack bit and the ack ; fail LED will be turned on. ;**************************************************************** TXDAT movlw .8 movwf count ; set the #bits to 8 TXLP bcf eeprom,do ; assume bit out is low btfsc txbuf,7 ; is bit out really low? bsf eeprom,do ; otherwise data bit =1 call BITOUT ; serial data out rlf txbuf, F ; rotate txbuf left decfsz count, F ; 8 bits done? goto TXLP ; no - go again call BITIN ; read ack bit btfsc eeprom,di ; check ack bit bsf PORTA,ackf ; set acknowledge fail LED if the retlw 0 ;**************************************************************** ; Receive data routine ; This routine reads one byte of data from the part ; into the 'datai' register. It then sends a high ; ack bit to indicate that no more data is to be read ;**************************************************************** RXDAT clrf datai ; clear input buffer movlw .8 ; set # bits to 8 movwf count bcf STATUS,C ; clear carry bit RXLP rlf datai, F ; rotate datai 1 bit left call BITIN ; read a bit btfsc eeprom,di bsf datai,0 ; set bit 0 if necessary decfsz count, F ; 8 bits done? goto RXLP ; no, do another retlw 0 ;*************************************************************** ; convert number in temph to BCD (hunds, tens, ones) ; and templ to 1/10 degrees instead of 1/16 (ptone) bcd ; if two's compliment (MSB = 1 -> negative) movlw 0x20 ; ascii for space movwf sign ; assume positive (print space not +) btfss temph,7 ; check if negative goto downd ; if positive skip down movlw 0xff ; all ones for xor xorwf temph,1 ; if negative invert xorwf templ,1 ; if negative invert incf templ,1 ; and add one btfsc STATUS,Z ; if zero bit set then incf temph,1 ; add one to MSB movlw 0x2D ; ascii for "-" movwf sign ; set sign value downd clrf hunds ; zero out all digits clrf tens clrf ones ; BCD conversion for hundreds digit upa movlw d'100' ; w = 100 subwf temph,0 ; w = temph - 100 btfss STATUS,C ; check if negative goto downa ; if negative then done - skip down movwf temph ; if positive change temph incf hunds,1 ; and inc the hundreds digit goto upa ; stay in loop downa clrwdt ; clear watchdog timer ; BCD conversion for tens digit upb movlw d'10' ; w = 10 subwf temph,0 ; w = temph - 10 btfss STATUS,C ; check if negative goto downb ; if negative then done - skip down movwf temph ; if positive change temph incf tens,1 ; and inc the tens digit goto upb ; stay in loop downb clrwdt ; clear watchdog timer ; BCD conversion for ones digit upc movlw d'1' ; w = 1 subwf temph,0 ; w = temph - 1 btfss STATUS,C ; check if negative goto downc ; if negative then done - skip down movwf temph ; if positive change temph incf ones,1 ; and inc the ones digit goto upc ; stay in loop downc ; 1/16 to 1/10 conversion swapf templ,0 ; swap high and low nibble put in w andlw 0x0F ; mask out any non-zero bits addwf PCL,1 ; jump to the proper value and return ; with the ascii value in w retlw 0x30 ; 0 -> 0 -> 0.0 retlw 0x31 ; 1 -> 0.0625 -> 0.1 retlw 0x31 ; 2 -> 0.125 -> 0.1 retlw 0x32 ; 3 -> 0.185 -> 0.2 retlw 0x32 ; 4 -> 0.25 -> 0.2 retlw 0x33 ; 5 -> 0.3125 -> 0.3 retlw 0x34 ; 6 -> 0.375 -> 0.4 retlw 0x34 ; 7 -> 0.4375 -> 0.4 retlw 0x35 ; 8 -> 0.5 -> 0.5 retlw 0x36 ; 9 -> 0.5625 -> 0.6 retlw 0x36 ; 10 -> 0.625 -> 0.6 retlw 0x37 ; 11 -> 0.6875 -> 0.7 retlw 0x37 ; 12 -> 0.75 -> 0.7 retlw 0x38 ; 13 -> 0.8125 -> 0.8 retlw 0x39 ; 14 -> 0.875 -> 0.9 retlw 0x39 ; 15 -> 0.9375 -> 0.9 ;************************************************************** ; rtemp (reads the temperature from the DS1721) ; (It should power up in continuous 12 bit conversion mode) ; Send a start convert command (0x51) ; Wait >1.2 Seconds for the 12 bit conversion to be completed ; Read the temperature ; temperature is returned in temph & templ (MSB & LSB's 0000) ; The address of the DS1721 (0,2,4,6,8,10,12 or 14) is stored in tmpad ;*************************************************************** rtemp bsf PORTB,led1 ; turn on LED1 ; set timer overflow rate (use max divide ratio on prescaler with timer) clrwdt ; clear watchdog timer bsf STATUS,RP0 ; bank 1 (upper half of memory on pic16f84) movlw b'00000111' ; use prescaler /256 for TMR0 movwf OPTION_REG bcf STATUS,RP0 ; bank 0 (lower half of memory on pic16F84) ; send start convert command to DS1721 clrwdt ; clear watchdog timer call BSTART ; generate start bit ; movlw 0x9E ; write command (1001 AAA W) movf tmpad,0 ; put tmpad in w iorlw 0x90 ; IOR write command with address bits movwf txbuf ; put in transmit buffer call TXDAT ; and send it clrwdt ; clear watchdog timer movlw 0x51 ; start convert command (0x51) movwf txbuf ; put in transmit buffer call TXDAT ; and send it call BSTOP ; generate stop bit ; wait for 12 overflows of the timer (12 * ~107ms = ~1.3 Seconds) clrf TMR0 ; clear timer 0 bcf INTCON,T0IF ; clear timer overflow bit movlw .12 ; do loop 12 times movwf temp ; use temp as the loop counter up2 clrwdt ; clear watchdog timer btfss INTCON,T0IF ; check if timer0 has overflowed goto up2 ; if no wait for it to overflow bcf INTCON,T0IF ; clear timer overflow bit decfsz temp,1 ; check if done 12 times yet goto up2 ; if no do loop again ; send read temperature command to DS1721 and read two bytes call BSTART ; generate start bit ; movlw 0x9E ; write command (1001 AAA W) movf tmpad,0 ; put tmpad in w iorlw 0x90 ; IOR write command with address bits movwf txbuf ; put in transmit buffer call TXDAT ; and send it clrwdt ; clear watchdog timer movlw 0xAA ; read temperature command (0xAA) movwf txbuf ; put in transmit buffer call TXDAT ; and send it clrwdt ; clear watchdog timer call BSTART ; repeate the start bit ; movlw 0x9F ; read command command (1001 AAA R) movf tmpad,0 ; put tmpad in w iorlw 0x91 ; IOR read command with address bits movwf txbuf ; put in transmit buffer call TXDAT ; and send it clrwdt ; clear watchdog timer call RXDAT ; read 1 byte from device clrwdt ; clear watchdog timer bcf eeprom,do ; set for low ack bit call BITOUT ; send ack bit movf datai,W ; move byte to w movwf temph ; move w to temperature high byte call RXDAT ; read 1 byte from device clrwdt ; clear watchdog timer bsf eeprom,do ; set for high ack bit call BITOUT ; send ack bit movf datai,W ; move byte to w movwf templ ; move w to temperature low byte call BSTOP ; generate stop bit ; swapf templ,F ; put the fractional temp in the lower nibble bcf PORTB,led1 ; turn off LED1 retlw 0 ;*************************************************************** ; sends the character (stored in temp) to the max232 chip at whatever baud rate the ; prescaler determines sbyte call delay ; start at correct time movlw 0x08 ; set the bit counter for sending a byte movwf bitcnt ; 8 bits nop ; sync with the other bits nop bcf PORTB,RX ; send start bit again call delay ; wait till time to send next bit call dout ; send the next bit decfsz bitcnt,1 ; if all 8 bits haven't been sent goto again ; then send the next bit call delay ; wait until time to send the stop bit nop ; sync with the other bits nop nop nop bsf PORTB,RX ; send the stop bit return ;*************************************************************** ; reads the serial line (TX) at whatever baud rate the prescaler determines rbyte call delay ; wait for start bit to finish movlw d'131' ; time offset to allow for 1/2 bit delay movwf TMR0 movlw 0x08 ; set the bit counter to receive a byte movwf bitcnt ; 8 bits again2 call delay ; wait for time to elapse rrf input,1 ; rotate input right one bit bcf input,7 ; clear MSB of input btfsc PORTB,TX ; check if TX is low bsf input,7 ; if not set the MSB of input decfsz bitcnt,1 ; otherwise dec the loop counter goto again2 ; and continue with the other bits call delay ; wait untill 1/2 of the stop bit is sent return ; before returning to the calling procedure ;*************************************************************** ; sets or clears the serial out (TX) line dout btfss temp,0 ; check lsb of temp bcf PORTB,RX ; if zero clear RX bit btfsc temp,0 ; check lsb of temp bsf PORTB,RX ; if one set RX bit rrf temp,1 ; rotate byte for next time in the loop return ;*************************************************************** ; delay until time for next bit to be sent or read (depends on baud rate) delay bcf INTCON,T0IF ; if yes clear bit and return upone clrwdt ; clear the watchdog timer btfss INTCON,T0IF ; check if timer0 has overflowed goto upone ; if no wait for it to overflow bcf INTCON,T0IF ; if yes clear bit and return tst return ; tst label used as break point in simulator ;*************************************************************** ; send the ascii temperature out the port sndasc bsf PORTB,led2 ; turn on LED2 ; send out neg sign if neg or space if positive movf sign,0 ; w = ascii char for sign movwf temp ; temp = w call sbyte ; send out the port ; send out hundreds digit movf hunds,0 ; w = hunds btfsc STATUS,Z ; check if w = 0 movlw 0xF0 ; (-10h) if yes send space not 0 (30h-10h=20h=" ") addlw 0x30 ; convert to ascii (30h = "0") movwf temp ; temp = hunds digit (or space if 0) call sbyte ; send out the port ; send out tens digit movf tens,0 ; w = tens btfsc STATUS,Z ; check if w = 0 movlw 0xF0 ; (-10h) if yes send space not 0 (30h-10h=20h=" ") addlw 0x30 ; convert to ascii (30h = "0") movwf temp ; temp = hunds digit (or space if 0) call sbyte ; send out the port ; send out ones digit movf ones,0 ; w = ones addlw 0x30 ; convert to ascii (30h = "0") movwf temp ; temp = hunds digit (or space if 0) call sbyte ; send out the port ; send out a decimal point movlw 0x2E ; ascii for "." movwf temp ; temp = "." call sbyte ; sent out the port ; send out the tenths of a degree movf ptone,0 ; w = tenths of a degree movwf temp ; temp = w call sbyte ; send it out the port ; send out 3 spaces movlw 0x20 ; ascii for " " movwf temp ; temp = space call sbyte ; sent out the port movlw 0x20 ; ascii for " " movwf temp ; temp = space call sbyte ; sent out the port movlw 0x20 ; ascii for " " movwf temp ; temp = space call sbyte ; sent out the port bcf PORTB,led2 ; turn off LED2 return ; return from procedure ;*************************************************************** ; Beginnig of main routine Note: baud rate and timing will be off if a 2.45764Mhz XTAL isn't used) start bsf STATUS,RP0 ; bank 1 (upper half of memory on pic16f84) movlw 0xff ; set PORTA to all inputs movwf TRISA movlw b'10000111' ; set PORTB ; RB1 = AC - used to read if AC unit is on (input) ; RB2 = TX - used to receive serial data (input) ; RB3 = RX - used to send serial data (output) ; RB4 = LED1 (output) ; RB5 = LED2 (output) ; RB6 = sclk for I2C (output) ; RB7 = sdata for I2C (default input) movwf TRISB movlw b'00001111' ; bypass prescaler use Fosc/4 as clk (2400 baud) movwf OPTION_REG ; RBPU NOT (bit 7) = 0 (week internal pull-ups enabled) bcf STATUS,RP0 ; bank 0 (lower half of memory on pic16F84) clrf INTCON ; disable all interupts clrf EEADR ; clear bit 6 & 7 of EEADR to save power bsf PORTB,RX ; default is stop bit state for RS232 loop1 ; set up timer for delay (prescaler for TMR0) clrwdt ; clear watchdog timer bsf STATUS,RP0 ; bank 1 (upper half of memory on pic16f84) movlw b'00000111' ; use prescaler /256 for TMR0 movwf OPTION_REG bcf STATUS,RP0 ; bank 0 (lower half of memory on pic16F84) clrf TMR0 ; clear timer and overflow bit movlw d'30' ; delay about three seconds (30 * 0.107sec) movwf bitcnt up123 call delay decfsz bitcnt,1 goto up123 movlw 0x03 ; three different temp sensors (0, 1 & 2) movwf adcnt ; adcnt will be the loop counter for the temp sensors tplp movf adcnt,0 ; w = loop counter (for three temp sensors) movwf tmpad ; put in temp sensor address reg decf tmpad,1 ; subtract one (1,2,3 -> 0,1,2) rlf tmpad,1 ; mult by two (0,1,2 -> 0,2,4) because AAAW or AAAR ; depending on read or write command - see rtemp bcf tmpad,0 ; clear the LSB incase carry was high durring shift call rtemp ; read temperure (~1.3 seconds for 12 bits) call bcd ; convert temp to BCD (hunds, tens, ones, 1/10) movwf ptone ; store tenths ascii value ; set up timer for serial port (Fosc/4) - 2.4576MHz XTAL clrwdt ; clear watchdog timer bsf STATUS,RP0 ; bank 1 (upper half of memory on pic16f84) movlw b'00000000' ; use prescaler /2 for 1200 baud movwf OPTION_REG ; RBPU NOT (bit 7) = 0 (week internal pull-ups enabled) bcf STATUS,RP0 ; bank 0 (lower half of memory on pic16F84) clrf TMR0 ; clear timer and overflow bit call sndasc ; send ascii temperature out the port decfsz adcnt,1 ; dec the loop counter goto tplp ; if not 0, read the next temp sensor ; set up timer for serial port (Fosc/4) - 2.4576MHz XTAL clrwdt ; clear watchdog timer bsf STATUS,RP0 ; bank 1 (upper half of memory on pic16f84) movlw b'00000000' ; use prescaler /2 for 1200 baud movwf OPTION_REG ; RBPU NOT (bit 7) = 0 (week internal pull-ups enabled) bcf STATUS,RP0 ; bank 0 (lower half of memory on pic16F84) clrf TMR0 ; clear timer and overflow bit ; check if AC unit is ON (input low) or OFF (input high) movlw 0x30 ; assume AC off & load ascii 0 btfss PORTB,AC ; check if AC input is low (AC unit ON) movlw 0x31 ; load ascii 1 movwf temp ; temp = w call sbyte ; send it out the port ; send out carriage return movlw 0x0D ; ascii for CR movwf temp ; temp = w call sbyte ; send it out the port ; send out line feed movlw 0x0A ; ascii for LF movwf temp ; temp = w call sbyte ; send it out the port goto loop1 ; loop forever end ; shouldn't get here