New To A/D Need Some Guide

Status
Not open for further replies.

Suraj143

Active Member
Hi guys this is my first attempt in A/D.

My target is to build a 0-99 Celsius temperature display. (Two digits & no need decimal point)

My temperature sensor is giving 10mV per Celsius. My supply is 5V.
My analog input is AN0.

For 99 C it has to measure = 99 X 10 = 990 mV. So an eight bit resolution is more than enough.

I just checked my input (AN0) by connecting a V/R. My BCD coding gives me 0 to 255 values when I turning the preset (V/R).

My problem is how to convert this 8 bit value to temperature?

I did a small math as in the graph please tell is that correct or not? If you like you can share a method how to convert this 8 bit value to temperature.

Many Thanks
 

Attachments

  • AD Values.JPG
    11.9 KB · Views: 186
Last edited:
hi Suraj,
Have you considered setting the +Vref to +2.5V, this will double the ADRESL value.
If you just want 8 bit resolution you could also Left Justify the ADC into ADRESH.

EDIT:
If you are going to display the ADRESX value as ASCII Temperature, on a LCD, you will need a binary to ascii conversion routine in your program.
 
Last edited:
Hi Eric thanks for your response.Actually I didn't set +Vref because i have never used Vref stuff before.

Is my data table ok?

I think i can use RLF command to make it double.

please help me.
 
Suraj143 said:
Hi Eric thanks for your response.Actually I didn't set +Vref because i have never used Vref stuff before.

Is my data table ok?

I think i can use RLF command to make it double.

please help me.

hi,
If its a 10bit ADC, this will give a value of 1023 decimal for a an ADC input voltage of +5V, when using the internal Vref of +5V.

So, for a Vin of 1V the ADC value will be: Value = (Vin/5)* 1023
equals 204 decimal 0xCC hex.

Calculate the rest of your graph/table using the same formula,

Does this help.?
 
Hi Eric I have BCD versions.I don't need ascii i just need decimals.

Now its displaying 0 to 255 in the segments because i'm using 8 bits.I gave inputs through a V/R(preset).when I turn the preset value varies 0 to 255.I can see from the seven segments.

I need to replace the V/R to my temperature sensor.My sensor 10mV per Celsius.
For 8 bits 5/255 = 0.0196 is this correct?
 

Hi,
I think you are using a LM35 temp sensor.?
If your maximum Temp is going to be 100Cdeg thats 100 * 0.01 = 1volt
So Max Value= (1/5) *1023 = 204.6.. IF you have right justified the ADC output or
Value = (1/5) *255 = 51 ... IF you have Left Justified the ADC output..

For the Temp range you are working over I would right justify and just use ADRESL output.
You will have to convert the binary value to BCD for your display.
 
ericgibbs said:
Hi,
I think you are using a LM35 temp sensor.?
Exactly.

Value = (1/5) *255 = 51 ... IF you have Left Justified the ADC output..
Exactly

For the Temp range you are working over I would right justify and just use ADRESL output. You will have to convert the binary value to BCD for your display.
Exactly.
 
Suraj143 said:
My Maximum value is 51 now what do I have to do?this must divide into 100 pcs.

Use an opamp to scale the voltage to a suitable range - fairly obviously you can't divide 51 into 100 pieces!.

Check my PIC tutorials for the hardware I use for A2D in the tutorials.
 
Suraj143 said:
My Maximum value is 51 now what do I have to do?this must divide into 100 pcs.

Why dont you right justify the ADC registers and just use the lower ADRESL register, this will give you 205 steps/increments for 0 to 100Cdeg.???
You will get 100/205... approx, 0.49Cdeg/increment in ADRESL

The resolution of the Tempr using 51 to represent 100Cdeg is a poor way to go, consider the Tempr resolution.
100/51= 2Cdeg resolution per increment!!!
 
Hi Eric great news!

I just right justify & read the ADRESL value. I wrote my own coding & it worked. But I have only one problem.

When the value changes in the segments its flickering.

For example if the temperature is 29 Celsius when it goes to 30 the both digits flickering so in the flickering time I can see both 88 (all the segments displaying).After the value changes its ok it will display nicely.

Is it a hardware error or coding error?

How do I get a smooth value change?

Here I have attached my hardware as well as my code.

Code:
		list		P=16F877A
		#include	<P16F877A.inc>
		errorlevel	-302
		__config 	_CP_OFF & _PWRTE_ON & _XT_OSC & _WDT_OFF & _BODEN_OFF & _LVP_OFF 
			
		cblock	20h
		Digit1,Digit2,Digit3,ADL,lsd,msd,bigmsd,Del
		endc			
			
		org	0000h
		clrf	STATUS	
Init		bsf	STATUS,RP0
		clrf	TRISB
		clrf	TRISD
		movlw	b'00000001'		;make RA0 input (sensor)
		movwf	TRISA
		movlw	b'10001110'		;result right justified,Vref+=Vdd,Vref-=Vss
		movwf	ADCON1
		bcf	STATUS,RP0			
		movlw	b'01000001'		;ADON,RA0 Channel,FOSC/8
		movwf	ADCON0
		clrf	ADL
		clrf	Digit1
		clrf	Digit2
		clrf	Digit3				
		clrf	PORTB
		clrf	PORTD
		clrf	PORTA
		goto	Main		
				
;************
;Main program
;************			
			
Main		call	Multiplex		;show the display	
		call	Check_AD		;get the AD value		
		bcf	STATUS,0
		[COLOR="Red"][B]rrf	ADL,F			;devide the AD value by by 2[/B][/COLOR]
		call	BCD				;call BCD & make into decimals
		call	BCD_Split		;move BCD results to segment digits
		goto	Main
									
;**********************************
;move BCD results to segment digits
;**********************************			
			
BCD_Split	movf	lsd,W
		movwf	Digit1
		movf	msd,W
		movwf	Digit2
		movf	bigmsd,W
		movwf	Digit3
		return
							
;**********************
;Read AD value routine
;**********************			
			
Check_AD	clrf	ADL
		bsf	ADCON0,GO
		btfsc	ADCON0,GO
		goto	$-1
		bsf	STATUS,RP0
		movf	ADRESL,W
		bcf	STATUS,RP0
		movwf	ADL
		return

;****************************
;8 bit to 3 digit BCD version
;****************************

BCD		movf	ADL,W
		clrf	msd			;result register1
		clrf	lsd			;result register2
		clrf	bigmsd			;result register3
		call	convert_bcd
		movf	msd,W
		call	convert_big
		return			

convert_bcd	clrf	msd			; clear the msd
		movwf	lsd			; move the number to convert into lsd
ten		movlw	.10			; load the constant 10
		subwf	lsd,w			; subtract 10 from lsd
		btfss	STATUS,0		; check if answer negative
		goto	done			; conversion complete, jump to done
		movwf	lsd			; save the answer back in lsd and
		incf	msd,F			; increment the msd
		goto	ten			; do the routine again
done		return				; return to caller
convert_big	clrf	bigmsd			; clear hundreds 
		movwf	msd			; move the hundred number to msd
hundred		movlw	.10			; load the constant 10
		subwf	msd,w			; subtract 10 from msd
		btfss	STATUS,0		; check if answer negative
		goto	hundreddone		; conversion complete, jump to hundreddone
		movwf	msd			; save the answer back in msd and
		incf	bigmsd,F		; increment the bigmsd
		goto	hundred			; do the routine again
hundreddone	return				; return to caller

;*******************************************************						
;Multiplex routine 3 digits (last digit ignoring-Digit3)
;*******************************************************	
		
Multiplex	movlw	10h
		movwf	PORTD
		movf	Digit3,W
		call	Delay
		movf	Digit2,W
		call	Delay
		movf	Digit1,W			
		goto	Delay
			
Delay		call	Table
		movwf	PORTB
		decfsz	Del,F
		goto	$-1
		clrf	PORTB
		bcf	STATUS,C
		rlf	PORTD,F
		return	

;***************************************
;Data look up table for segment patterns
;***************************************
			
Table		addwf	PCL,F
		retlw	b'01111110'		;0
		retlw	b'01100000'		;1 	  ;dp    cbdeafg
		retlw	b'00111101'		;2	
		retlw	b'01110101'		;3			
		retlw	b'01100011'		;4			
		retlw	b'01010111'		;5			
		retlw	b'01011111'		;6			
		retlw	b'01100100'		;7			
		retlw	b'01111111'		;8			
		retlw	b'01110111'		;9			
			
			
		end
 

Attachments

  • LM35.JPG
    5.7 KB · Views: 154
How do I get a smooth value change?
You could write your code so the display is only updated every second or so. That way the bobble will be slower when the ADC is near a changer over in value. You could also write your code to take the average of 256 ADC readings and then update the display. You also could also have noise on the ADC input. A lowpass filter may help.
 
Last edited:
You mean that my Multiplexing routine I must call every one second?

You could also write your code to take the average of 256 ADC readings and then update the display.
Sorry kchriste I cannot understand this.

In my diagram is it a low pass filter?
 
Suraj143 said:
You mean that my Multiplexing routine I must call every one second?
No, just try calling BCD_Split once a second. The display will still "bobble" when the ADC is near the threshold of changing values, but only at a one second rate. Maybe something like this untested/inelegant code:

Code:
Main          movlw 0x??                     ; delay value
                movwf SomeDelay

Loop		call	Multiplex		;show the display	
		call	Check_AD		;get the AD value		
		bcf	STATUS,0
		rrf	ADL,F			;divide the AD value by by 2
		call	BCD			;call BCD & make into decimals
                decfsz SomeDelay, F
		goto	Loop
 		call	BCD_Split		;move BCD results to segment digits
		goto	Main
Sorry kchriste I cannot understand this.
You would take 256 ADC readings and add them to a 16bit location as they are acquired. The upper 8bits of the 16bit number would represent the average value of the 256 ADC readings after 256 ADC readings. You could also take the average of any other number of readings, but 256 makes the "math" really easy.
In my diagram is it a low pass filter?
Not really, it is more of a damper to compensate for lead capacitance and noise according the the datasheet. A 2.2K resistor in series with the output of the LM35 with a capacitor to ground on the PIC side of the circuit would be a lowpass filter.
 
Last edited:
Hi kchriste I got your point.For every one second I'll update the display & see.
Thanks for that hint.


What I know is for every 256 increments the ADRESH will increment by one.
Thats what I know.
 
Project Success 70%

Hi kchriste I followed your three steps all of the methods gave me good results.

I tried one by one, the best method was reading the average value. That is the more accurate method.

I added a 16bit register to place the 256 times AD results.& read the higher byte to get the average value.

I wrote my own coding again & applied.

Sometimes you can see the bubbles.It means if the temperature is 21 celsious when it goes to 22 C it shifting like this 21,22,21,22,21,22,21,22 this happens continuously even if I read the average temperature.

I also applied the 2.2K resister with 0.1uF capacitor (low pass filter)

So what do you think?

Code:
;************
;Main program
;************			
Display	call	Multiplex						
Loop	call	Check_AD		
	incfsz	Count256,F	;count 256 AD readings
	goto	$+9		;No,
	clrf	Count256	;yes, it has reached 256 times
	bcf	STATUS,C
	rrf	average_H,F	;make the value divide by 2
	call	BCD		;make the value into decimals
	call	BCD_Split	;convert into segment digits
	clrf	average_H	;clear 16 bit higher byte
	clrf	average_L	;clear 16 bit lower byte
	[COLOR="Red"]goto	Display		;show the display with updates	[/COLOR]
	movf	ADL,W		;take the AD result to W
	addwf	average_L,F	;add the value to lower byte of average register
	btfss	STATUS,C	;has the carry bit set?
	[COLOR="Red"]goto	Display		;No, then show the display without updates[/COLOR]
	incf	average_H,F	;Yes, then increment the higher byte of average register
	[COLOR="Red"]goto	Display		;show the display without updates[/COLOR]
 
I wrote my own coding again & applied.
Code looks good and will display the average value. Good work.
So what do you think?
If you want to totally eliminate the digit bobble, you would need to scale your input with an OpAmp to use the entire 10bits of the ADC. Then your code would have to add 1-2bits of hysteresis which would eliminate the bobble but also reduce the effective resolution to 8bits which would be fine in your case. Least significant digit bobble is a common artifact when a digital device displays an analog signal which is between two neighboring values:
if the temperature is 21 celsious when it goes to 22 C it shifting like this 21,22,21,22,21,22,21,22
The real temperature is 21.5 Celsius so the display will bobble.
 
Last edited:
kchriste said:
Code looks good and will display the average value. Good work.
Thank you

Least significant digit bobble is a common artifact when a digital device displays an analog signal which is between two neighboring values:
Oh I see I thought this bobble happens only in my coding.Its a common fact

The real temperature is 21.5 Celsius so the display will bobble.
Exactly

kchriste I just checked my temperature is correct or not?I measured the LM35 output voltage.
Its showing 0.28V = 25 Celsius

It should 28 Celsius.

Why is this happeneing?

Shall I add 3 to the result of the ADC every time?
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…