Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ADC reading

Status
Not open for further replies.

hjl4

Member
Ok so I need opinion on how to implement this.
I am reading an analogue voltage (GP0) on 12f675, and I need to trigger an LED if the results in ADRESH or ADRESL, are >greater then 3volts, LED turns off if in between 2.99v and 1.70v, but if it is less then 1.70volts, the LED must turn on again.
I have setup my ports to be GP0 and GP1 as Analogue input, and GP3 as digital.
I turned Comparators off etc...

I'm no math wizard, but I just wondered if this is possible without reading thru a table.
Maybe interrupt??
 
hjl4 said:
I am reading an analogue voltage (GP0) on 12f675, and I need to trigger an LED if the results in ADRESH or ADRESL, are >greater then 3volts, LED turns off if in between 2.99v and 1.70v, but if it is less then 1.70volts, the LED must turn on again.
Simply compare the result of the A/D conversion with some constants. If the reference voltage is 5 V and you use 10-bit resolution, then 3 V = 0x266, etc.


hjl4 said:
I have setup my ports to be GP0 and GP1 as Analogue input, and GP3 as digital.
Why two analog inputs? What's the function of GP3 exactly?
 
The reason for GP0 and GP1 are both analogue, is that I will be reading both ports one after the other and if any of those two separate readings are greater then or less then set number, then LED goes on. I'm reading two different probes, and if either one or both is out of range, LED(alarm) goes off until voltage returns to acceptable levels.


Simply compare the result of the A/D conversion with some constants. If the reference voltage is 5 V and you use 10-bit resolution, then 3 V = 0x266, etc.

I don't quite understand how to do that, when there is a whole range to cover.

In any case,thanks for your reply.
 
What I meant, was that comparing to one constant is easy, but not so when you have a range to got thru.
 
I asked you about GP3 because it's input only. So, if you planned to connect the LED there, you have to change pin.

EDIT: are you using assembly or higher-level language?
 
Last edited:
eng1 I asked you about GP3 because it's input only. So, if you planned to connect the LED there, you have to change pin.

EDIT: are you using assembly or higher-level language?

Ok I see, no GP3 is not used, and GP5 is LED port.

I am using assembly, and even after 2 yrs, I still have some issues, when it comes to compare or math.
 
Ok. I am going to use 8-bit resolution to make it simple. For example, if you want to compare the A/D result (stored in ADRESH) with 3 V, you can write:

Code:
;select bank
movf    ADRESH, w
;select bank
sublw   0x99  
btfss   STATUS, C
goto    LED_ON
 
Last edited:
Try checking on the PICList, there's an entire section about comparisons - greater than, less than, greater than or equal - etc. There are also 8 and 16 bit versions, but for your purpose I would suggest configuring the A2D as 8 bit (one bit change in a register) and use 8 bit routines.
 
The subtract instructions in the pic chips are not very sensible. For example sublw does not equal subtract literal from word as you would expect. It actually executes subtract word from literal.

With this in mind, I thought I'd practice a little 16 bit comparison and came up with this,

Code:
	movlw	low(0x015B)
	subwf	Word,W
	movlw	high(0x015B)
	btfss	STATUS,C
	movlw	high(0x015B)+1
	subwf	Word+1,W
;	carry clear if word is less than 0x15B
	btfss	STATUS,C
	goto	LEDon

	movlw	low(0x0266)
	subwf	Word,W
	movlw	high(0x0266)
	btfss	STATUS,C
	movlw	high(0x0266)+1
	subwf	Word+1,W
;	carry set if word is greater or equal to 0x266
	btfsc	STATUS,C
	goto	LEDon

; turn LED off here

Copy the value of ADRESL into Word and ADRESH into Word+1 and the above should do what you want. Or, change the Word variable to ADRESL & ADRESH with the appropriate bank switching.

Mike.
Edit, I had the led on at the wrong time.
 
Last edited:
Thanks Pommie, I will try that, and unfortunately I'm at work right now, so my replies are pretty slow and far apart.
 
Sorry to cut in,

But does this style of code work for 16F628 PIC's as well? I'm considering the same thing. Thanks
 
Can anyone go over this code, and tell me if I'm on right track. I tried the MPLAB simulator, but I am at a loss when it comes to (stimulus functions).

This code was partially copied from Pommie(thanks), and I hope it is well implemented.
All it does is read AN0 and AN1, and compare the results to < than or > than a certain value, and if out of range, LED goes on GP5. If in range LED stays off.

I hope code OK. May need some tweaking.

I know it's been a while since original post, but my family and work, are also a priority.

Here it is,

Code:
	list      p=12f675           ; list directive to define processor
	#include <p12f675.inc>        ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT 

; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.




;***** VARIABLE DEFINITIONS

Word equ 0x30 





;**********************************************************************
		ORG     0x000             ; processor reset vector
		goto    main              ; go to beginning of program
	

		ORG     0x004             ; interrupt vector location
		

; isr code can go here or be located as a call subroutine elsewhere



; these first 4 instructions are not required if the internal oscillator is not used
main
		call    0x3FF             ; retrieve factory calibration value
		bsf     STATUS,RP0        ; set file register bank to 1 
		movwf   OSCCAL            ; update register with factory cal value 
		bcf     STATUS,RP0        ; set file register bank to 0


;*******************************************************************************************************
;**************************************  Begining of application code  *********************************
;*******************************************************************************************************


portsetup
                        ; ensure Bank "0" is previously selected
       clrf GPIO        ; clear GPIO 
                        ; the default chip configuration upon start up, or reset, is analogue input on GP0, GP1, GP2 and GP4
                        ; to alter this configuration, next 2 instructions are necessary, customize per your application.
       movlw 03h        ; move literal 03h working register
       movwf ANSEL      ; move working register to file ANSEL, setting GP2 as digital input and GP1 and GP0 as analogue input.                 
       movlw 07h        ; move literal to working register 
       movwf CMCON      ; turn comparators off as they are not used here
       bsf STATUS, RP0  ; switch to Bank "1" to set up ports
       movlw 0Bh        ; move literal to working register, 0Bh (001011b) (1 = input, 0 = output)
       movwf TRISIO     ; move working register value to TRISIO setting GP3, GP1 and GP0, as inputs, and GP2, GP4 and GP5, as digital outputs.
       bcf STATUS, RP0  ; return to Bank "0"
       
start  
       nop              ; small delay to settle micro
       nop
       nop
       nop
       nop
       btfss GPIO,3     ; check to see if PTO is engaged.(high) if set then skip next instruction
       goto start       ; if not set, loop back to start
       call Init_ADC0
       call Read_ADC1
       nop
       nop
       nop
       call result
       nop
       nop
       nop              ; small delay to settle micro
       btfss GPIO,3     ; check to see if PTO is engaged.(high) if set then skip next instruction
       goto start       ; if not set, loop back to start       
       call Init_ADC1
       nop
       nop
       nop
       call Read_ADC2
       nop
       nop
       nop
       call result
       goto start

Init_ADC0					;set for AN0
; Set ADCON0
    		movlw   b'10000001' 
    		movwf   ADCON0     ; bit 7 is set meaning results will be right justified, and bit 0 is also set, meaning A/D module is operating. no other bit are set so Channel 00 for AN0 will be read.
; Set ADCON1
    		BANKSEL ANSEL
    		movlw   b'10100001'
    		movwf   ANSEL      ; bit 7 is set, but is unimplemented. bit 0 is set, meaning GP0(AN0) is assigned as an analogue input.
    		BANKSEL ADCON0     ; switch to bank 0.
		    return

Init_ADC1					   ; set for AN1
; Set ADCON0
    		movlw   b'10000101'
    		movwf   ADCON0     ; bit 7 is set meaning results will be right justified, and bit 0 is also set, meaning A/D module is operating. bit 2 is set, meaning Channel 01 for AN1 is ready for reading.
; Set ADCON1
    		BANKSEL ANSEL
    		movlw   b'10100101'
    		movwf   ANSEL      ; bit 7 is set, but is unimplemented. bit 0 and 2 are  set, meaning GP0(AN0) and GP2(AN1), are assigned as an analogue input.
    		BANKSEL ADCON0
	    	return
         
Read_ADC1   ; read CHS0 ( channel 0)
    		bsf	ADCON0, GO_DONE		; initiate conversion
    		btfsc   ADCON0, GO_DONE
    		goto    $-1			    ; wait for ADC to finish

    		movf    ADRESH,W        ; move results from ADRESH file to W
    		movwf   Word            ; move value from W to file named Word
    		BANKSEL ADRESL          ; switch to bank 1
    		movf    ADRESL,W        ; move results from ADRESL file to W
    		movwf   Word+1          ; move value from W to file named Word and add 1
    		return
    		
    		
Read_ADC2   ; read CHS1 (channel 1)
    		bsf	ADCON0, GO_DONE		; initiate conversion
    		btfsc   ADCON0, GO_DONE
    		goto    $-1			    ; wait for ADC to finish

    		movf    ADRESH,W        ; move results from ADRESH file to W
    		movwf   Word            ; move value from W to file named Word
    		BANKSEL ADRESL          ; switch to bank 1
    		movf    ADRESL,W        ; move results from ADRESL file to W
    		movwf   Word+1          ; move value from W to file named Word and add 1
    		return
    		
    		
result
            movlw	low(0x015B)     ; load W with value of low 0x15
	        subwf	Word,W          ; subtract value in file Word, with value in W
        	movlw	high(0x015B)    ; load W with value of 0x15
          	btfss	STATUS,C        ; check to see if bit "C", in Status is set.
         	movlw	high(0x015B)+1  ; load W with value high 0x15 and add 1
        	subwf	Word+1,W        ; subtract value in file Word, with value in W
            btfss	STATUS,C        ; carry clear if word is less than 0x15B
	        call	LEDoff
         	movlw	low(0x0266)
        	subwf	Word,W
        	movlw	high(0x0266)
         	btfss	STATUS,C
         	movlw	high(0x0266)+1
	        subwf	Word+1,W
            
        	btfsc	STATUS,C        ; carry set if word is greater or equal to 0x266
	        call	LEDon
	        goto start

            ; turn LED off here 
	
	
	
		
LEDon
    
    bsf GPIO,5                      ; set bit 5 of GPIO register to 1 (high)
    return	
    
LEDoff
   
    bcf GPIO,5                      ; set bit 5 of GPIO register to 0 (low)
    return        		
; initialize eeprom locations	
   

		ORG	0x2100
		DE	0x00, 0x01, 0x02, 0x03


		END                       ; directive 'end of program'

Thanks to all.
 
I would suggest to configure the ansel register at the beginnig only.
Code:
       movlw  b'00010011'
       movwf ANSEL

I would turn the ADC off before selecting channels and insert a short delay after turning it on again. Are you using low impedance sources?
 
eng1

I would suggest to configure the ansel register at the beginnig only.
Code:

movlw b'00010011' movwf ANSEL


I would turn the ADC off before selecting channels and insert a short delay after turning it on again. Are you using low impedance sources?

Ok I'll try that, as for low impedance , yes.
 
It seems that you can select a channel without turning the ADC off, but a minimum delay is reqiuired. I'm reading AN546.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top