CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

ADC Voltage <> integer values(compiler)
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

ADC Voltage <> integer values(compiler)
PostPosted: Fri Nov 14, 2014 8:04 pm     Reply with quote

Hello.
This may be a very basic question, my english is poor so I will try my best to explain what I need.

I want to work with voltages using the ADC.
Several times I just want to check for a voltage using ADC then I need to do the math by hand, lets say 8bit ADC, want 4.2v:
4.2v ÷ (5v ÷ 256) = ~215
Then put in the code something like: if ADC > 215...
No problem with the math at all, but it consumes time and code gets less straightforward to understood.

My question is, there is a way to directly put directly the voltage value in the code (instead of the hand calculated integer) and without making the uC spend time calculating this?
I mean, make the compiler do this math.
Kinda: if ADC > 4.2v... or maybe
if ADC > (4.2/(5/256))...

Thank you.
jgschmidt



Joined: 03 Dec 2008
Posts: 184
Location: Gresham, OR USA

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Nov 14, 2014 11:18 pm     Reply with quote

We often do this with a MACRO. Rather than burying constants deep in the code we do:

Code:
#define  ADC_LEVEL  ( 4.2 / ( 5 / 256 ))
.
.
.
if( ADC > ADC_LEVEL ) etc...


You can then easily change the 4.2 to whatever you need to in the future. Showing the math helps to explain where the constant came from. The compiler will do the math for you the one time - it does not get done at execution time. Look up MACRO in a C language primer for all the fun things you can do with them.

Happy coding.
_________________
Jürgen
www.jgscraft.com
Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 1:51 am     Reply with quote

You can always find out 'what' the expansion codes to, by compiling and looking at the result.

If you try FJMSoft's suggestion, it won't work. Reason is that maths defaults to using integer, and 5/256 in integer, gives 0. So the compiler will complain about a divide by zero error.

However:
Code:

#define int_adc(x) x/0.01953
#define int2_adc(x) x*51.2

    //with you then using:

    if (volt>int_adc(4.2))

    //or
   
    if (volt>int2_adc(4.2))

Will both simply replace intx_adc(4.2), with 215.

The reason is that the compiler 'knows' it can be solved at compile time, since 'x' is a constant in the expression. It then 'sees' the decimal point, and uses float maths _at compile time_ to solve this.

So:
Code:

....................    adc_val=int2_adc(4.2);
035E:  MOVLW  D7
0360:  MOVWF  20


'20' here is the address of the variable 'adc_val', and 0xD7, is 215 in hexadecimal. Smile
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 9:27 am     Reply with quote

Wow!
VERY NICE!

Ttelmah code looks more interesting for me, more flexible and voltage value keeps exposed in the code.

So, I can securely make any math like this "#define int_adc(x) x/0.01953" and it will be placed as integer in the code?

Also, 5/0.01953 = 256... being 256 will not make a problem here?

Thank you very much! :D
Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 10:24 am     Reply with quote

It'll mean that if you did use 5, it'd switch to doing an int16 comparison.
However since you can never test for the ADC reading being above 5v, it shouldn't apply....
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 10:58 am     Reply with quote

I dont want to jump into int16.

Above 5v for sure not, but for exact 5v is possible.
There is a way to compare ADC to 5v without using int16?

Using 0.0196 instead of 0.01953 will add a small error but maximum comes back to 255.
Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 11:23 am     Reply with quote

You can't compare for 5v, with the ADC at all....

It'll 'read' it's maximum, 1.5bits below 5v.

Historically, if you had an 8bit ADC, you'd have to do division by 255, not 256. This makes it slow in a processor. So some years ago, Texas produced an ADC, that was scaled _as if_ it counted to 256, but then stopped at 255. Just about every ADC since has done the same. The PIC ADC behaves as if it counted to 256 (1024), but stops at 255 (1023). It gives 255, nearly 0.03v _below_ 5v, and then doesn't count any higher.

Just do a #define for (say) MAX_ADC, and MIN_ADC, and use these for the maximum and minimum values.
temtronic



Joined: 01 Jul 2010
Posts: 9098
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 12:03 pm     Reply with quote

There is a 'cheat' I did years ago on an 877 project....which should work for most 5V PICs.
Supply the PIC with a VDD of 5.25 volts.Since the VDD max is 5.5 , this is just below the max and the PIC is happy to function fine.
Another possible 'cheat' is to use the Vref option and ,again, feed that pin with 5.25 volts. This is within the spec of VDD+.3 as noted in the datasheets.
If you really,really need to read 5.00 volts this should work for you. Obviously the volts per bit will have to be recalculated, that exercise is left to you.

Jay
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 12:26 pm     Reply with quote

I got it.
Thank you very much!
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Sun Nov 23, 2014 9:06 pm     Reply with quote

Hello again.

Friends, I was trying to use this technique in my code, test code is like this:
Code:

#define VoltToByte(x) x*(255/30) //Voltage will be divided by 6, so maximum will be 30v
#define ChargeCutV VoltToByte(14)

Int8 I;

I=ChargeCutV;

The resulting ASM code is:
Code:

....................     I=ChargeCutV;
014B:  MOVLW  70
014C:  MOVWF  27

Compiler calculated 70h = 112 but...
255 / 30 = 8,5 * 14 = 119 or 77h

How can I solve this?
Thank you very much.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 23, 2014 9:51 pm     Reply with quote

Get more accuracy with floating point math:
Quote:
#define VoltToByte(x) x*(255/30.0)
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Sun Nov 23, 2014 10:43 pm     Reply with quote

PCM programmer wrote:
Get more accuracy with floating point math:
Quote:
#define VoltToByte(x) x*(255/30.0)


Now 77h = 119
NICE!
Thank you very much!!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Mon Nov 24, 2014 2:47 am     Reply with quote

Also, step back. Remember that comment that the ADC _behaves_ as if it has 256 'risers', in terms of it's actual transfer function.

Have a look at AN536 from Microchip.
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Mon Nov 24, 2014 10:41 am     Reply with quote

I was giving a little check in the ASM code:
Code:

....................   if (ADCA<ChargeCutV);
014A:  CLRF   29
014B:  MOVF   24,W
014C:  MOVWF  28
014D:  CALL   032
014E:  MOVF   23,W
014F:  MOVWF  2B
0150:  MOVF   22,W
0151:  MOVWF  2A
0152:  MOVF   21,W
0153:  MOVWF  29
0154:  MOVF   20,W
0155:  MOVWF  28
0156:  CLRF   2F
0157:  CLRF   2E
0158:  MOVLW  6E
0159:  MOVWF  2D
015A:  MOVLW  85
015B:  MOVWF  2C
015C:  CALL   04F
015D:  BTFSS  03.0
015E:  GOTO   15F


It is normal so much code for a simple IF?
I believe it is dealing with floating point numbers.
For test, when I remove all decimal points from VoltageToByte formula and also from the define value the IF code is MUCH shorter, like 4 lines.

Ttelmah, I remember what you told me but I dont know what to do in the code about that :(
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Nov 24, 2014 12:03 pm     Reply with quote

Well, what is one way to convert a float to an integer in C ?
Casting. Do the math in floating point, then cast the result back to an int.
Quote:
#define VoltToByte(x) (int8)((x*(255/30.0)) + 0.5)


Your next question will be, what about rounding ?
To round off the float, add 0.5 to the result.
Quote:
#define VoltToByte(x) (int8)((x*(255/30.0)) + 0.5)
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group