My inexperience with C led me to mix my data types and spend several hours baffled by the result!
MAX7219 Dot matrix module MCU control Display module DIY kit for Arduino
http://r.ebay.com/I0Liug

By Julian

Youtuber, shed dweller, solar charge controller aficionado

13 thoughts on “Arduino c mystery – integer constants and 6-bit numbers”
  1. Avataaar/Circle Created with python_avatars w02190219 says:

    really nice

  2. Avataaar/Circle Created with python_avatars Readme .txt says:

    It is not 63 or 32 – you divide it all by 1023 😛 . dtostrf (DOUBLE); Almost none of the above is constant. Almost each parameter has different TYPE and byte width and so the meaning for compiler (e.g. integers are by default signed and cant store more than 32k value) It should be all 'float', so percentage = ((float)AnalogRead(A4) * (float)99.0) / (float)1023.0; dotostrf((double) percentage….); You cant leave it to compiler decide for you Sir. There are differences between compilers.

  3. Avataaar/Circle Created with python_avatars MadManMarkAu says:

    A 16-bit signed integer (the default data type for integers) goes from -32658 to 32767. The analog input goes from 0 to 1023.

    You're multiplying the analog input by 100, then dividing by 1024. You had problems going above 31. If we take the value 31, multiply by 1024, we get 31744. This is very close to the maximum integer value. 32 would produce 32768, which is ABOVE the maximum integer value.

    If you go above the maximum value of an integer, it will wrap around from 32767 to -32768. Thus, the analog value that would normally make the output go to 32, actually takes the intermediate value to -32768. If you divide -32768 by 1024, you get -32.

    To explain more clearly, you're multiplying the 16-bit signed integer value coming from the analogRead() function, by the 16-bit signed integer "100". This value is stored temporarily as a 16-bit signed integer. Thus, the the maximum value of analogRead() this code can handle is 327 (327*100=32700, lower than 32767). As soon as you go above that value, to 328, the value wraps around (328*100=32800, higher than the 32767 maximum). This is where the overflow and "wrap-around" effect you're seeing comes from.

    While using a float value to overcome this problem IS a valid solution, you can also use the "long" data type, which stores a 32-bit signed integer – plenty of space for those overflowed bits. And, doing integer maths is much faster than doing floating-point maths, although the latency of the analogRead() function greatly buries any potential gain you would get from using integer maths.

    Also, you can specify the data type of a constant (or, literal) value, using the "UI", "L" and "UL" modifiers, like thus:

    100UI = 16-bit unsigned integer
    100L = 32-bit signed integer
    100UL = 32-bit unsigned integer

    I would rewrite that line as:

    int percentage = analogRead(A0) * 100UL / 1023;

  4. Avataaar/Circle Created with python_avatars Hans Neve (LB4NH) says:

    Hello, easier way to do this.
    1. read adc 10bit 
    2.shift 10 bit 2 places (>>2)  = 8bit 
    3. divide by 254 * 100 = percentage .

    8bit mcus are not too fond of doubles and longs so i tend to stay away if i can.

  5. Avataaar/Circle Created with python_avatars schwartzenheimer1 says:

    Ditch that Ardweeb-o crap, and just download a REAL C compiler.  Arduino is for Mac fanbois ONLY!

  6. Avataaar/Circle Created with python_avatars oreubens says:

    also   &var[0] is the same as just typing var. 
    println uses the same base code dtostrf used, but you have no control over how it's displayed (how many decimals to show).  Also you may not want to output to go to the serial port, so println isn't always an option.
    'normal' C would have sprintf() or ftoa() to format a float into a string, but that doesn't work on arduino.
    Be careful tho, the width is the MINIMUM width, if you format a large float value, the result could be larger than 5 characters and could overflow your buffer with all nasties resulting from that, make sure your buffer is large enough (at least 6 in this case for the zero terminator)  The width is usually used to 'right align' the number into the given width. (left align with a negative width)

  7. Avataaar/Circle Created with python_avatars oreubens says:

    it's not locking you into 6 bits, it's locking you into 16 bits (the size of an int on arduino)  either signed -32768 to 32767 or unsigned 0 to 65535 whenever any integer calculation exceeds those, you'll get overflow.  You can use the long type which is 32bits (plus or minus 2billion something in signed), or you can use float.  Note that float has an accuracy issue, it can only hold 6 decimal digits accurately (with an exponent)  It's the /1024 that's putting you off, the value you're dividing by 1024 has already overflowed.

  8. Avataaar/Circle Created with python_avatars John Knutsson says:

    when multiplying with a word or integer, you end with a word or integer result, before you divide with 1023. Before dividing you get an overflow, and then you divide. That is what is happening i guess.

  9. Avataaar/Circle Created with python_avatars jpopelish says:

    If A/D outputs 10 bit binary, use 16 bit integer math and multiply by 25, then divide by 256, for a 0 to 99 integer result.  1023 * 25=25575 (fits 16 bit signed integer of +32,767 to -32768.  25575/256=99.9, truncated to 99. 
    Dividing by 256 is also a very fast division, since it is just an 8 bit shift off the right end.

  10. Avataaar/Circle Created with python_avatars jpopelish says:

    This problem is a perfect example why I prefer to program microprocessors in machine language/assembly.  Scaling 1023 to 99 is a simple problem with shifts and adds, and no mysteries.

  11. Avataaar/Circle Created with python_avatars Rob B VK6ES says:

    Not sure of the target subjects but for a sense of scale a top line cyclist can sustain an output of 400W and bursts to over 1.5kW. Even an average  fit person could get to 250W/1000W burst so you will need to select the voltage of the generator carefully to avoid further overflow issues while maintaining good resolution or simply measure th VA in a single light globe used in a bank of paralleled bulbs. The bulbs would also give a nice "analogue" indicator to the subject and audience. It is a bit hard to interpret a numerical display when at maximum effort.

  12. Avataaar/Circle Created with python_avatars HillOrStream says:

    I'd like to see more on this display type. I want to put three or four of these together and scroll text across them.

  13. Avataaar/Circle Created with python_avatars superdau says:

    I'm a little late to the party it seems 😉 . Many good explanations here already. Be aware that the compiler may combine constants used in an expression for efficiency reasons and operations may necessarily be executed in the order things appear in a formula (although, I have to say, I don't know how much of that avr-gcc is doing).

    Try to avoid floats on an Arduino. The C-compiler does a good job at concealing that an ATmega does not have a floatingpoint unit. But all float calculations are done "in software" and are very costly. Stay with the int datatype as long as you can and think about them as fixed point numbers. That's more reasonable in most µC applications anyway. For example the resolution behind the comma of a sensor value is most probably the same over the whole range. So thinking about a value as fixed point is more fitting than thinking about it as float, with which you get more digits behind the comma the smaller the number gets.

    Divisions are even more intensive. So instead of dividing by the number you need, try to multiply with a number first, so you can then divide by a power of 2. Integer multiplication isn't that bad in an AVR (watch for overflows, though, but you know that already 😉 ), and a division by powers of 2 results in simple bit shifts. E. g. instead of dividing by 10 multiply with 205 first then divide by 2048 (2^11).

    All of this of course is not that much of a problem, if you've got enough time to spare in the µC. Arduino wouldn't be so successful, if everyone HAD to think about those details. But for efficient code (or in a case like yours, where even Arduino/gcc couldn't hide the fact from you, that you reach the datatype limits quite fast within am expression) it really pays off to rearrange expressions and combine constants as much as possible (even out of multiple expressions).

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.