PDA

View Full Version : Sugestions with code



ruijc
- 4th December 2007, 11:15
Hi all,

I've finished my experiment circuit to learn how to handle with ADC,capture, processing it and send out it's readings.

The circuit , using a 16F88 and a LM35 temp sensor reads temp. and voltage and sends the values to a LCD.

I used 10bit resolution, removed last digit from result and added a constant value to calibrate the temperature ( because i get a difference of +- 4ºC ).

For the voltage, since i'm reading from 13V, i used 3 resistor as voltage divider. Then again i added a constant value to calibrate the result.

The code is working and reason for this Thread is only to get feedback from you experient users about the code.

Please let me know you thoughts and tips if this can be improved ;)

Thanks

Here is the code :


Codestart:

output portb.7

low portb.7

Define osc 4

' Define LCD pins
Define LCD_DREG PORTB
Define LCD_DBIT 0
Define LCD_RSREG PORTB
Define LCD_RSBIT 4
Define LCD_EREG PORTB
Define LCD_EBIT 5
Define LCD_BITS 4

'variables
va1 var word
va2 var word
a var byte
b var byte
c var byte
d var byte
e var byte
f var byte
g var byte

pause 200 'init LCD
lcdout $fe,1 'clear LCD

lcdout $fe,2," Voltage/Temp" 'lcd intro
pause 2500

lcdout $fe,1 'clear LCD

'Define ADCIN parameters
Define ADC_BITS 10 ' Set number of bits in result ( 8 or 10 bits )
Define ADC_CLOCK 3 ' Set clock source (3=rc)
Define ADC_SAMPLEUS 50 ' Set sampling time in uS


input porta.0
input porta.1

ADCON1 = %00000001 ' Set PORTA analog

loop:

ADCIN 0, va1 'Store ADC value to va1
va1=va1/10 'remove last digit
ADCIN 1, va2 'Store ADC value to va2
va2=va2/10 'divide by 10 to get xx,xºc
va2=va2 - 42 'calibration setting
va1=va1/10 'remove last digit
va1=va1*2 'multiply to compensate voltage divider
va1=va1+0179 'calibration setting


a=va2 dig 0 ' separate digits
b=va2 dig 1 ' separate digits
c=va2 dig 2 ' separate digits

d=va1 dig 0 ' separate digits
e=va1 dig 1 ' separate digits
f=va1 dig 2 ' separate digits
g=va1 dig 3 ' separate digits

high portb.7 'Led on indicating code running

lcdout $fe,2,"VOLTAGE..",#g,#f,",",#e,#d,"V" 'Show values Line 1 - Voltage
lcdout $fe,$c0,"TEMP.....",#c,#b,",",#a,"C" 'Show values Line 2 - Temperature
pause 250 'pause between readings

Goto loop

End

sayzer
- 4th December 2007, 12:12
Suggestion1:

Remove all these:
a=va2 dig 0 ' separate digits
b=va2 dig 1 ' separate digits
c=va2 dig 2 ' separate digits

d=va1 dig 0 ' separate digits
e=va1 dig 1 ' separate digits
f=va1 dig 2 ' separate digits
g=va1 dig 3 ' separate digits

and use this instead:

lcdout $fe,2,"VOLTAGE..",dec va1 dig 3 ,dec va1 dig 2,",",dec va1 dig 1,dec va1 dig 0,"V" 'Show values Line 1 - Voltage
lcdout $fe,$c0,"TEMP.....",dec va2 dig 2,dec va2 dig 1,",",dec va2 dig 0 ,"C" 'Show values Line 2 - Temperature
pause 250 'pause between readings


Good?
Bad?

ruijc
- 4th December 2007, 16:19
sayzer ,

good one ;)

Anything else ?

jblackann
- 4th December 2007, 16:26
You might want to take a look at this thread also.

http://picbasic.co.uk/forum/showthread.php?t=4289

ruijc
- 4th December 2007, 17:20
jblackann ,

thanks for the link.

But i'm getting a hard time understanding the logic.

AD_AN3_Volt = (AD_AN3_VALUE */ 500) >> 2

Using 10Bit resolution:

5V = 1023 so 2.5V = 511

( final reading on LCD should be 2.50V )

If i have 2.5V the AD_AN3_VALUE = 511

*/ -> get the middle 16bits from the 32 ( divided aftermath )

511 / 500 = 1,022

1,022 - the 16 middle bits ???

Then >>2 means shift 2 positions to the right ( binary ) ??


And final the DEC2 - this is not included in the PBP manual...
EDIT: But this last line i understand the logic.

.

ruijc
- 5th December 2007, 12:47
Can someone help me undestand the code ?

AD_AN3_Volt = (AD_AN3_VALUE */ 500) >> 2

thanks

jblackann
- 6th December 2007, 13:55
I had a problem understanding this too. Here is another link that you can look at that explains the '*/' operator. http://www.picbasic.co.uk/forum/showthread.php?t=5545

Quote from Darrel Taylor on Jan 17, 2007.
======================
*/ is the MidWord multiplier.

When you multiply 2 16-bit values together, you'll get up to a 32-bit result (4 bytes). The Midword, is the 2 bytes in the middle.

For instance, let's say you have an A/D value of 600, and you multiply it times 5000, that gives you 3,000,000. And if you express that in Hexadecimal, it looks like ...
002D:C6C0

The MidWord is 2DC6, or 11,718.

That's the same as (600 * 5000) / 256. The /256 is implied, and happens without the extra time required to do a division. So, it can be allot faster than using DIV32.

The rest of the formula is, >> 2, or shiftright 2 places. Which is the same as /4. Since the result has already been divided by 256, /4 makes the total divisor equal to 1024 (256*4). And, the result will be 2,929, which represents 2.929 Volts input to the ADC.

So, the whole formula is really just (600 * 5000) / 1024. But in a way that PBP can handle it with 16-bit numbers.
--------------------------------------------------------------------------------

OK, so how to go the other direction...

Quote:
I would like to take 0.01 to 0.250V

You'll need the integer numbers (10 to 250) I'll call it Offset. Then just do the reverse formula.

AD_Cal = (Offset * 1024) / 5000

This one doesn't fit in with the */ operator, so you'll need to use DIV32.
Code:
Offset = 250 ; 0.250V - Must be a WORD Var
AD_Cal = Offset * 1024
AD_Cal = DIV32 5000This gives a result of 51, which can then be added or subtracted from the AD result as necessary.

HTH,
__________________
DT
=====================

As for the DEC3 command, I looked in the manual at SEROUT2 command, it has a little bit more explanation. From the manual, a numerical value preceded by DEC will send the ASCII representation of its decimal value. For example, if B0 = 123, then DEC B0 (or DEC 123) will send "123".

Also BIN, DEC, and HEX may also be followed by a number. Normally these modifiers will display exactly as many digits as necessary, zero blanked (leading zeros are not sent). However, if a number follows the modifier, SEROUT2 will always send that number of digits, adding leading zeros as necessary. It was also trim off any extra high order digits. For exampl, BIN6 8 would send "001000" and BIN2 8 would send "00".

You can try to do some experimenting with this.

I believe with the code I supplied
======
TO have precision to three decimal points use:
AD_AN3_Volt = (AD_AN3_VALUE */ 5000) >> 2
LCDOUT $FE, 1 ' Clear LCD screen
LCDOUT "A to D Value"
LCDOUT $FE, $C0, DEC (AD_AN3_volt/1000) ,".",DEC3 AD_AN3_VOLT ,"VDC"
=======
I am using 10 bit A to D, so the max value I could have for AD_AN3_VOLT is 1023. I then use the */ 5000 which is equivalent to *5000 /256 and then I use '>>' (shift right by 2) which is equivalent to dividing by 4. My value is now equal to a max of 4995. I then divide AD_AN3_VOLT by 1000 and get a integer (using the DEC will allow it to display 0 if it needs to). And DEC3 AD_AN3_VOLT will provide a 3 digit value for AD_AN3_VOLT. I believe that I how it works. I did this awhile ago and proved it to myself then. I would suggest you experiment with the code and see that happens. Best of luck.

ruijc
- 6th December 2007, 14:34
jblackann,

i thank you very much for the detailed explanation :)

In fact i did tryed the code and it works 5*****

i just wasnt undestanding the math...and now i do ;)

This way we get precise results with less code.


Thanks ;)

.