TITLE   "A/D using Multiple Channels"
;This program is a simple implementation of the PIC16C71's
;A/D feature. This program demonstrates
;how to select multiple channels on the PIC16C71.
;The A/D is configured as follows:
;       Vref = +5V internal.
;       A/D Osc. = fosc/2.
;       A/D Interrupt = Off
;       A/D Channels = "Round Robin" format.
;       A/D reuslts are stored in ram locations as follows:
;       ch0 --> ADTABLE + 0
;       ch1 --> ADTABLE + 1
;       ch2 --> ADTABLE + 2
;       ch3 --> ADTABLE + 3
;
;The ch3 A/D result is displayed on a 3 digit LED display LTM8522. 
;
;
	LIST P=16C71,F=INHX8M
;
	include "d:\pic16c\ad\picreg.equ"
;
;       REGISTER EQUATES FOR DISPLAY ROUTINES
;
ACCA    EQU     18h
ACCA1   equ     19h
ACCB    EQU     1Ah
ACCB1   EQU     1Bh
ACCC    EQU     1Ch
ACCC1   equ     1Dh
ACCD    EQU     1Eh
ACCD1   equ     1Fh
ACCE    EQU     20h
ACCE1   equ     21h
TCAL    EQU     22h
TEMP    EQU     24h
;
ch2     equ     6
ch3     equ     7
flag    equ     0C
ADTABLE equ     20
;
	ORG     0x00
;
;
	goto    start
;
	org     0x04
	goto    service_int      ;interrupt vector
;
;
	org     0x10
start
	call    ClearRam
	movlw   B'11110000'     ;init i/o ports
	movwf   PORT_B
	tris    PORT_B
;
	call    InitializeAD   
update      
	movf    ADRES,W
	movwf   0               ;save in table
	movlw   ADTABLE         ;chk if ch3
	subwf   FSR,W           ;     /
	xorlw   3               ;    /
	btfss   STATUS,Z        ;yes then skip
	goto    NextAd          ;else do next channel
	movf    ADRES,W         ;get a/d value
	movwf   ACCB1           ;in ACCB and ACCB1
	clrf    ACCB            ;       /
;code below is used to to display the a/d result on the
;LTM8522 LED display unit.
	movlw   .196            ;multilply a/d result
	movwf   ACCA1           ;by 196 to take into
	clrf    ACCA            ;account 5V ref.        
	call    MPY             ;ACCA*ACCB (16 bit)
	movf    ACCC1,W         ;transfer result to
	movwf   ACCB1           ;ACCB and ACCB1        
	movf    ACCC,W          ;       /
	movwf   ACCB            ;       /
	CALL    BINTOB          ;convert to BCD
	CALL    DRIVR           ;LOAD LED Display
;******** end of display setup/update ********************
NextAd
	call    NextChannel     ;select next channel
	bsf     ADCON0,2        ;start new a/d conversion
loop
	btfsc   ADCON0,2        ;a/d done?
	goto    update          ;yes then update
	goto    loop            ;wait till done
;
service_int
	return                  ;do not enable int
;
PAGE
;
;ClearRam clears ram from 0x0C to 0x2F.
ClearRam
	movlw   0x0c            ;get first ram location
	movwf   FSR             ;load in indirect address
CR1
	clrf    0               ;do indirect ram clr
	incf    FSR             ;inc FSR
	btfss   FSR,5           ;if bit 5 set then skip
	goto    CR1             ;else clr next
	btfss   FSR,4           ;if bit 4 set then done
	goto    CR1             ;else clr next
	return                  
;
;InitializeAD, initializes and sets up the A/D hardware.
InitializeAD
	bsf     STATUS,5        ;select pg1
	movlw   B'00000000'     ;select ch0-ch3...
	movwf   ADCON1          ;as analog inputs
	bcf     STATUS,5        ;select pg0
	movlw   B'00000001'     ;select:fosc/2, ch0.
	movwf   ADCON0          ;turn on a/d
	movlw   ADTABLE         ;get top of table address
	movwf   FSR             ;load into indirect reg
	clrf    ADRES           ;clr result reg.
	return
;
;NextChannel, selects the next channel to be sampled in a 
;"round-robin" format.
NextChannel
	movlw   0x08            ;load channel offset
	addwf   ADCON0          ;add to conf. reg.
	bcf     ADCON0,5        ;clear any carry over
;increment pointer to correct a/d result register
	clrf    TEMP
	btfsc   ADCON0,3        ;test lsb of chnl select
	bsf     TEMP,0          ;set if ch1 or ch3
	btfsc   ADCON0,4        ;test msb of chnl select
	bsf     TEMP,1          ;set if ch0 or ch2
	movlw   ADTABLE         ;get top of table
	addwf   TEMP,0          ;add with temp
	movwf   FSR
	return
;
PAGE
;
;The rest of the subroutines below, are required to display the a/d
;result on the LED display LTM8522.
;
;***********************************************************************
;
;       MULTIPLY SUBROUTINE 16 BIT * 16 BIT FOR 32 BIT RESULT
;
;       INPUTS  ACCA (16BITS)
;               ACCB (16BITS)
;
;       OUTPUTS ACCB  (16BITS) ACCC (16BITS) 
;
;***********************************************************************
MPY     
	CALL    SETUP   ;RESULTS IN B(16 MSB'S) AND C(16 LSB'S)
MLOOP
	RRF     ACCD    ;ROTATE D RIGHT
	RRF     ACCD+1
	SKPNC           ;NEED TO ADD?
	CALL    MADD
	RRF     ACCB
	RRF     ACCB+1
	RRF     ACCC
	RRF     ACCC+1
	DECFSZ  TEMP    ;LOOP UNTIL ALL BITS CHECKED
	GOTO    MLOOP
	RETLW   0

MADD
	MOVF    ACCA+1,W
	ADDWF   ACCB+1  ;ADD LSB
	BTFSC   STATUS,0        ;ADD IN CARRY
	INCF    ACCB
	MOVF    ACCA,W
	ADDWF   ACCB    ;ADD MSB
	RETLW   0

SETUP
	MOVLW   10h
	MOVWF   TEMP
	MOVF    ACCB,W  ;MOVE B TO D
	MOVWF   ACCD
	MOVF    ACCB+1,W
	MOVWF   ACCD+1
	MOVF    ACCC,W
	MOVWF   ACCE
	MOVF    ACCC+1,W
	MOVWF   ACCE+1
	CLRF    ACCB
	CLRF    ACCB+1
	RETLW   0

;*****************************************************************************
;
;       DIVIDE SUBROUTINE  32 BIT / 16 BIT FOR 16 BIT RESULT
;
;       INPUTS  ACCB (16 BIT) ACCC (16BIT ) / ACCA (16 BIT)
;
;       OUTPUTS ACCB (16 BIT)
;
;*****************************************************************************
 
DIV
	CALL    SETUP
	MOVLW   20h
	MOVWF   TEMP
	CLRF    ACCC
	CLRF    ACCC+1
DLOOP
	CLRC
	RLF     ACCE+1
	RLF     ACCE
	RLF     ACCD+1
	RLF     ACCD
	RLF     ACCC+1
	RLF     ACCC
	MOVF    ACCA,W
	SUBWF   ACCC,W  ;CHECK IF A>C
	SKPZ
	GOTO    NOCHK
	MOVF    ACCA+1,W
	SUBWF   ACCC+1,W        ;IF MSB EQUAL THEN CHECK LSB
NOCHK
	SKPC            ;CARRY SET IF C>A
	GOTO    NOGO
	MOVF    ACCA+1,W        ;C-A INTO C
	SUBWF   ACCC+1
	BTFSS   STATUS,0
	DECF    ACCC
	MOVF    ACCA,W
	SUBWF   ACCC
	SETC            ;SHIFT A 1 INTO B (RESULT)
NOGO
	RLF     ACCB+1
	RLF     ACCB
	DECFSZ  TEMP    ;LOOP UNTILL ALL BITS CHECKED
	GOTO    DLOOP
	RETLW   0

;*************************************************************************
;       THIS SUBROUTINE CONVERTS A 16 BIT BINARY WORD
;       INTO A 4 DIGIT BCD
;       THE HIGH ORDER INPUT IS IN ACCB, LOW ORDER IN ACCB+1
;       OUTPUT IS IN ACCD, ACCD+1 AND ACCE, ACCE+1
;       WITH THE 4 LSB'S OF ACCD HIGH ORDER
;
;*************************************************************************
;
BINTOB
	MOVLW   10h
	MOVWF   ACCE+1
	CLRF    ACCE    ;CLEAR OUTPUT REGISTERS
	CLRF    ACCD+1
	CLRF    ACCD
LOOPC
	RLF     ACCB+1  ;SHIFT BINARY INTO BCD REGS ONE BIT
	RLF     ACCB
	RLF     ACCE
	RLF     ACCD+1
	RLF     ACCD
	DECFSZ  ACCE+1
	GOTO    ADJDEC
	MOVF    ACCE,W
	MOVWF   ACCE+1
	MOVLW   0Fh
	RRF     ACCE+1
	RRF     ACCE+1
	RRF     ACCE+1
	RRF     ACCE+1
	ANDWF   ACCE+1,F
	MOVF    ACCD+1,W
	MOVWF   ACCE
	MOVLW   0Fh
	ANDWF   ACCE
	RRF     ACCD+1
	RRF     ACCD+1
	RRF     ACCD+1
	RRF     ACCD+1
	ANDWF   ACCD+1
	RETLW   0       ;EXIT AFTER 16 SHIFTS

ADJDEC
	MOVLW   ACCE
	MOVWF   FSR
	CALL    ADJBCD
	MOVLW   ACCD+1
	MOVWF   FSR
	CALL    ADJBCD
	MOVLW   ACCD
	MOVWF   FSR
	CALL    ADJBCD
	GOTO    LOOPC

ADJBCD
	MOVLW   03h
	ADDWF   0,W     ;ADD 3 TO LSD
	MOVWF   TEMP
	BTFSC   TEMP,3  ;SAVE IF RESULT >7
	MOVWF   0
	MOVLW   30h
	ADDWF   0,W     ;ADD 3 TO MSD
	MOVWF   TEMP
	BTFSC   TEMP,7  ;SAVE IF RESULT >7
	MOVWF   0
	RETLW   0

;***************************************************************************
;
;       BEGIN OF LED DRIVER ROUTINES
;
;***************************************************************************
;
BCDT
	ADDWF   PC      ;ADD NUMBER TO PC - MAKE JUMP TABLE
	RETLW   0FCh    ;CODE FOR ZERO
	RETLW   060h    ;CODE FOR ONE
	RETLW   0DAh    ;CODE FOR TWO
	RETLW   0F2h    ;CODE FOR THREE
	RETLW   066h    ;CODE FOR FOUR
	RETLW   0B6h    ;CODE FOR FIVE
	RETLW   0BEh    ;CODE FOR SIX
	RETLW   0E0h    ;CODE FOR SEVEN
	RETLW   0FEh    ;CODE FOR EIGHT
	RETLW   0E6h    ;CODE FOR NINE

LDATA
	MOVLW   8
	MOVWF   TEMP
DRLOOP  
	BCF     PORT_B,1        ;SET CLOCK LO
	NOP
	BSF     PORT_B,2        ;SET DATA HIGH
	RLF     ACCA
	BTFSS   STATUS,0        ;CHECK DATA
	BCF     PORT_B,2        ;SET DATA LOW IF DATA LOW
	NOP
	BSF     PORT_B,1        ;SET CLOCK HIGH
	DECFSZ  TEMP
	GOTO    DRLOOP
	RETLW   0
;*********************************************************************
;
;       DISPLAY DRIVER ROUTINE
;       DISPLAYS 3 DIGITS 
;       INPUT IN ACCD ADDC+1 ACCE
;       EXPECTS DECIMAL DIGIT (0-9) IN REGISTER
;
;**********************************************************************
;
DRIVR
	MOVF    ACCD,W
;        BTFSS   STATUS,Z
	GOTO    ALL_DIGIT
	MOVF    ACCD+1,W
	BTFSS   STATUS,Z
	GOTO    TWO_DIGIT
	GOTO    ONE_DIGIT
ALL_DIGIT
	CALL    BCDT    ;FIND LED CODE FOR MSB
	MOVWF   ACCD
	movlw   1       ;set decimal on
	addwf   ACCD
	MOVF    ACCD+1,W
TWO_DIGIT
	CALL    BCDT    ;FIND LED CODE FOR MIDDLE BITS
	MOVWF   ACCD+1
ONE_DIGIT
	MOVF    ACCE,W
	CALL    BCDT    ;FIND LED CODE FOR LSB
	MOVWF   ACCE
DISPLAY
	CLRF    ACCA
	BCF     PORT_B,1        ;SET CLOCK LOW
	NOP
	BCF     PORT_B,3        ;SET ENABLE LOW  (ON)
	NOP
	BSF     PORT_B,2        ;SET DATA HIGH
	NOP
	BSF     PORT_B,1        ;CLOCK HIGH TO LOAD START BIT
	NOP
	BCF     PORT_B,2        ;DATA LOW
	NOP
	BCF     PORT_B,1        ;CLOCK LOW
	MOVF    ACCD,W
	MOVWF   ACCA    ;LOAD MSB
	CALL    LDATA   ;SHIFT IN MSB
	MOVF    ACCD+1,W
	MOVWF   ACCA    ;MDDL TO LOAD REGISTER
	CALL    LDATA   ;SHIFT IN MDDL
	MOVF    ACCE,W
	MOVWF   ACCA    ;LSB TO LOAD REGISTER
	CALL    LDATA   ;SHIFT IN LSB
	CLRF    ACCA
	CALL    LDATA   ;LOAD IN EIGHT ZEROES
	CALL    LDATA   ;LOAD IN EIGHT ZEROES
	BCF     PORT_B,1        ;SET CLOCK LOW
	NOP
	BSF     PORT_B,3        ;SET ENABLE HIGH (OFF)

	MOVLW   b'00001111'     ;SET RB1 HIGH (ON WHEN ACTIVATED)
	MOVWF   PORT_B
	RETLW   0


	END

