;******************************************************************************
;                                                                             *
;    Filename:        Linear Dimmer.asm                                       *
;    Date:            September 20, 2013                                      *
;    File Version:                                                            *
;                                                                             *
;    Author:          Shawn Rhen                                              *
;    Company:         Digi-Key Corporation                                    *
;                                                                             *
;******************************************************************************

	list		p=12F1822      ; list directive to define processor
	#include	<p12F1822.inc> ; processor specific variable definitions

	errorlevel  -302          ; suppress message 302 from list file
;------------------------------------------------------------------------------

; CONFIGURATION WORD SETUP
 
    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF

;------------------------------------------------------------------------------
; VARIABLE DEFINITIONS

data_type	equ 0x71
data_ID	equ 0x72

data_H	equ	0x73
data_T	equ	0x74
data_O	equ	0x75

temp1	equ 0x76
temp2	equ	0x77

loop equ 0x78
DB1 equ 0x79
DB2 equ 0x7a

; Definitions

#define	clk	PORTA,5
#define	dbit PORTA,4
#define load PORTA,2
#define	carry STATUS,0

;------------------------------------------------------------------------------
; EEPROM INITIALIZATION

DATAEE    ORG  0xF000

;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

    ORG     0x0000      ; processor reset vector

    GOTO    main        ; When using debug header, first inst.
                        ; may be passed over by ICD2.  

;------------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------

    ORG      0x0004

;------------------------------------------------------------------------------
; USER INTERRUPT SERVICE ROUTINE GOES HERE
;------------------------------------------------------------------------------


    RETFIE              ; return from interrupt
  
;**************
; delay routine

delay
		movlw 	0x0a	; move 0xA (10) into w    
		movwf	20h		; move w into register 20
more2	movlw	0x25	; move 0x25 (37) into w
		movwf	21h		; move w into register 21
more1	decfsz	21h,f	; decrement register 21, skip next if 0
		goto	more1
		decfsz	20h,f	; decrement register 20, skip next if 0
		goto	more2
		return

;*************		  

main
; set up internal oscillator for 8MHz clock

	banksel	OSCCON	; select Bank 1
	movlw	0x72	; 0x72 (114) for 8MHz 
	movwf	OSCCON	; move w into OSCCON

;****************************************

; set up I/O configuration

	banksel PORTA	; select Bank 0
	clrf PORTA		; clear I/O

	banksel	LATA	; select Bank 2
	clrf	LATA	; clear Latch A

	banksel ANSELA	; select Bank 1
	clrf 	ANSELA	; clear analog select register

	banksel	TRISA	; select Bank 1
	movlw 	0x2		; move 0x2 into w
	movwf	 TRISA	; move w into TRISIO (RA1 input, all others outputs)

	banksel PORTA	; select bank 0
	bsf	load		; set load pin

;**********************************	 	

; USART initialization

	banksel	SPBRGH			; select Bank 3
	clrf	SPBRGH			; clear SPBRGH
	movlw	0x19			; mov 0x19 into w (25)
	movwf	SPBRGL			; set SPBRG registers for 19200 Baud (8 MHZ clock)
	bsf		TXSTA,BRGH		; set BRGH 
	bcf		BAUDCON,BRG16	; clear BRG16
	bcf		TXSTA,SYNC		; select asynchronous mode
	bsf		RCSTA,SPEN 		; set SPEN bit
	bcf		TXSTA,TX9		; disable 9-bit transmission
	bsf		TXSTA,TXEN		; enable transmission
	bcf		RCSTA,RX9		; disable 9-bit reception
	bsf		RCSTA,CREN 		; enable continuous reception

	banksel	PIR1			; select Bank 0
	bcf		PIR1,RCIF		; clear RCIF interrupt flag

;**********************************
; clear data registers

	movlw	0x30			; mov 0x30 into W, 30H = ASCII 0 (zero)
	movwf	data_H			; mov 30H into data_H
	movwf	data_T			; mov 30H into data_T
	movwf	data_O			; move 30H into data_O

;****************

rx		
		banksel PIR1		; select Bank 0
		btfss 	PIR1, RCIF	; skip next if RCIF is set
		goto	rx
		bcf		PIR1,RCIF	; clear RCIF interrupt flag	

		banksel	RCSTA		; select Bank 3 
		movlw	06h			; Mask out unwanted bits
		andwf	RCSTA,W		; Check for errors
		btfss	STATUS,Z	; skip next if zero bit was set
		goto	err

		movf	RCREG,W		; Get input data
		movwf	data_type	; store received byte

;**************

; check for "D"
		movlw	0x44		; mov "D" into w
		subwf	data_type,w ; subtract data_type from w
		btfsc	STATUS,2	; skip next if not "D"
		goto	get_id

;**********************************

err			
	banksel	RCSTA		; select Bank 3
	bcf		STATUS,0	; clear carry bit
	bcf		RCSTA,CREN 	; clear error
	movlw	0x3f		; mov ASCII "?" into w
	movwf	TXREG		; transmit "?"
	call	err_wait
	bsf		RCSTA,CREN 	; enable continuous reception

	banksel	PIR1		; select Bank 0
	bcf		PIR1,RCIF	; clear RCIF interrupt flag
	goto	rx

err_wait	
		banksel TXSTA	; select Bank 3
e_wait	btfss TXSTA,1	; skip next if TXIF is set
		goto e_wait	
		return

;*******************

get_id

waitID	
		banksel PIR1		; select Bank 0
		btfss 	PIR1, RCIF	; skip next if RCIF is set
		goto	waitID

		bcf		PIR1,RCIF	; clear RCIF interrupt flag	

		banksel	RCREG		; select Bank 3
		movf	RCREG,W		; Get input data
		movwf	data_ID		; store received byte (which data number)

; check for "1"
		movlw	0x31		; mov ASCII "1" into w
		subwf	data_ID,w	; subtract data_ID from w
		btfsc	STATUS,2	; skip next if zero bit not set
		goto	wait1H

		goto	err

;********************

wait1H	
		banksel	PIR1		; select Bank 0
		btfss 	PIR1, RCIF	; skip next if RCIF is set
		goto	wait1H

		bcf		PIR1,RCIF	; clear RCIF interrupt flag	

		banksel RCREG		; select Bank 3
		movf	RCREG,W		; Get input data
		movwf	data_H		; store received byte

wait1T	
		banksel PIR1		; select Bank 0
		btfss 	PIR1, RCIF	; skip next if RCIF is set
		goto	wait1T

		bcf		PIR1,RCIF	; clear RCIF interrupt flag	

		banksel RCREG		; select Bank 3
		movf	RCREG,W		; Get input data
		movwf	data_T		; store received byte

wait1O	
		banksel PIR1		; select Bank 0
		btfss 	PIR1, RCIF	; skip next if RCIF is set
		goto	wait1O

		bcf		PIR1,RCIF	; clear RCIF interrupt flag	

		banksel RCREG		; selct Bank 3
		movf	RCREG,W		; Get input data
		movwf	data_O		; store received byte

		banksel	PORTA		; select Bank 0

; check to see if data_H = "1", if so then percentage = 100%

		movlw	0x31		; mov ASCII "1" into w
		subwf	data_H,0	; subtract data_H from w
		btfsc	STATUS,2	; skip next if not equal to "1"
		goto	one_hundred

;**********************

		movlw	0x30		; mov ASCII "0" into w, check for 0%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "0"
		goto	off

		movlw	0x31		; mov ASCII "1" into w, check for 10%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "1"
		goto	ten

		movlw	0x32		; mov ASCII "2" into w, check for 20%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "2"
		goto	twenty

		movlw	0x33		; mov ASCII "3" into w, check for 30%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "3"
		goto	thirty

		movlw	0x34		; mov ASCII "4" into w, check for 40%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "4"
		goto	forty

		movlw	0x35		; mov ASCII "5" into w, check for 50%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "5"
		goto	fifty

		movlw	0x36		; mov ASCII "6" into w, check for 60%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "6"
		goto	sixty

		movlw	0x37		; mov ASCII "7" into w, check for 70%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "7"
		goto	seventy

		movlw	0x38		; mov ASCII "8" into w, check for 80%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "8"
		goto	eighty

		movlw	0x39		; mov ASCII "9" into w, check for 90%
		subwf	data_T,0	; subtract data_T from w
		btfsc	STATUS,2	; skip next if not "9"
		goto	ninety

		goto	rx

;***************************

one_hundred
		movlw	0x0ff
		movwf	DB1		; load values for
		movwf	DB2		; 10 volt output from D/A
		call	output
		goto	rx

;******************

off
		movlw	0x0
		movwf	DB1		; load values for
		movlw	0x00	; 0 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

ten
		movlw	0x1
		movwf	DB1		; load values for
		movlw	0x9a	; 1 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

twenty
		movlw	0x3
		movwf	DB1		; load values for
		movlw	0x33	; 2 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

thirty
		movlw	0x4
		movwf	DB1		; load values for
		movlw	0xcd	; 3 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

forty
		movlw	0x6
		movwf	DB1		; load values for
		movlw	0x66	; 4 volt output from D/A
		movwf	DB2
		call	output
		goto	rx


;******************

fifty
		movlw	0x8
		movwf	DB1		; load values for
		movlw	0x0		; 5 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

sixty
		movlw	0x9
		movwf	DB1		; load values for
		movlw	0x9a	; 6 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

seventy
		movlw	0xb
		movwf	DB1		; load values for
		movlw	0x33	; 7 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

eighty
		movlw	0xc
		movwf	DB1		; load values for
		movlw	0xcd	; 8 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;******************

ninety
		movlw	0xe
		movwf	DB1		; load values for
		movlw	0x66	; 9 volt output from D/A
		movwf	DB2
		call	output
		goto	rx

;*****************

output
		rlf		DB1,1	; rotate DB1 left 4 times to shift the
		rlf		DB1,1	; lower 4 bits into the upper 4 bits
		rlf		DB1,1	; for bit-banging into the 12-bit
		rlf		DB1,1	; digital-to-analog converter

		movlw	0x4		; mov 4 into w
		movwf	loop	; load loop counter with w
		bcf		carry	; clear carry bit
again1	bcf		dbit	; clear dbit
		rlf		DB1,1	; rotate DB1 left into carry	
		btfsc	carry	; skip next if carry is clear
		bsf		dbit	; set data bit

		call	delay

		bsf		clk		; set clk bit

		call	delay

		bcf		clk		; clear clock bit

		call	delay

		decfsz	loop,1	; decrement loop and skip next if zero
		goto	again1

; end of DB1

		movlw	0x7		; mov 7 into w
		movwf	loop	; load loop counter with w	
		bcf		carry	; clear carry bit
again2	bcf		dbit	; clear dbit
		rlf		DB2,1	; rotate DB2 left into carry	
		btfsc	carry	; skip next if carry is zero
		bsf		dbit	; set data bit

		call	delay
		
		bsf		clk		; set clk bit

		call	delay

		bcf		clk		; clear clk bit

		call	delay

		decfsz	loop,1	; decrement loop and skip next if zero
		goto	again2


		bcf		dbit	; clear dbit
		rlf		DB2,1	; rotate DB2 into carry
		btfsc	carry	; skip next if carry is zero
		bsf		dbit	; set dbit

		call	delay

		bsf		clk		; set clk bit

		call	delay

		bcf		load	; load D/A with data

		call	delay

		bcf		clk		; clear clk bit

		call	delay

		bsf		load	; set "load" pin

		call	delay

		return

;*****************

    END