Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

a little c code

Status
Not open for further replies.

aibelectronics

New Member
Could anyone crack this one? I'll cut out the unimportant details:

int b[1700], c[1700], a[1700];
.....
a=(inportb(stat)^0x80)&0xf0;
.....
b=(inportb(stat)^0x080)&0xf0;
.....
a=a>>4;
c=c*0.0196....

Now don't let the upper lines divert you, i only added them for the sake of clarity. The problem actually is with the last line. Won't there be a type conflict b/w c & 0.0196?

a and b in turn take inputs from an ADC via a multiplexer, 1's and 0's essentially, they being the digital representation of an analog signal that we've sampled. 0.0196mV is the resolution of the ADC.

could the code be wrong?
 
well there definitely will be a problem, whether or not your compiler picks it up is another story...

if it's a fancy compiler it might do an implicit typecast of the value in c to a floating point, then do the conversion, and then round the result to an integer to store in c, however that value would be horribly inaccurate, because an integer representing volts would only give you one-volt accuracy... however, I would suspect it would just round .0196 down to zero (nearest integer) and multiply c by that... leaving you with zero every time.

if you want a real result, you would have to typecast the value in c to a floating-point variable, and then multiply it... and you can't store it back into c because it would just get rounded to the nearest integer again.

are you trying to do this on a computer, or on a microcontroller? if it's on a microcontroller (which it seems to be), you should try to make a more clever scheme for figuring out the voltage, most importantly, one that avoids floating-point math, which is something most microcontrollers are not suited for.

for starters, what size is an integer variable for you? if it's an 8-bit variable, then it's only going to handle values from -128 to +127, so a 7-bit signed value... that may or may not be enough for your ADC results.
if you need 8 bits, use an unsigned integer type. if you need 10 or more, then use a 16-bit variable.

one way to do it is to replace 0.0196 with 196 (an integer, which is 10,000 times 0.0196), and then multiply them, and then divide the answer by 10, and then you'll have the answer in millivolts. the operation will have to be done with 16-bit math, and the result will have to be stored in a 16-bit (or more) variable, so you'll either have to change c to a 16-bit, or use a separate variable to store the result. and unless the microcontroller you're using has hardware support for multiplication/division, that operation could be very slow (hundreds of instruction cycles), because multiplication and division (especially in 16-bit) can be very slow on microcontrollers, so hopefully you don't need to do it extremely quickly.
 
evandude said:
if it's a fancy compiler it might do an implicit typecast of the value in c to a floating point, then do the conversion, and then round the result to an integer to store in c.


It beeing a C compiler i would assume it conforms to ANSI regulations?
In that case:

Code:
int = int * double

The double is converted to an integer (wich would turn 0.0196 into 0) before the calculation.
So every result you'll get from that line is the same : 0


Also, i'm assuming the inportb() function returns a byte ? In this case you should use an 'unsigned char' to store the results. using a signed int may screw up the result when you do your bitwise shift.
 
Exo said:
It beeing a C compiler i would assume it conforms to ANSI regulations?

you might be surprised at the number of c compilers for PICs that don't ;) the makers of the C2C compiler are now making the BoostC compiler, and one of its big touted "features" is ANSI compliance, finally.

but yes, I think the scenario you described is correct, so you'll just get all zeros.
 
c code

int=int*double;
actually the correct conversion would be int to double, then the double would be stored as int removing whatever decimal there is.

I hope I communicated my code well? For this was actually posted as a working code for a computer interface circuit(not microcontrollers). Please see PC Oscilloscope circuit at electronicsforu.com, perhaps then you'll get the question bettter. Or is the code wrong? I'll be glad if you helped check up the above website. Otherwise all other part of the code seem correct.

thanks for the help.
 
why would you want to store it as an integer value representing volts though? that would only give you 1-volt resolution! that would be a pretty terrible oscilloscope.

multiplying the constant 0.0196 by 1000 would at least give you the integer value in millivolts, so you'd have at least some amount of resolution...
 
c code

sorry actually it's not my code, i'm only trying to unravel someone else's code. :)
c is an integer because its elements are 1's and 0's, i.e an 8-bit binary approximation of the amplitude of the analog signal at each sample.
For example we might have, say, c[5] or the 6th sample to be equal to 11010001 which is equivalent to 1x2^7+1x2^6+0+1x2^4+...etc in decimal format, representing the amplitude of the analog signal at that moment.
Another section of the code would be used to plot the amplitude/time plot on the PC screen.
I don't know but all other parts of the code seem okay and it's on the strenght of that, that I still want to give the code the benefit of the doubt. Am I missing something? :?
 
I realize what c is supposed to represent in the beginning, but the line
Code:
c[i] = c[i] * 0.0196;
would destroy what was in c, and replace it with 0, 1, or 2 (if it's an 8-bit signed integer, and assuming the implicit typecast is done as you said, int to float to int, rather than just float to int, in which case it would always be zero) and I can't see why you would want to do that.

*edit: I just read the original code from the article...

it seems you left out an extremely important part of the code... :roll:

Code:
float scale =1;
...
c[i]=c[i]*0.0196*45/scale;

by multiplying it by 45, you get 45 counts per volt, instead of 1, or about 22.2 millivolts per count. so they are still doing a little bit of rounding, but to the nearest 22.2 millivolts, not the nearest volt!

makes MUCH more sense that way. :lol:
 
Re: c code

aibelectronics said:
int=int*double;
actually the correct conversion would be int to double, then the double would be stored as int removing whatever decimal there is.

ANSI C will always convert all terms of the equation into the result type.
 
reply

Code:
float scale =1;
...
c[i]=c[i]*0.0196*45/scale;

by multiplying it by 45, you get 45 counts per volt, instead of 1, or about 22.2 millivolts per count. so they are still doing a little bit of rounding, but to the nearest 22.2 millivolts, not the nearest volt!

makes MUCH more sense that way. :lol:[/quote]

that's odd! but wouldn't all their approximation be lost since the result type is integer? It somewhat confuses. 22.2 millivolts/count? I don't quite get it... :?
 
their result would be still an integer, but each volt now contains 45 integers. In other words, each unit is now equal to 22mV

So you have:

INT VOLTS
0 0.022
1 0.044
2 0.066
. .
. .
. .
45 1.000
46 1.022

etc...
 
It's worth noting that arithmetic binary operators (such as + or *) convert their operands to a common type, according to the following precedence:
1. If either operand is not an arithmetic type, no conversion is performed.
2. Else if both operands are of the same type, no conversion is performed.
3. Else if either operand is a double, the other is converted to double.
4. Else if either operand is an unsigned long int, then the other is converted to an unsigned long int.
5. Else if one operand is a long int and the other is an unsigned int, both are converted to unsigned long int.
6. Else if one operand is a long int, (noting that the other must be an int if it has made it to this rule) then the other is converted to a long int.
7. Else if one operand is an unsigned int, then the other is converted to unsigned int.
8. Finally, if this rule is reached, both must be ints, and this is covered in rule 2.

ETA: The calculation is performed, and the result cast to the type of the storage location. Thus, c would be converted to double, because 0.0196 (or whatever) is a double, the result would be a double, and then it would be cast to int to store it in c. That is, of course, if it's ANSI C. Note that the K&R rules are essentially the same, particularly in this regard.

This from Harbison & Steele, second edition.

Note that bitwise logical operators cannot be applied to float or double. These are &, |, ^, ~, >>, and <<, which are bitwise AND, bitwise OR, bitwise XOR, unary ones complement, right shift, and left shift.
 
Thnx Shneibster.

Those were quite important tips that anyone would be interested in. In other words when an arithmetic operation is performed on two operands, the one with the lower range(say integer) is converted to the one of the higher range(say double or unsigned integer). And of course all these could be offset using a type cast: (type)...

The problem has long been solved and I believe much has been gained. Thnx guys. :)
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top