PDA

View Full Version : Need advice on A/D



james
- 15th August 2007, 15:49
Hello,

I am currently working on a project that consists of a Seconds Counter, 2 A/D inputs(1 for Temperature, 1 for monitoring battery voltage). The idea is to take the data and transmit via morse code. I have it all wired up to an 2x16 LCD display, and a piezo speaker until I can get everything running correctly. Currently using a PIC16F88 to test all of this, in the end I will be using a PIC12F675.

flow should be as follows
1)Read A/D
2)Turn on Tx
3)Send morsecode in this order: Counter, Temperature, Battery Voltage, and Identification
4)Turn off for 15sec
5)Repeat

My problem is, I am not so sure my A/D is working correctly.. my temperature displayed stays at 77degrees F. the voltage input to the processor is 3.16v Im using an LM335z which is calibrated at 10mv/K..and I know its not 109degree's F. more like 73 F...

I dont mean to come here and get all the answers, although I would love to get some constructive critizism. Not just about problem previously mentioned, but my coding in general..

Thanks in advance,
James



Code is as follows:



'Define LCD connections
'
Define LCD_DREG PORTB 'LCD data bits on PORTB
Define LCD_DBIT 0 'PORTB starting address
Define LCD_RSREG PORTB 'LCD RS bit on PORTB
Define LCD_RSBIT 5 'LCD RS bit address
Define LCD_EREG PORTB 'LCD E bit on PORTB
Define LCD_EBIT 4 'LCD E bit address
Define LCD_BITS 4 'LCD in 4-bit mode
DEFINE LCD_LINES 2 'LCD has 2 rows

' Define ADCIN parameters
'
Define OSC 8 'Set oscillator at 8MHz
Define ADC_BITS 8 'Set number of bits in result
Define ADC_CLOCK 3 'Set Clock source (3 = rc)
DEFINE ADC_SAMPLEUS 50 'Set sampling time in uS
CMCON = 7 'Turn comparators OFF

'------( Variables )------
'
tx var byte 'Transmitter variable
adval var byte 'A/D input for temperature
adval2 var byte 'A/D input for . . . .
tempF var byte 'Result of A/D after temperature conversion
counter var byte 'Time variable
dit var byte 'for morse code "dot"
dah var byte 'for morse code "dash"
ditpause var byte 'for morse code pauses between letters/numbers
wordpause var byte 'Pause between words
i var byte 'Variable for subroutine
dig1 var byte 'Variable for subroutine
dig2 var byte

'------( Registers )------
' 76543210
TRISA = %00000001 'PortA.0 = input, all else = outputs
TRISB = %00000000 'PortB = outputs
OSCCON = %01110000 '
ADCON0 = %01000001 'Make AN0 analog inputs,
ADCON1 = %00000000 'Format selection/divide clock
'Reference voltage = VDD
ANSEL = %00001001 'Sets all A/D off, except RA0 &

'------( Initialization )------
'

dit = 4 'Length of dot in morse code(Lower number is Faster)
dah = dit * 3 'Length of dash in morse code
ditpause = dit * 12 'Length of pause between dits & dahs in morse code
wordpause = ditpause * 5 'Pause between letters/numbers
counter = 0 'Clear time to 0
Pause 18 'Wait for LCD to initialize
LCDOUT $FE, 2, "Loading..."

'------( Main Code )------
'
Loop:

pause 1000
tx = 1
'PORTA.3 = 1 ' Tx ON
counter = counter + 1 'Increment time

ADCIN 0, adval 'Read channel 0 - Temperature
pause 20
adcin 3, adval2 'Read channel 3 - Battery Voltage
tempf = adval / 10 '
Tempf = tempf - 273 '** Conversion from 10mV/K to Fahrenheit**
TempF = Tempf * 9 '
tempf = tempf / 5 '
tempf = tempf + 32 '

LCDout $FE, 1
LCDOUT $FE, 2,$14,$14,$14,$14,$14,$14,$14,$14,$14, "A=", #adval2
LCDOUT $FE, 2, "Cnt=", #counter
Lcdout $FE, $C0, "F=", #tempf,$14,$14,$14,"ID:N3PX"

'------( Subroutine )------
'
for i = 2 to 0 step -1 '
dig1 = counter dig i 'Subroutine to send out :Time
gosub outdigit '
next i

pause 1000 'Pause before sending next reading

for i = 2 to 0 step -1 '
dig1 = tempf dig i 'Subroutine to send out :Temperature
gosub outdigit '
next i

pause 1000 'Pause before sending next reading

for i = 2 to 0 step -1 '
dig1 = adval2 dig i 'Subroutine to send out :Battery Monitor
gosub outdigit '
next i

Pause 1000 'Pause before sending Callsign

gosub a '
gosub num3 'Subroutine to send out :Callsign
gosub b '
gosub c '

tx = 0
'PORTA.3 = 0 'Tx off

Pause 2000 'Pause before recycling

goto loop

outdigit:


Branchl dig1, [num0,num1,num2,num3,num4,num5,num6,num7,num8,num9]

james
- 15th August 2007, 15:54
Whats the corect way for posting code in the nice window?

I thought it was code: then /code ?

keithdoxey
- 15th August 2007, 16:30
Whats the corect way for posting code in the nice window?

I thought it was code: then /code ?



It is but you need the square brackets [ code ] code here [ /code ]

(no space inside the brackets!)

james
- 21st August 2007, 13:33
I still cannot come up with a solution as to whats wrong with the A/D converter. I've used Mister E's "PicMultiCalc" to make sure my clock/bits and sampleus are defined correctly, though it was not the ticket. . . Any idea's?

Another thing I'd like to learn how to fix : The seconds counter gets way behind, due to the output of morse code taking time. I've rigged up a way to compensate for the lost time by adding in counter = counter + 3, throughout my subroutines... but feel this isnt the correct way of keeping my seconds counter on track. I'd like to have the counter as accurate as possible.

any light shed is greatly appreciated.

James

a.majid
- 21st August 2007, 15:50
Hi,
12F675 A/D converter output is 10 bits wide data.
adval and adval2 should assign as word.
Please take care about ansel and adcon settting.

james
- 22nd August 2007, 16:33
majid,

Define ADC_BITS 8 'Set number of bits in result

This should take care of changing the result from 10bits to 8bits, and would eliminate the need for setting adval/adval2 as a WORD. Correct?

I have looked over the ansel and adcon register numerous times, and still I can find no problem with A/D.

mackrackit
- 22nd August 2007, 18:27
Being that you are using ADCIN, VDD as a reference and 8 bit resolution, You do not need to set all of the ADCON0,ADCON1 and so on, PBP does that for you. The default DEFINES are fine for what you are doing so you do not need to put them in your code either.

This is all you need to read the ADC, All the other stuff is available it you need to change the defaults.



tempF VAR WORD 'or BYTE What ever the conversion needs
ANSEL=%00000001 'AN0 Input
CMCON=7

R_ADC: 'Read ADC Loop
ADCIN 0, tempF
LCDOUT $FE,1,#tempF
PAUSE 100
GOTO R_ADC

Darrel Taylor
- 22nd August 2007, 20:38
I think you've got several problems going on here.

First, is the 3.16V output from the device when it's "not 109°F".
Until you resolve the hardware issue, it will never work in software.

Next, while the A/D resolution is 8-bits, and adval doesn't need to be a WORD, the variable used to convert it to Fahrenheit (Ftemp) DOES need to be a WORD.

Also, by using 8-bit A/D, it limits the resolution of the final reading to +/- 3.5°F (horrible).
If you use 10-bit A/D it reduces that to about +/- 0.8°F (better).

Now the formula,
> The LM335 is calibrated as 10mv/°K.
So you have to convert the A/D reading to a voltage before you can convert it to a temperature.
And the math needs to be done differently to avoid overflows and to handle negative values.

DEFINE ADC_BITS 10

adval VAR WORD
TempF VAR WORD
Sign VAR BIT

ADCIN 0, adval 'Read channel 0 - Temperature
pause 20
adcin 3, adval2 'Read channel 3 - Battery Voltage

TempF = adval * 4887 ' Convert to Voltage
TempF = DIV32 1000 ' in millivolts (°K*10)
TempF = TempF -2730 ' Convert °K to °C

Sign = TempF.15 ' Convert °C to °F
TempF = ABS(TempF) * 9 / 5
if TempF DIG 0 > 5 then ' Round up to whole digit over .5
TempF = TempF + 10
endif
TempF = TempF / 10

if Sign = 1 then TempF = -TempF ' restore sign
TempF = TempF + 32

That will give it the full -50 to +150°C range (-58 to +302°F)

Since there are negative numbers, you'll also need to change the Temperature output routine...
IF TempF.15 = 1 then
dig1 = "-"
gosub outdigit
endif
for i = 2 to 0 step -1 '
dig1 = ABS(TempF) dig i 'Subroutine to send out :Temperature
gosub outdigit '
next i

Tested on a 16F88.

HTH,

james
- 24th August 2007, 12:05
Thank you, everyone who helped!

Added Darrel's code into my program and still had no luck. I then put adval straight on to the LCD to see what kind of value I was getting, Ended up being a 5 digit number. I recently learned that 1024 should be the highest possible value to be displayed. So back to the registers for A/D, sure enough I had it left justified, and adcon0 bit 7 set at Fosc/8 instead of FRC(bit6 & 7 = 11). Also when I posted my code,I had TRISA = %00000001, I needed %00001001. So many problems including my formula. Fixed all that, and put the A/D back through Darrel's code ..My LCD now displays 71degree's fahrenheit, and increases when I add heat. (Am very excited!)

Just wanted to thank everyone who replied. Came through great!
Almost ready to launch my weather balloon!

Have a good weekend,
James

a.majid
- 24th August 2007, 19:30
Hi james,
Scaling the A/D input voltage by (230ohm+10kohm) divider or adjust the Vdd at
5.115 volt,and if ADVAL>=511 then Farenheit=9ADVAL-4594.(Last digit is decimal fraction)
If ADVAL<=510 then
minus_sign=1
Farenheit=9ADVAL-4594
Farenheit=~Farenheit+1
endif
Last digit of Farenheit is decimal fraction.

I was really sorry for first reply.At that time I didn't know PBP's 8Bits A/D conversion can
done on 12F675.We use 16F676 to make 10 bit A/D conversion.Today we made 8bit A/D on 16F676 well.
Thank you for sharing.

a.majid