;-----------------------------------------------------------
; Subroutines for PIC10F322
; Author: Terry Hitt
; Last change: Feb 2, 2012
;-----------------------------------------------------------
; NOTE: !!! Routines are timed for 16MHz clock !!!
;-----------------------------------------------------------
; Routines Provided:
; Delay_uSec_W - Delays "W" microseconds (min = 3)
; Delay_mSec_W - Delays "W" milliseconds
; Delay_mSec - Delays "delay" milliseconds. Destroys "delay"
; Delay_10mSec_W - Delays "W" x 10 milliseconds
; Delay_10mSec - Delays "delay" x 10 milliseconds. Destroys "delay"
;
; Serial_In - Receives a byte, stores it in "serialData"
; You must define SERINPIN in your code before include.
; Default baud rate is 9600. Define InBaud to change.
;
; Serial_Out_W - Sends byte value in "W" to serial out pin as character
; You must define SEROUTPIN in your code before include.
; Default baud rate is 9600. Define OutBaud to change.
; Serial_Out - Sends byte value in "serialData" to serial out pin as character. Destroys "serialData"
; You must define SEROUTPIN in your code before include.
; Default baud rate is 9600. Define OutBaud to change.
; Print_Byte_W - Sends byte value in "W" to serial out pin as ASCII
; You must define SEROUTPIN in your code before include.
; Default baud rate is 9600. Define OutBaud to change.
; Print_Byte - Sends byte value in "printValue" to serial out pin as ASCII. Destroys "printValue"
; You must define SEROUTPIN in your code before include.
; Default baud rate is 9600. Define OutBaud to change.
; Print_Word - Sends word value in "printValue_LSB" "printValue_MSB" to the serial out pin.
; Destroys "printValue_LSB", "printValue_MSB"
; You must define SEROUTPIN in your code before include.
; Default baud rate is 9600. Define OutBaud to change.
;
; OW_Reset - Resets the 1-Wire bus
; You must define OWPIN in your code before include.
; OW_Read - Read a byte from the 1-wire bus. Value returned "W" and "owData"
; You must define OWPIN in your code before include.
; OW_Write_W - Write value in "W" to the 1-wire bus
; You must define OWPIN in your code before include.
; OW_Write - Write the value in "owData" to the 1-wire bus
; You must define OWPIN in your code before include.
;
; I2C_Start - Creates I2C start condition
; I2C_Stop - Creates I2C stop condition
; I2C_Read - Reads a byte from the I2C bus. Value in W and i2cData
; I2C_Write_W - Writes "w" to the I2C bus
; I2C_Write - Writes value in "i2cData" to I2C bus
;-----------------------------------------------------------
; You may save code space by omitting code by defining these:
; #DEFINE No_Delay_mSec
; #DEFINE No_Delay_10mSec
; #DEFINE No_Print_Byte
; #DEFINE No_Print_Word
; #DEFINE No_I2C_Read
;-----------------------------------------------------------
; Serial pin is high when at idle
; Default baud rate is 9600
; Set baud rate by defineing OutBaud and InBaud (Range 19200 to 4800)
; For Example:
; #DEFINE OutBaud d'19200'
;-----------------------------------------------------------
; YOU MUST DEFINE THE PINS IN YOUR CODE
; If a pin is not defined, the routines that use that pin are not included
;
;SEROUTPIN EQU d'0'
;SERINPIN EQU d'1'
;SCLPIN EQU d'0'
;SDAPIN EQU d'1'
;OWPIN EQU d'2'
radix dec
; Subroutine variables. Uses RAM from 0x74 to 0x7f
delayuSec EQU 0x74
delay EQU 0x75 ; mSec value for delay_mSec routine
delayTemp EQU 0x76 ; Temp for delay_mSec routine
printValue EQU 0x77 ; Value to be printed (destroyed by subroutine)
printValue_LSB EQU 0x78 ; LSB of 16-bit value to be printed
printValue_MSB EQU 0x79 ; MSB of 16-bit value to be printed
printChar EQU 0x7a ; Char (digit) to be printed
tempW_LSB EQU 0x7b ; LSB of temporary variable
tempW_MSB EQU 0x7c ; MSB of temporary variable
serialData EQU 0x7d ; Data for Serial_Out routine
bitCnt EQU 0x7e ; Bit count for Serial_Out routine
owData EQU 0x7f ; Data for 1-wire device
; --------------------------------------------------------------
; Delay microSeconds
; CALL Delay_uSec_W ; value is in "W" min=3
; "W" is preserved; all flags are preserved
; --------------------------------------------------------------
Delay_uSec_W:
movwf delayuSec ; Save value
decfsz delayuSec,f ; Adjust for movlw,call,return overhead without affecting flags
decfsz delayuSec,f
nop
nop
decfsz delayuSec,f
goto $-2
return
#IFNDEF No_Delay_mSec
; --------------------------------------------------------------
; Delay milliSeconds
; CALL Delay_mSec_W ; value is in "W" 0 = 256mSec
; CALL Delay_mSec ; value to send is in "delay" 0 = 256mSec
; Destroys value in "delay"
; --------------------------------------------------------------
Delay_mSec_W: ; Delay "W" milliseconds
movwf delay ; Set delay variable
Delay_mSec:
movlw 4 ; (1)
movwf delayTemp ; (1)
movlw 249 ; (1)
call Delay_uSec_W
decfsz delayTemp,F ; (1)
goto $-3 ; (2)
decfsz delay,F ; Wait another millisecond ?
goto Delay_mSec ; Yes, go back again
retlw 0x00 ; No, Done
#ENDIF ; #IFNDEF No_Delay_mSec
; --------------------------------------------------------------
; Delay 10 milliSeconds
; CALL Delay_10mSec_W ; value is in "W" 0 = 2560mSec
; CALL Delay_10mSec ; value to send is in "delay" 0 = 2560mSec
; Destroys value in "delay"
; --------------------------------------------------------------
#IFNDEF No_Delay_10mSec
Delay_10mSec_W: ; Delay "W" milliseconds
movwf delay ; Set delay variable
Delay_10mSec:
movlw 40 ; (1)
movwf delayTemp ; (1)
movlw 249 ; (1)
call Delay_uSec_W
decfsz delayTemp,F ; (1)
goto $-3 ; (2)
decfsz delay,F ; Wait another millisecond ?
goto Delay_10mSec ; Yes, go back again
retlw 0x00 ; No, Done
#ENDIF ; #IFNDEF No_Delay_10mSec
#IFDEF SEROUTPIN
#IFNDEF No_Print_Word
; -----------------------------------------------------
; Send word value as ASCII to Serial_Out routine
; Does not print leading zeros
; CALL Print_Word ; value to be printed in "printValue"
; Destroys value in "printValue"
; Uses subroutine Serial_Out_W
; -----------------------------------------------------
Print_Word:
clrf printChar ; Set char to zero
; Do 10,000's digit
movlw 39 ; Set value to subtract to 10,000 for 10,000's digit
movwf tempW_MSB
movlw 16
movwf tempW_LSB
call WDigit ; Returns with "W" set to 48d
andwf printChar,F ; Zero the char, but keep the 32&16 bits.
; Do 1,000's digit
movlw 3 ; Set value to subtract to 1,000 for 1,000's digit
movwf tempW_MSB
movlw 232
movwf tempW_LSB
call WDigit ; Returns with "W" set to 48d
andwf printChar,F ; Zero the char, but keep the 32&16 bits
; Do 100's digit
clrf tempW_MSB ; Set value to subtract to 100 for 100's digit
movlw 100
movwf tempW_LSB
call WDigit ; Returns with "W" set to 48d
andwf printChar,F ; Zero the char, but keep the 32&16 bits
; Do 10's digit
movlw 10 ; Set value to subtract to 10 for 10's digit
movwf tempW_LSB
call WDigit ; Returns with "W" set to 48d
andwf printChar,F ; Zero the char, but keep the 32&16 bits
; Do 1's digit
addwf printValue_LSB,W ; 1's digit always prints, just add 48 to value left
goto Serial_Out_W ; Print digit and return
WDigit:
incf printChar,F ; Increment print char
movf tempW_LSB,W ; Prepare to subtract LSB values
subwf printValue_LSB,F ; Subtract LSB values
movf tempW_MSB,W ; Prepare to subtract MSB values (no borrow on LSB)
btfss STATUS,C ; If LSB caused a underflow,
incf tempW_MSB,W ; subtract 1 more from MSB
subwf printValue_MSB,F ; Subtract MSB of digit value from value to be printed
btfsc STATUS,C ; Did we underflow ?
goto WDigit ; No, then repeat
addwf printValue_MSB,F ; Yes, then add MSB digit value back to value to be printed
movf tempW_LSB,W ; and LSB as well
addwf printValue_LSB,F
decf printChar,W ; Print char will be 1 higher than value, dec it
btfsc STATUS,Z ; If print char is zero, then don't print it
retlw 48 ; Digit was leading zero, don't print it, just return
iorlw 48 ; Make char ASCI by setting 32 & 16 bits
movwf printChar ; Save value so next digit knows this wasn't a leading zero
goto Serial_Out_W ; Falls into Serial_Out_W
#ENDIF ; #IFNDEF No_Print_Word
#IFNDEF No_Print_Byte
; -----------------------------------------------------
; Send byte value as ASCII to Serial_Out routine
; Does not print leading zeros
; CALL Print_W ; value to be printed in "W"
; CALL Print ; value to be printed in "printValue"
; Destroys value in "printValue"
; Uses subroutine Serial_Out_W
; -----------------------------------------------------
Print_Byte_W:
movwf printValue ; Save value to print
Print_Byte:
clrf printChar ; Set char to zero
movlw 100 ; Set value to subtract to 100 for 100's digit
call BDigit ; Returns with "W" set to 48d
andwf printChar,F ; Zero the char, but keep the 32&16 bits then we can tell that
; the 100's character WASN'T a zero if they are set
movlw 10 ; Set value to subtract to 10 for 10's digit
call BDigit ; Returns with "W" set to 48d
addwf printValue,W ; 1's digit always prints, just add 48 to value left
goto Serial_Out_W ; Print digit and return
BDigit:
incf printChar,F ; Increment print char
subwf printValue,F ; Subtract digit value from value to be printed
btfsc STATUS,C ; Did we underflow ?
goto BDigit ; No, then repeat
addwf printValue,F ; Yes, then add digit value back to value to be printed
decf printChar,W ; Print char will be 1 higher than value, dec it
btfsc STATUS,Z ; If print char is zero, then don't print it
retlw 48 ; Digit was leading zero, don't print it, just return
iorlw 48 ; Make char ASCI by setting 32 & 16 bits
movwf printChar ; Save value so next digit knows this wasn't a leading zero
; Falls into Serial_Out_W
#ENDIF ; #IFNDEF No_Print_Byte
; -----------------------------------------------------
; Sends a character to "SEROUTPIN" as serial data
; If clock is 4MHz baud rate is 19200
; CALL Serial_Out_W ; value to send is in "W"
; CALL Serial_Out ; value to send is in "serialData"
; Destroys "serialData" & "bitCnt"
; -----------------------------------------------------
#IFNDEF OutBaud
#DEFINE OutBaud 9600
#ENDIF
Serial_Out_W: ; Sends value in "W" on pin "SEROUTPIN"
movwf serialData
Serial_Out:
movlw 10 ; Send 10 bits (including start bit and stop bit)
movwf bitCnt
bcf LATA,SEROUTPIN ; Set pin to start bit state (same as data 0 bit state)
SerOut_NextBit:
movlw (960000 / OutBaud) ; Delay for each bit
call Delay_uSec_W
btfsc serialData,0 ; set pin to data bit state
bsf LATA,SEROUTPIN
btfss serialData,0
bcf LATA,SEROUTPIN
bsf STATUS,C ; rotate data bits and shift in stop bit value (1 bit)
rrf serialData,F
decfsz bitCnt,F ; loop until all bits are done
goto SerOut_NextBit
retlw 48 ; Support "Print" subroutine by setting "W" to 48d on return
#ENDIF ; IFDEF SEROUTPIN
; -----------------------------------------------------
; Receives a character from "SERPIN" as serial data
; If clock is 16MHz baud rate is 19200
; CALL Serial_In ; value received is in "serialData"
; -----------------------------------------------------
#IFDEF SERINPIN
#IFNDEF InBaud
#DEFINE InBaud 9600
#ENDIF
Serial_In:
clrf serialData
btfss PORTA,SERINPIN ; Wait for idle (HIGH)
goto $-1
btfsc PORTA,SERINPIN ; Wait for start bit (LOW)
goto $-1
movlw (1440000 / InBaud) ; Wait 1.5 bit times
call Delay_uSec_W
movlw 8 ; Receive 8 bits
movwf bitCnt
SerIn_NextBit:
bcf STATUS,C ; Make carry match pin state
btfsc PORTA,SERINPIN
bsf STATUS,C
rrf serialData,F ; Shift in received bit
movlw (960000 / InBaud) ; Wait 1 bit time
call Delay_uSec_W
decfsz bitCnt,F
goto SerIn_NextBit
movf serialData,w
return
#ENDIF ; IFDEF SERINPIN
; -----------------------------------------------------
; Reset 1-Wire device
; CALL OW_Reset ; Resets 1-wire device
; -----------------------------------------------------
#IFDEF OWPIN
OW_Reset:
bcf LATA,OWPIN ; Make pin low
bcf TRISA,OWPIN
movlw 250 ; Delay 500uSec
call Delay_uSec_W
movlw 250
call Delay_uSec_W
bsf TRISA,OWPIN ; Make pin input
movlw 250 ; Delay 500uSec
call Delay_uSec_W
movlw 250
call Delay_uSec_W
return
; -----------------------------------------------------
; Read a byte from 1-Wire device
; CALL OW_Read ; Read byte from 1-wire device, value in owData
; -----------------------------------------------------
OW_Read:
movlw 0xff
; -----------------------------------------------------
; Write a byte to 1-Wire device
; CALL OW_Write ; Write byte to 1-wire device
; -----------------------------------------------------
OW_Write_W:
movwf owData
OW_Write:
; 0 = Low for 60uSec; input for 10uSec
; 1 = Low for 5uSec; input for 15uSec, sample, input for 55uSec
movlw 8
movwf bitCnt
OW_Write_Next
rrf owData,f
bcf TRISA,OWPIN ; Make pin low
movlw 5
call Delay_uSec_W
btfsc STATUS,C ; If C=1 make pin input
bsf TRISA,OWPIN
movlw 10
call Delay_uSec_W
btfss PORTA,OWPIN ; If pin is low
bcf STATUS,C ; then clear carry
movlw 45
call Delay_uSec_W
bsf TRISA,OWPIN ; Make pin input
movlw 10
call Delay_uSec_W
decfsz bitCnt,f ; Do all bits
goto OW_Write_Next
rrf owData,f ; Get last bit from carry
movf owData,w ; Return with value read in "W"
return
#ENDIF ; IFDEF OWPIN
#IFDEF SCLPIN
#IFDEF SDAPIN
I2C_Start:
return
I2C_Stop:
return
#IFNDEF No_I2C_Read
I2C_Read:
return
#ENDIF ; #IFNDEF No_I2C_Read
I2C_Write_W:
movwf i2cData
I2C_Write:
return
#ENDIF ; #IFDEF SDAPIN
#ENDIF ; #IFDEF SCLPIN