LIST P=12C508 ;Processor used
 ;
 fuses:
  		 WDT - on
		 OSC - internal RC
 		 MCLR - internal MCLR
		 CP - code protect on
 ;
 ;Processor defined registers and bits
 ;
 		  INCLUDE "D:\Get51\MPLAB IDE\MCHIP_Tools\P12C508.INC" ;Microchip include file
  		  LIST
 ; P12C508.INC Standard Header File, Version 1.01 Microchip Technology, Inc.
 LIST
 ;
 ;Program defined registers;
 GPIO 	  EQU H'06' ;Output port register
 TEMP0 	  EQU H'07' ;Temporary storage register
 TEMP1 	  EQU H'08' ;Temporary storage register
 DUTY_CYC EQU H'09' ;Storage register for duty cycle
 DATA_REG EQU H'0A' ;Storage register for serial data
 FULL_BIT EQU H'0B' ;Holds full bit period delay
 QURT_BIT EQU H'0C' ;Holds a quarter bit period delay
 ;;
 ;Program defined bits;
 ;GPIO port bits
 OUTPUT EQU  H'00' ;GPIO, output enable pin
 INPUT 	EQU  H'03' ;GPIO, input for serial data
 SW1 	EQU  H'04' ;GPIO, input switch #1
 SW2 	EQU  H'05' ;GPIO, input switch #2
 ;****************************************************************************
 ;																			 ;
 ;****************************************************************************
 ;****************************************************************************
 ;****                        Reset Vector                                ****
 ;****************************************************************************
 ;****************************************************************************
  	    ORG    H'000'
        MOVWF  OSCCAL ;Move internal trim value to osccal
        GOTO   MAIN
 ;****************************************************************************
 ;****************************************************************************
 ;BYTE_IN: Byte_in receives data from a master at 2400 baud, 8N1, LSB first.
 ;         If a valid byte of data is read in then it replaces the current
 ;         duty cycle value in the SMART SWITCH. In this way serial
 ;         communication can control the duty cycle of the switch.
 ;
 ;         Called From:        MAIN
 ;         Modified Registers: STATUS, TEMP0, TEMP1, GPIO, DATA_REG
 ;         DUTY_CYC
 ;         Subroutines Called: DELAY
 ;         Enabled Interrupts: NONE
 ;
 BYTE_IN
         CLRWDT
         BTFSC  GPIO,INPUT ;Test for a start bit
         RETLW  H'00'
         MOVF   QURT_BIT,W ;Set up timer for start bit check
         MOVWF  TEMP0
 delay_loop
         CALL   DELAY
         BTFSC  GPIO,INPUT ;Make sure input remains low
         RETLW  H'00'
         DECFSZ TEMP0
         goto   delay_loop
         MOVLW  H'08' ;Set up temp to count 8 bits
         MOVWF  TEMP1
 more_bits
         MOVF   FULL_BIT,W ;Load temp with baud rate value
         MOVWF  TEMP0
 first_bit
         CALL   DELAY ;22*18us + 20us = 0.415ms ->2403 baud
         DECFSZ TEMP0
         goto   first_bit
         BTFSS  GPIO,INPUT ;Test input value
         BCF    STATUS,C ;Input was low so clear carry bit
         BTFSC  GPIO,INPUT
         BSF    STATUS,C ;Input was high so set carry bit
         RRF    DATA_REG ;Rotate carry bit into data reg.
         NOP
         NOP
         NOP
         NOP ;A little delay to get 2400 baud
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         DECFSZ TEMP1
         goto   more_bits ;1/(0.396ms + 20us) = .415 -> 2403baud
         MOVF   FULL_BIT,W
         MOVWF  TEMP0
         INCF   TEMP0 ;Add a little more to stop bit
 stop_bit
 		 CALL   DELAY ;23 * 18us = .414ms -> 2415 baud
 		 DECFSZ TEMP0
 		 goto   stop_bit
 		 BTFSS  GPIO,INPUT ;Test for valid stop bit
 		 RETLW  H'00'
 		 MOVF   DATA_REG,W ;Move received data to W
 		 MOVWF  DUTY_CYC
 		 BTFSC  STATUS,Z ;See if duty cycle is H'00'
 		 INCF   DUTY_CYC ;If so increment duty cycle
 		 INCF   DUTY_CYC,W ;See if duty cycle is H'FF'
 		 BTFSC  STATUS,Z
 		 DECF   DUTY_CYC ;If so decrement duty cycle
 		 RETLW  H'00'
 		 RETLW  H'00'
 ;****************************************************************************
 ;DUTY_CYCLE: This routine monitors the input pins for logic low levels and
 ;            increments or decrements the current duty cycle depending on which
 ;            switch is pressed. Afterwards the 15us delay routine will
 ;            automatically adjust the duty cycle. The duty cycle is required to
 ;            be from H'01' to H'FE'.
 ;
 ; Called From:        MAIN
 ; Modified Registers: DUTY_CYC, STATUS
 ; Subroutines Called: DELAY
 ; Enabled Interrupts: NONE
 ;
 DUTY_CYCLE
         BTFSC  GPIO,SW1 ;Test for change of duty cycle
         goto   check_decrement ;Check next switch
         MOVLW  H'16' ;Start switch debounce
         MOVWF  TEMP1
 debounce_loop_0
         MOVLW  H'20'
         MOVWF  TEMP0
 debounce_loop_1
         CLRWDT
         CALL     DELAY ;Maintain current PWM output
         DECFSZ   TEMP0 ;Apply 15ms debounce to switch
         goto     debounce_loop_1
         DECFSZ   TEMP1
         goto     debounce_loop_0
         BTFSC    GPIO,SW1 ;Check switch after debounce
         RETLW    H'00'
         INCF     DUTY_CYC ;If good then increment duty cycle
         goto     check_duty_threshholds
check_decrement
		 BTFSC     GPIO,SW2 ;Test for change of duty cycle
		 RETLW     H'00'
		 MOVLW     H'16' ;Start switch debounce
		 MOVWF     TEMP1
debounce_loop_2
         MOVLW     H'20'
         MOVWF	   TEMP0
debounce_loop_3
		 CLRWDT
		 CALL      DELAY ;Maintain current PWM output
		 DECFSZ	   TEMP0 ;Apply 15ms debounce to switch
		 goto	   debounce_loop_3
		 DECFSZ    TEMP1
		 goto      debounce_loop_2
		 BTFSC 	   GPIO,SW2 ;Check switch after debounce
		 RETLW     H'00'
		 DECF      DUTY_CYC ;If good then decrement switch
check_duty_threshholds
		 MOVF 	   DUTY_CYC,W
		 BTFSC     STATUS,Z ;See if duty cycle is H'00'
		 INCF 	   DUTY_CYC ;If so increment duty cycle
		 INCF 	   DUTY_CYC,W ;See if duty cycle is H'FF'
		 BTFSC 	   STATUS,Z
		 DECF 	   DUTY_CYC ;If so decrement duty cycle
		 RETLW 	   H'00'
 ;****************************************************************************
 ;DELAY: A standard 15us delay. Instructions + loop + call and return
 ; 		equal 15us. If timer zero rolls over then the output
 ; 		(GPIO,OUTPUT) is toggled. The value in DUTY_CYC is the number
 ; 		of 64us periods that GPIO,OUTPUT stays low. The complement
 ; 		of DUTY_CYC is the number of 64us periods that GPIO,OUTPUT stays
 ; 		high. This routine generally maintains the duty cycle of the
 ; 		pass elements PWM.
 ;
 ; Called From: 	   MAIN
 ; Modified Registers: TMR0, DUTY_CYC, GPIO, STATUS
 ; Subroutines Called: NONE
 ; Enabled Interrupts: NONE
 ;
 DELAY
    	MOVF 	   TMR0,W ;Test for TMR0 rollover
 		BTFSS	   STATUS,Z
 		goto 	   hold ;If no rollover don't change output
 		BTFSC	   GPIO,OUTPUT
 		goto 	   t_clr
 		BSF 	   GPIO,OUTPUT ;Set output	
 		COMF 	   DUTY_CYC,W  ;Complement duty cycle to W
 		MOVWF	   TMR0        ;Move value to TMR0
 		NOP 	               ;Timing no-op
 		goto	   done ;Get out of routine
 t_clr
 		BCF 	   GPIO,OUTPUT ;Clear output
 		MOVWF 	   DUTY_CYC,W ;Move duty cycle reg to W
 		MOVWF	   TMR0 ;Move value to TMR0
 		goto	   done ;Get out of routine
 hold
 		NOP
 		NOP 			;If TMR0 doesn't roll over
 		NOP 			;then count out a standard delay
 		NOP
 		NOP
 		NOP
 		NOP
 		RETLW		H'00'
 ;****************************************************************************
 ;**** 							Main Program 							  ****
 ;****************************************************************************
 MAIN				;
 OPTION_SETUP
		MOVLW 		H'C5' ;1100 0101
		OPTION 		 ;Pull-up disabled, TMR0 1:64
 CLEAR_REGISTERS
 		CLRF		TEMP0 ;Clear first RAM location for use
 		MOVLW   	H'18' ;Number of registers to clear
 		MOVWF   	TEMP0
 		MOVLW   	H'08' ;Start of RAM clearing
 		MOVWF 		FSR
 clear_loop
 		CLRF 		INDF ;Clear register pointed to
 		INCF 		FSR,F ;Go to next RAM location to clear
 		DECFSZ 		TEMP0,F ;Check to see if all clearing done
 		goto		clear_loop
 PORT_SETUP
 		MOVLW		H'3E' ;0011 1110
 		MOVWF 		GPIO ;Set output low
 		NOP
 		MOVLW 		H'3E' ;0011 1110
 		TRIS		GPIO ;Set GP0 direction as an output
 REGISTER_SETUP
 		MOVLW 		H'01' ;Start duty cycle at zero
 		MOVWF  		DUTY_CYC ;(1 is as close to zero as possible)
 		MOVLW  		H'16' ;Start duty cycle at zero
 		MOVWF  		FULL_BIT ;Initialize serial communication
 		MOVLW  		H'06' ;for 2400 baud
 		MOVWF  		QURT_BIT
 		CLRF 		TMR0
 ;****************************************************************************
 ;****************************************************************************
 MAIN_LOOP
 		CLRWDT
 		CALL   		DELAY ;Maintain PWM
 		CALL 		DUTY_CYCLE ;Test for manual adjustment
 		CALL 		BYTE_IN ;Test for serial data adjustment
 		GOTO 		MAIN_LOOP ;Do it all again
 ;****************************************************************************
 ;
 ;End of code indicator
 ;
 		 END
