LIST P=16C84 include "..\P16C84.INC" ; 12 bit A-D converter using an AD7858L at 1MHz ; definitions of I/O pins ; serial I/O definitions (port B) SOUT equ 6 SIN equ 7 ; ADC interface (port B) SYNC equ 0 SCLK equ 1 DOUT equ 2 ; data out from the PIC DIN equ 3 ; data in to the PIC tx_byte equ 0ch ; serial byte tx_count equ 0dh ; count of serial bits CHR equ 0eh ; test char delay equ 0fh ; delay counter SAV_WREG equ 10h SAV_SREG equ 11h ; registers that hold commands to the ADC CMD1 equ 12h ; first byte sent. 111xyz00 CMD2 equ 13h ; second byte sent 00010000 INP1 equ 14h INP2 equ 15h CHAN equ 16h ; channel number ADC1 equ 17h ; output from ADC to send ADC2 equ 18h ADC3 equ 19h ; channel number of last conversion ldelay equ 1ah ; long delay counter org 0 goto init org 4 intr movwf SAV_WREG swapf STATUS, W movwf SAV_SREG intr_ret swapf SAV_SREG, W movwf STATUS swapf SAV_WREG swapf SAV_WREG, W retfie init clrf INTCON movlw B'00100000' movwf STATUS ; select page 1 movlw 0h ; set all PORTA bits as output movwf TRISA movlw B'10001000' ; PORT B bit 3 = data in from ADC, bit 6 serial in movwf TRISB movlw B'00001000' movwf OPTION_REG ; assign to WDT bcf STATUS, RP0 ; back to page 0 bsf PORTB, SYNC bsf PORTB, SCLK clrf CHAN call wait1s ; let things settle down movlw B'11100001' ; command the ADC to self-calibrate movwf CMD1 movlw B'00010000' movwf CMD2 call adc call wait1s ; this is the main loop ; increment the channel number ; call adc to send it to the ADC to sample the data ; call adc again to command the ADC to start the conversion ; call adc a thirs time to read the results of the conversion ; send the channel number and the 16 bits ; from the ADC as serial data loop ; now send the command to start the next conversion, incf CHAN, w andlw 07h movwf CHAN ; movlw 1 call conv_ch ; convert the 0-7 channel number to ; the correct bit pattern movwf CMD1 ; fill in the CMD1 byte to insert the other data movlw B'11100001' addwf CMD1, w movwf CMD1 movwf ADC1 clrf CMD2 ; set the channel only, don't do call adc ; the conversion movf ADC1, w movwf CMD1 movlw B'00010000' ; this time do the conversion movwf CMD2 call adc clrf CMD1 ; final time, read the result clrf CMD2 call adc ; send the channel number first movf CHAN, w ; as the data read was from the previous andlw B'00000111' ; conversion addlw '0' call ser_out ; now send the 16 bits of data from the ADC to the serial port swapf INP1, w ; get top 4 bits andlw 0fh addlw 0f6h ; 0-9 +. f6 - ff, a-f => 0-5 and CY set btfsc STATUS, 0 ; check if 0-9 or A-F addlw 7 ; shift from numeric to alpha addlw 3ah ; convert to '0'-'9' or 'A'-'F' call ser_out movlw 0fh andwf INP1, 0 addlw 0f6h btfsc STATUS, 0 addlw 7 addlw 3ah call ser_out swapf INP2, w ; get top 4 bits andlw 0fh addlw 0f6h ; 0-9 +. f6 - ff, a-f => 0-5 and CY set btfsc STATUS, 0 ; check if 0-9 or A-F addlw 7 ; shift from numeric to alpha addlw 3ah ; convert to '0'-'9' or 'A'-'F' call ser_out movlw 0fh andwf INP2, 0 addlw 0f6h btfsc STATUS, 0 addlw 7 addlw 3ah call ser_out movlw .10 ; ASCII newline call ser_out goto loop ; routine to write serial output at 9600 Baud ; (using 1MHz clock, 4uS/instruction) ; equals 26 clock cycles per bit ser_out movwf tx_byte call bitout_1 nop nop nop movlw 8 movwf tx_count ser_loop call bitout rrf tx_byte, f decfsz tx_count, f goto ser_loop call bitout_0 return ; routine to output a bit with the correct timing for 9600Bd @ 1Mhz ; this bit-sense works with a MAX-232 (i.e. inverted) bitout btfsc tx_byte, 0 goto bitout_0 bitout_1 nop nop bcf PORTB, SOUT goto bit_done bitout_0 bsf PORTB, SOUT bit_done movlw 4 movwf delay bit_delay decfsz delay, f goto bit_delay return ; routine to send/receive 16 bits to the ADC, ; read input on the falling edge of SCLK ; send CMD1 then CMD2 clocked on the rising edge of SCLK ; most significant bit first adc bcf PORTB, SYNC movlw 8 movwf tx_count adc_1 rlf INP1, f bcf PORTB, SCLK bcf INP1, 0 btfsc PORTB, DIN bsf INP1, 0 ; now send the output bcf PORTB, DOUT btfsc CMD1, 7 bsf PORTB, DOUT bsf PORTB, SCLK rlf CMD1, f decfsz tx_count, f goto adc_1 ; now send the second byte movlw 8 movwf tx_count adc_2 rlf INP2, f bcf PORTB, SCLK bcf INP2, 0 btfsc PORTB, DIN bsf INP2, 0 ; send the output bcf PORTB, DOUT btfsc CMD2, 7 bsf PORTB, DOUT bsf PORTB, SCLK rlf CMD2, f decfsz tx_count, f goto adc_2 ; reset SYNC output bsf PORTB, SYNC return ; the values of CH0, 1, 2 required to address ; channels 0 - 7 are not the numeric values ; this routine does the conversion conv_ch addwf PCL, 2 retlw 0 retlw 10h retlw 04h retlw 14h retlw 08h retlw 18h retlw 0ch retlw 1ch ; wait for the ADC to complete calibration on power-up wait1s movlw .100 movwf ldelay ; long delay counter wait1s_1 call wait10ms decfsz ldelay goto wait1s_1 return wait10ms movlw .250 ; number of times round the loop movwf delay wait_1 nop nop nop nop nop nop nop decfsz delay, f goto wait_1 ; at 1MHz, 10 instructions = 40uS return