PIC mathematical operations weird problemPIC uno32 SPI communication with sensorNTC Thermistor circuit, ADC conversion, compute temperaturePIC18f45k20 ADC - always returns zeroRatiometric ADC and conversion algorithmsThe 4-wire resistive touch is connected to the ADC's input but it doesn't give correct valueUsing a digital potentiometer in a voltage dividerfluctuating ADC Reading for 4-20mA Pressure transducer inputMeasuring input voltage with 3.3V ADC MCUA/D Input PIC24EPConvert ADC value to real voltage
Why doesn't WotC use established keywords on all new cards?
How wide is a neg symbol, how to get the width for alignment?
I'm in your subnets, golfing your code
Can a nothic's Weird Insight action discover secrets about a player character that the character doesn't know about themselves?
Independent, post-Brexit Scotland - would there be a hard border with England?
What is the difference between 'unconcealed' and 'revealed'?
Building a list of products from the elements in another list
Fitch Proof Question
Why didn't the check-in agent recognize my long term visa?
Why wasn't the Night King naked in S08E03?
Is there an idiom that support the idea that "inflation is bad"?
Would Hubble Space Telescope improve black hole image observed by EHT if it joined array of telesopes?
Why was the battle set up *outside* Winterfell?
In Avengers 1, why does Thanos need Loki?
Can hackers enable the camera after the user disabled it?
Would the Disguise Self spell be able to reveal hidden birthmarks/tattoos (of the person they're disguised as) to a character?
I need a disease
Shantae Dance Matching
How to model the curly cable part of the phone
Have I damaged my car by attempting to reverse with hand/park brake up?
How to apply differences on part of a list and keep the rest
Why do only some White Walkers shatter into ice chips?
Has a commercial or military jet bi-plane ever been manufactured?
Can you complete the sequence?
PIC mathematical operations weird problem
PIC uno32 SPI communication with sensorNTC Thermistor circuit, ADC conversion, compute temperaturePIC18f45k20 ADC - always returns zeroRatiometric ADC and conversion algorithmsThe 4-wire resistive touch is connected to the ADC's input but it doesn't give correct valueUsing a digital potentiometer in a voltage dividerfluctuating ADC Reading for 4-20mA Pressure transducer inputMeasuring input voltage with 3.3V ADC MCUA/D Input PIC24EPConvert ADC value to real voltage
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read()
function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:
adc_value*(4.9)*(11) / 4096
My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:
4.9*11/4096 = 0.01315917968.
But when I multiply them like this, I get something incorrect:
int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;
I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?
pic adc c
$endgroup$
|
show 2 more comments
$begingroup$
I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read()
function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:
adc_value*(4.9)*(11) / 4096
My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:
4.9*11/4096 = 0.01315917968.
But when I multiply them like this, I get something incorrect:
int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;
I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?
pic adc c
$endgroup$
$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15
$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19
2
$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38
$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42
$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55
|
show 2 more comments
$begingroup$
I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read()
function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:
adc_value*(4.9)*(11) / 4096
My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:
4.9*11/4096 = 0.01315917968.
But when I multiply them like this, I get something incorrect:
int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;
I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?
pic adc c
$endgroup$
I am trying to display the voltage value on my specific GPIO pin. I use PIC18F26K83. I can read ADC value. ( I tested it and it gives correct results.) ADC_read()
function gives me 12 bit number. Now in order to find the voltage value I need to follow this calculation:
adc_value*(4.9)*(11) / 4096
My voltage reference is 4.9 V and I have a voltage divider 1/11. So I need to multiply the adc_value I get, with this:
4.9*11/4096 = 0.01315917968.
But when I multiply them like this, I get something incorrect:
int adc_value= adc_Read(0);
adc_value=adc_value*0.01315917968;
I supposed to get something around 11. ADC_Value is around 1100. But the result of this calculation becomes 2.... Where am I wrong with this calculation?
pic adc c
pic adc c
edited Apr 24 at 7:36
Mike
31714
31714
asked Apr 24 at 5:58
Günkut AğabeyoğluGünkut Ağabeyoğlu
19613
19613
$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15
$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19
2
$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38
$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42
$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55
|
show 2 more comments
$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15
$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19
2
$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38
$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42
$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55
$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15
$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15
$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19
$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19
2
2
$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38
$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38
$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42
$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42
$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55
$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55
|
show 2 more comments
3 Answers
3
active
oldest
votes
$begingroup$
Try dividing by 1/0.013159 => 76 instead.
8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.
You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.
$endgroup$
1
$begingroup$
A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
$endgroup$
– Uwe
Apr 24 at 8:34
$begingroup$
You are absolutely correct, I blame it being early in the morning when I answered.
$endgroup$
– r_ahlskog
Apr 24 at 8:37
add a comment |
$begingroup$
Where am I wrong with this calculation?
To add to the other answers, and to come at this from a different direction:
The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.
If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:
adc_value*(4.9)*(11) / 4096
For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):
(adc_value * (10 * 4.9 * 11)) / 4096
which is the same as:
(adc_value * 539) / 4096
For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:
(adc_value * 539) >> 12
(This will round down; if we want to round to the nearest integer, see below)
So now we have a calculation which avoids both non-integers and division.
Plugging in the values mentions in a comment to the question:
(1140 * 539) >> 12 = 150
150 in tenths of a volt = 15.0 V, which is the expected answer.
If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.
If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:
(x + 2048) >> 12
So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:
((adc_value * 539) + 2048) >> 12
$endgroup$
1
$begingroup$
Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
$endgroup$
– Yet Another User
Apr 24 at 21:49
add a comment |
$begingroup$
adc_value=adc_value*0.01315917968;
This is a floating poínt calculation and you try to put the result in an int
value.
Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.
float ADC_complete;
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("schematics", function ()
StackExchange.schematics.init();
);
, "cicuitlab");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "135"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2felectronics.stackexchange.com%2fquestions%2f435142%2fpic-mathematical-operations-weird-problem%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Try dividing by 1/0.013159 => 76 instead.
8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.
You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.
$endgroup$
1
$begingroup$
A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
$endgroup$
– Uwe
Apr 24 at 8:34
$begingroup$
You are absolutely correct, I blame it being early in the morning when I answered.
$endgroup$
– r_ahlskog
Apr 24 at 8:37
add a comment |
$begingroup$
Try dividing by 1/0.013159 => 76 instead.
8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.
You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.
$endgroup$
1
$begingroup$
A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
$endgroup$
– Uwe
Apr 24 at 8:34
$begingroup$
You are absolutely correct, I blame it being early in the morning when I answered.
$endgroup$
– r_ahlskog
Apr 24 at 8:37
add a comment |
$begingroup$
Try dividing by 1/0.013159 => 76 instead.
8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.
You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.
$endgroup$
Try dividing by 1/0.013159 => 76 instead.
8-bit microcontrollers are not too happy about floating point. Granted 76 will be a little off (14 instead of 14.47) so you could try rewriting your formula to integer operations and see if you cant get it better than just a plain 76. Divisions may also be a bit sketchy depending on your speed requirement.
You can also multiply with 10 or 100 to get more precision into your values. There is some margin on that 12 bit value stored in a 16 bit integer, enough to multiply by 10 to get a decimal digit on your final value.
edited Apr 24 at 10:38
answered Apr 24 at 6:33
r_ahlskogr_ahlskog
26616
26616
1
$begingroup$
A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
$endgroup$
– Uwe
Apr 24 at 8:34
$begingroup$
You are absolutely correct, I blame it being early in the morning when I answered.
$endgroup$
– r_ahlskog
Apr 24 at 8:37
add a comment |
1
$begingroup$
A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
$endgroup$
– Uwe
Apr 24 at 8:34
$begingroup$
You are absolutely correct, I blame it being early in the morning when I answered.
$endgroup$
– r_ahlskog
Apr 24 at 8:37
1
1
$begingroup$
A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
$endgroup$
– Uwe
Apr 24 at 8:34
$begingroup$
A 12 bit value stored in a 16 bit integer may be multiplied with 10 or 16 without loosing bits of ADC data. But only 8 or 9 bits of ADC data may be multiplied by 100.
$endgroup$
– Uwe
Apr 24 at 8:34
$begingroup$
You are absolutely correct, I blame it being early in the morning when I answered.
$endgroup$
– r_ahlskog
Apr 24 at 8:37
$begingroup$
You are absolutely correct, I blame it being early in the morning when I answered.
$endgroup$
– r_ahlskog
Apr 24 at 8:37
add a comment |
$begingroup$
Where am I wrong with this calculation?
To add to the other answers, and to come at this from a different direction:
The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.
If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:
adc_value*(4.9)*(11) / 4096
For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):
(adc_value * (10 * 4.9 * 11)) / 4096
which is the same as:
(adc_value * 539) / 4096
For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:
(adc_value * 539) >> 12
(This will round down; if we want to round to the nearest integer, see below)
So now we have a calculation which avoids both non-integers and division.
Plugging in the values mentions in a comment to the question:
(1140 * 539) >> 12 = 150
150 in tenths of a volt = 15.0 V, which is the expected answer.
If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.
If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:
(x + 2048) >> 12
So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:
((adc_value * 539) + 2048) >> 12
$endgroup$
1
$begingroup$
Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
$endgroup$
– Yet Another User
Apr 24 at 21:49
add a comment |
$begingroup$
Where am I wrong with this calculation?
To add to the other answers, and to come at this from a different direction:
The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.
If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:
adc_value*(4.9)*(11) / 4096
For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):
(adc_value * (10 * 4.9 * 11)) / 4096
which is the same as:
(adc_value * 539) / 4096
For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:
(adc_value * 539) >> 12
(This will round down; if we want to round to the nearest integer, see below)
So now we have a calculation which avoids both non-integers and division.
Plugging in the values mentions in a comment to the question:
(1140 * 539) >> 12 = 150
150 in tenths of a volt = 15.0 V, which is the expected answer.
If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.
If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:
(x + 2048) >> 12
So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:
((adc_value * 539) + 2048) >> 12
$endgroup$
1
$begingroup$
Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
$endgroup$
– Yet Another User
Apr 24 at 21:49
add a comment |
$begingroup$
Where am I wrong with this calculation?
To add to the other answers, and to come at this from a different direction:
The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.
If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:
adc_value*(4.9)*(11) / 4096
For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):
(adc_value * (10 * 4.9 * 11)) / 4096
which is the same as:
(adc_value * 539) / 4096
For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:
(adc_value * 539) >> 12
(This will round down; if we want to round to the nearest integer, see below)
So now we have a calculation which avoids both non-integers and division.
Plugging in the values mentions in a comment to the question:
(1140 * 539) >> 12 = 150
150 in tenths of a volt = 15.0 V, which is the expected answer.
If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.
If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:
(x + 2048) >> 12
So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:
((adc_value * 539) + 2048) >> 12
$endgroup$
Where am I wrong with this calculation?
To add to the other answers, and to come at this from a different direction:
The PIC18F26K83 has a hardware multiplier, but no hardware divider, nor a floating-point unit. This means that any calculations involving division or non-integers will pull in library functions to do the maths in software. Compared to an equivalent calculation which avoids these things (if that's possible), this will increase the size of the program (unless the library functions are already used elsewhere) and make the calculation slower.
If space or time are important, then it's worth considering alternatives. In this instance we want to calculate:
adc_value*(4.9)*(11) / 4096
For the top line, we can avoid losing precision by using tenths of a volt as the unit, rather than volts, giving us (with a little rearranging):
(adc_value * (10 * 4.9 * 11)) / 4096
which is the same as:
(adc_value * 539) / 4096
For the bottom line, we note that dividing by 4096 is the same as right-shifting by 12 (because 4096 = 2^12). This gives us:
(adc_value * 539) >> 12
(This will round down; if we want to round to the nearest integer, see below)
So now we have a calculation which avoids both non-integers and division.
Plugging in the values mentions in a comment to the question:
(1140 * 539) >> 12 = 150
150 in tenths of a volt = 15.0 V, which is the expected answer.
If we want the value in volts later, we can divide by 10 at that point - but not before. For internal calculations, it may be better to keep it in tenths of a volt to avoid losing any precision.
If we want to round to the nearest integer, the trick is to add to the top of the fraction half the value of the bottom of the fraction. In this case:
(x + 2048) >> 12
So if x is between 0 and 2047, this will output 0. If is x is between 2048 and (2047 + 4096), this will output 1. So the final calcuation is:
((adc_value * 539) + 2048) >> 12
answered Apr 24 at 13:31
Steve MelnikoffSteve Melnikoff
635410
635410
1
$begingroup$
Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
$endgroup$
– Yet Another User
Apr 24 at 21:49
add a comment |
1
$begingroup$
Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
$endgroup$
– Yet Another User
Apr 24 at 21:49
1
1
$begingroup$
Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
$endgroup$
– Yet Another User
Apr 24 at 21:49
$begingroup$
Shifting rather than dividing is obfuscation and does not affect the actual output of the compiler if you are using a competent compiler. In fact, most of them have an unbelievable amount of number theory built in, specifically for avoiding actually executing divisions by most fixed divisors on all architectures.
$endgroup$
– Yet Another User
Apr 24 at 21:49
add a comment |
$begingroup$
adc_value=adc_value*0.01315917968;
This is a floating poínt calculation and you try to put the result in an int
value.
Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.
float ADC_complete;
$endgroup$
add a comment |
$begingroup$
adc_value=adc_value*0.01315917968;
This is a floating poínt calculation and you try to put the result in an int
value.
Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.
float ADC_complete;
$endgroup$
add a comment |
$begingroup$
adc_value=adc_value*0.01315917968;
This is a floating poínt calculation and you try to put the result in an int
value.
Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.
float ADC_complete;
$endgroup$
adc_value=adc_value*0.01315917968;
This is a floating poínt calculation and you try to put the result in an int
value.
Better to work with a complete int calculation on such a small controller. If you really want to use float, yout had to work with a float variable. e.g.
float ADC_complete;
answered Apr 24 at 6:38
MikeMike
31714
31714
add a comment |
add a comment |
Thanks for contributing an answer to Electrical Engineering Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2felectronics.stackexchange.com%2fquestions%2f435142%2fpic-mathematical-operations-weird-problem%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
What is the input voltage value?
$endgroup$
– Chu
Apr 24 at 6:15
$begingroup$
It is 15 V and I get 1140 from ADC_read(); function. But when I do the multiplication I get something incorrect. Maybe this value ( 0.01315917968), has too many fractional parts? That is why it cannot make the calculation?
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 6:19
2
$begingroup$
Did you actually try the current answers and it solved the problem? The PIC can do arbitrary large floating point calculations just fine, that's what a processor does. Are you performing this calculation in the interrupt?
$endgroup$
– pipe
Apr 24 at 7:38
$begingroup$
Actually, I could not multiply with the value 0.01315917968, eventhough I chose adc_value to float or double. So I just decided to divide the adc_value by 76, that makes me lose some accuracy but that was the only option worked for me.
$endgroup$
– Günkut Ağabeyoğlu
Apr 24 at 7:42
$begingroup$
"Actually, I could not multiply with the value 0.01315917968" - but your question says you did, and the result was 2. What did you really see?
$endgroup$
– Dmitry Grigoryev
Apr 24 at 11:55