;************************************************************************ ; Digital Thermostst * ;************************************************************************ list p=16f628 #include errorlevel 0,-302 CBLOCK 0x20 DS_DAT DS_SIGN SEND COUNT NUM1 NUM2 NUM3 DATA1 HALF DUMMY0 DUMMY1 DUMMY2 DUMMY5 DUMMY6 BITS COMPARE SET_TEMP ADDR endc ; End of definition #define DQ PORTA,0 ; Define text substitution #define E PORTB,0 #define RS PORTB,3 org 0x000 goto Start ;********************************************************************** ; LCD Display ;********************************************************************** Room_ addwf PCL,f ; dt "Room Temp " Set_ addwf PCL,f dt "Set Temp " First_ addwf PCL,f dt " " ;********************************************************************** ; Main Program * ;********************************************************************** Start call Init_Port ; Set -up port call Init_LCD ; Initial LCD movlw 0x20 ; Set temperature data = 00100000b = 16.0C movwf SET_TEMP bsf PORTA,4 ; Off relay, first movlw 0x80 ; movwf ADDR ; Select LCD's first line address call Set_Addr clrf COUNT ; Get message from table Send_Lp2 movf COUNT,w ; Begin with counter = 0 call First_ ; Income data position COUNT call Send ; Send data to LCD incf COUNT,f ; Get the next data if counter < 16 movlw .16 subwf COUNT,w ; Test counter < 16 ? btfss STATUS,Z goto Send_Lp2 ; If < 16, still send data Again movlw 0xC5 ; Select the center of LCD's second line movwf ADDR call Set_Addr clrf HALF ; Save half degree bcf STATUS,C rrf SET_TEMP,w ; Rotate bit data rlf HALF,f ; movwf DATA1 ; Save for conversion call Convert call Send_Temp ; Send temperature value to LCD btfsc PORTA,1 ; Check temperature increment switch goto Check_Run call Delay200 ; Delay for switch debouncing incf SET_TEMP,f Check_Run btfsc PORTA,3 ; Check running switch goto Again ; If not pressed, loop again movlw 0x01 ; Send command for clearing display movwf ADDR call Set_Addr call Delay5 ; Nescessary delay clrf COUNT ; Get message from table Send_Lp3 movf COUNT,w ; Begin with counter = 0 call Set_ ; Income data position COUNT call Send ; Send data to LCD incf COUNT,f ; Still send next data if counter < 8 movlw .9 subwf COUNT,w ; Test counter < 8 ? btfss STATUS,Z goto Send_Lp3 ; If < 8, try again call Send_Temp movlw 0xC0 ; Select LCD's second line address movwf ADDR call Set_Addr clrf COUNT ; Get message from Table Send_Lp4 movf COUNT,w ; Begin with counter = 0 call Room_ ; Income data position COUNT call Send ; Send data to LCD incf COUNT,f ; Still send next Data if counter < 8 movlw .9 subwf COUNT,w ; Test counter < 8 ? btfss STATUS,Z goto Send_Lp4 ; If < 8, try again OFF_ bsf PORTA,4 ; Off relay call RD_Temp movf DS_DAT,w ; Load data clrf HALF ; Clear register for storing a half temp value bcf STATUS,C rrf DS_DAT,w ; Use 7-bit upper rlf HALF,f ; Store a half degree (.5) or (.0) movwf DATA1 ; Data for conversion to decimal call Convert ; Convert data to decimal movf DS_DAT,w ; Check room temp > setting temp ? subwf SET_TEMP,w btfss STATUS,C goto ON_ ; If more than, goto on relay movlw 0xC9 ; If not, show room's temp on LCD movwf ADDR call Set_Addr call Send_Temp call Delay200 goto OFF_ ; Loop again ON_ bcf PORTA,4 ; On relay movlw 0xC9 ; Set address for LCD movwf ADDR ; Show room's temp call Set_Addr call Send_Temp ; Send temperature value to LCD call Delay200 call RD_Temp ; Read temperature value again movf DS_DAT,w ; Load data clrf HALF ; Clear register for storing a half temp bcf STATUS,C rrf DS_DAT,w ; Use 7-bit upper rlf HALF,f ; Store a half degree (.5) or (.0) movwf DATA1 ; Data for decimal conversion call Convert movf DS_DAT,w ; Check temperature again addlw 0x01 ; Temperarure is lower than [setting Temperature - 1] ? subwf SET_TEMP,w btfsc STATUS,C ; If yes, off relay goto OFF_ ; goto ON_ ; If no, loop again ;********************************************************************** ; SetPort I/O of PIC16F628 * ;********************************************************************** Init_Port clrf PORTA ; Clear PORTA before initial movlw 0x07 ; Set PORTA to digital I/O movwf CMCON bsf STATUS,RP0 movlw b'11101111' ; Set RA0, RA1 and RA3 as input, RA4 as output movwf PORTA movlw b'00000110' ; Use PORTB for LCD movwf PORTB bcf STATUS,RP0 return ;********************************************************************** ; Read Data From DS1820 * ;********************************************************************** RD_Temp call DS_Rx ; Check DS1820 status addlw 0x01 ; 255=ready, 0= ready btfss STATUS,Z ; Zero flag set = ready return ; W register is not zero = not ready Get_Temp call DS_Reset ; Reset chip first btfss STATUS,Z ; Zero flag set = OK goto Error_ ; If not response, exit movlw 0xcc ; Skip ROM command call DS_Tx ; Send command movlw 0xbe ; Read scratch pad command call DS_Tx ; Send command call DS_Rx ; Read 8-bit data movwf DS_DAT ; Save data to register call DS_Rx ; Sign (FF=-VE, 00=+VE) movwf DS_SIGN ; Save 9th bit to register call DS_Reset ; Restart movlw 0xcc ; Skip ROM command call DS_Tx ; Send command movlw 0x44 ; Start convert command call DS_Tx ; Send command movf DS_SIGN,w ; Check dign btfsc STATUS,Z ; Check dign = 00 ? goto Pass ; If yes, Temp as positive then return addlw 0x01 ; btfss STATUS,Z ; Check sign = FF ? goto Error_ ; If not, end with error Pass retlw 0x00 ; If Yes, (Temp as negstive then return Error_ retlw 0x01 ;********************************************************************** ; MACRO For DS1820 * ;********************************************************************** DQLOW macro bcf DQ ; DQ bit ready bsf STATUS,RP0 bcf DQ ; Set DQ to output bcf STATUS,RP0 endm DQHIZ macro bsf STATUS,RP0 bsf DQ ; Set DQ to input bcf STATUS,RP0 endm PAUSE macro DELAY ; Generate delay time movlw DELAY movwf DUMMY0 call DelayAL endm ;********************************************************************** ; DS1820 SubRoutine * ;********************************************************************** DelayAL nop ; Use for pausing macro nop decfsz DUMMY0,f goto DelayAL return ;********************************************************************** ; Reset DS1820 * ;********************************************************************** DS_Reset DQLOW PAUSE 0x77 ; 600 microsecond delay DQHIZ PAUSE 0x0c ; Wait 67 microsecond for response bit nop nop movf PORTA,w andlw 0x01 ; Use RA0 only movwf DUMMY1 PAUSE 0x3b ; 300 microsecond delay movf DUMMY1,w ; Response in W register return ;********************************************************************** ; Send Data To DS1820 (8 Bit) * ;********************************************************************** DS_Tx movwf DUMMY2 ; Transmission data movlw 0x08 ; Prepare 8-bit counter for sending data movwf DUMMY1 ; Define loop counter Tx_Loop DQLOW ; Macro of DQ pin to low, This is start bit PAUSE 0x01 ; 10 microsecond delay rrf DUMMY2,f ; Rotate data to Carry flag btfsc STATUS,C ; Test Carry flag bsf DQ ; If Carry flag = "1" , set DQ to high PAUSE 0x0d ; 70 microsecond delay DQHIZ nop decfsz DUMMY1,f ; 8 times ? goto Tx_Loop ; No, send again return ;********************************************************************** ; Recieve Data From DS1820 (8 Bit) * ;********************************************************************** DS_Rx movlw 0x08 ; Recieve 8-bit data movwf DUMMY1 Rx_Loop DQLOW ; Macro of DQ pin to low, this is start bit PAUSE 0x01 ; 10 microsecond delay DQHIZ ; Back to high for receiving nop nop movf PORTA,w ; Read data andlw 0x01 ; Get data bit 0 only addlw 0xff ; Move data bit 0 to Carry flag with addition method rrf DUMMY2,f ; Move data bit 0 to DUMMY bit 7 PAUSE 0x0b ; 60 microsecond delay decfsz DUMMY1,f ; Loop 8 times goto Rx_Loop ; Read again movf DUMMY2,w ; Save data to W register return ;********************************************************************** ; Subroutine For Send Data To LCD * ;********************************************************************** Send_Temp movf NUM3,w ; Read data from DS1820 btfsc STATUS,Z ; Fisrt data = 0 ? movlw 0xe0 ; If yes, convert to blank 0xE0+0x30 =0x20 (" ") addlw 0x30 ; Convert number to ASCII call Send ; Send data to LCD movf NUM2,w ; Read second digit addlw 0x30 ; Convert to ASCII call Send ; movf NUM1,w addlw 0x30 call Send movlw '.' ; call Send movlw '0' btfsc HALF,0 ; Test half degree = [0] or [5] movlw '5' call Send movlw 'C' call Send return Set_Addr bcf E ; Fix position on LCD bcf RS ; Send command call Delay125 movf ADDR,w ; Select address for sending data to LCD call Send bsf RS call Delay125 return reset_LCD macro movlw 0x38 ; Fisrt, send 8-bit mode command movwf BITS call Flip call Pulse call Delay125 endm Init_LCD bcf E ; Set command mode bcf RS call Delay125 reset_LCD reset_LCD reset_LCD reset_LCD movlw 0x28 ; Send 4-bit mode command in MSB only movwf BITS call Flip call Pulse call Delay125 movlw 0x28 ; Set LCD mode to 4 bit mode, 2 line display, 5x7 dot call Send movlw 0x0c ; Set LCD on, cursor off, cursor not blink call Send movlw 0x01 ; Clear display call Send call Delay5 return Send movwf BITS ; Send 8-bit data to LCD module call Flip ; call Pulse ; Send Upper 4-bit first and lower 4-bit following swapf BITS,f call Flip call Pulse call Delay125 return Flip bcf PORTB,4 ; Copy data from BITS register to RB4-RB7 btfsc BITS,4 ; bsf PORTB,4 ; Unchange other bit of PORTB bcf PORTB,5 ; btfsc BITS,5 bsf PORTB,5 bcf PORTB,6 btfsc BITS,6 bsf PORTB,6 bcf PORTB,7 btfsc BITS,7 bsf PORTB,7 return Pulse bsf E ; Generate enable pluse for LCD nop bcf E call Delay125 return Delay125 movlw .42 ; Delay 125 microsecond movwf DUMMY1 decfsz DUMMY1,f goto $-1 return Delay5 movlw .41 ; Delay 5 millisecond movwf DUMMY2 D1 call Delay125 decfsz DUMMY2,f goto D1 return Delay200 clrf DUMMY5 ; Delay ~ 200 mSec For Key Bounce clrf DUMMY6 decfsz DUMMY6,f goto $-1 decfsz DUMMY5,f goto $-3 return ;********************************************************************** ; Convert Hex to 3 Digit Decimal * ;********************************************************************** Convert clrf NUM2 ; Clear register of 10's unit Check movlw 0x0A ; Subtract with 10 until the result lower 10 subwf DATA1,w ; Fisrt subtraction < 10 ? btfss STATUS,C goto Less1 ; If < 10 then return incf NUM2,f ; If > 10 then increase 10's unit movlw 0x0A ; Subtract with 10 subwf DATA1,f ; Test Again. Is it lower 10 ? goto Check Less1 movf DATA1,w ; If < 10, send data to 1's unit movwf NUM1 ; clrf NUM3 ; Clear 100's unit Check2 movlw 0x0A subwf NUM2,w ; 10's unit > 10 ? btfss STATUS,C return ; If < 10 then return incf NUM3,f movlw 0x0A ; If > 10 then subtraction again subwf NUM2,f ; and check until the result is lower 10 goto Check2 end