Number System Conversions

When writing programs for microcontrollers we’re usually stuck dealing with 3 different number systems: decimal, binary and hexadecimal (or hex). We use decimal because it comes naturally; that’s the way we count. Unfortunately, it’s not how computers count. Since computers and microcontrollers are limited to 1’s and 0’s, they count using sequences of these numbers. This is the binary number system. Binary numbers are usually prefixed with the '0b' characters which are not part of the number. Sometimes they are also subdivided into groups of 4 digits to make them easier to read as well as easier to relate to the hexadecimal number system. An example of a binary number is 0b0100.1011. The periods in the number don't represent anything, they just make it easier to read the number.

The binary system is simple to understand, but it takes a lot of digits to use the binary system to represent large numbers. The hexadecimal system can represent much larger numbers using fewer characters, and it closely resembles binary numbers. Hexadecimal numbers are usually prefixed with the characters '0x' which are not part of the number. A single hexadecimal digit can represent four binary digits!

Binary numbers can only consist of 1’s and 0’s; typically a binary number consists of 8 digits (or some multiple of 8) if it’s being used in some kind of a computer (or microcontroller). It’s useful to know how to convert a binary number into a decimal number and vice versa. So how do we convert between number systems? First consider how we determine the value of a decimal number. The number 268 can be broken down as 200 + 60 + 8, or 2 * (10^2) + 6 * (10^1) + 8 * (10^0).  There are two important numbers that we have to know to ‘deconstruct’ the number - the base of the number system and the location of the digit within the number. The base of a decimal number is 10. When we’re converting the number 268, 2 is the second digit, 6 is the first digit and 8 is the zero digit. Each digit has to be scaled according to its place within the number. The scale of the digit is the base of the number system raised to the power of the digit's location in the number. So each number is scaled, and then all of the scaled digits are added to find the total value of the number.

The same method can be used to find the value of a binary number. For example, let’s look at the number 0b1011.0101. The base of the binary system is 2 (the prefix 0b is often used in code to indicate that the number is in the binary format). The value of our number is: 1*(2^7)+0*(2^6)+1*(2^5)+1*(2^4)+0*(2^3)+1*(2^2)+0*(2^1)+1*(2^0), which is equal to 181.

0b1011.0101. What a completely inefficient way of typing a number! But we can represent the same binary number using only 2 hexadecimal digits. First though, we'll start by converting a hexadecimal (hex) number to decimal like we did for a binary number. How about 0xB5? Wait, what?! The prefix 0x is used in code to indicate that the number is being written in hex. But what is ‘B’ doing in there? The hexadecimal format has a base of 16, which means that each digit can represent up to 16 different values. Unfortunately, we run out of numerical digits after ‘9,’ so we start using letters. The letter ‘A’ represents 10, ‘B’ is 11, ‘C’ is 12, ‘D’ is 13, ‘E’ is 14 and ‘F’ is 15. ‘F’ is the largest digit in the hex numbering system. We convert the number the same way as before. The value of 0xB5, then, is: B*(16^1)+5*(16^0) or 181.

Knowing how to convert binary and hex to decimal is important, but the most useful number conversion is probably converting between hex and binary. These two numbering systems actually work pretty well together. The numbering systems happen to be related such that a single hex digit represents exactly 4 binary digits, and so 2 hex digits can represent 8 bits (or binary digits). Here’s a table that shows how each hex digit is related to the binary system:

Binary Value Hex Value
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 A
1011 B
1100 C
1101 D
1110 E
1111 F

For example, to convert the hex number 0x1C to binary, we would find the corresponding binary value for 1 and C and combine them. So, 0x1C in binary is 0b0001.1100. If we wanted to figure out the hex value for a binary number we just go the other way. To find the hex representation of the binary number 0b0010.1011 we first find the hex value for 0010, then the hex value for 1011 and combine them; the hex value would be 0x2B.

There are many free tools available to help convert between these numbering systems, just google 'hex number conversion.' If you use Windows as an operating system you have a great tool built into the calculator. Just change the calculator to scientific mode and you can convert between number systems by typing a number then changing the format of the calculator!

Comments 16 comments

  • What… No love for octal? ;-)

  • Does anybody know how to convert minutes and/or seconds into hexadecimal??? I’m trying to mod a pc baseball game for my own personal use by changing the team data from “and the Oakland Athletics” to “and the Oakland A’s”. I changed the data wav file with my audio editor and uploaded it to the game but it would only play correctly at home but not on the road. The guys at MVPMods website wouldn’t help me even though they did it several times for the Expos and Devil Rays.

    I hope somebody can steer me in the right directions.


  • I just registered on SparkFun and I already found something interesting. Now I can convert from binary and hexadecimal to decimal, but how do I convert from decimal to binary or hexadecimal? I don’t know if that could be useful at all, I just want to do it for the fun of it.

  • I’m having trouble with the statement “A single hexadecimal digit can represent four binary digits!”. <br />
    My understanding is that HexaDecimal is 16 so it would hold up to 16 binary digits, Not 4. <br />
    <br />
    I’m a programmer that has worked with Packed Fields (AS/400) and I can’t figure how it only holds 4 binary digits.

    • A four-bit field can be used to represent 16 different possible values. Values = 2storage bits.

    • There isn’t as much bit-twiddling with the AS/400 as there is in embedded systems. My co-workers were in awe when I did an uppercase conversion by using %BITOR with a 0x80. It’s a different world.

    • To work out how much information (number of combinations) a given length number (n digits) in number base-m (ie. 2 for binary, 10 for decimal, 16 for hexidecimal) it is mn.<br />
      <br />
      1 hex digit can store 161 = 16 combinations or ‘states’, which is the same as 4 binary digits (24 = 16).<br />
      <br />
      <br />
      Some common conversions:<br />
      <br />
      1 octal = 3 binary<br />
      <br />
      1 hex = 4 binary<br />
      <br />
      1 base-64 = 8 binary

    • A single hex digit:<br />
      0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F<br />
      <br />
      Check out the table near the bottom of the tutorial.

  • seanroberts:<br />
    <br />

    seanroberts: Why does it have to be 0b and 0x to tell which form its in, not b and x?<br />
    <br />

    I understand the need for a prefix,I just want to know why it has to be 0b or 0x instead for just b or x. You were talking about making things ambiguous, and having different types of numbers stat with 0 sounds ambiguous.<br />
    <br />
    More to your point, the reason is speed and convenience for a parser. When a computer program is trying to read text it helps to break things down into smaller pieces. If you were to write a compiler or parser or whatnot, you might start by breaking all the text down into words based on were you find blank space. With that done, your program may loop over every word trying to make sense of it. For each token (word) you need to decide whether it’s a number, punctuation, keyword, or other word. What’s a quick way for a program to know if a token is actually a number? It makes things easier if you make a rule that all numbers must start with a number, regardless of the number base (also called the radix). <br />
    <br />
    Have you noticed that many programmimg languages have a rule that function and variable names can have letters and numbers but they must not start with a number? It’s for the same reasons. That rule is the “other side of the coin” if you follow what I mean. <br />
    <br />
    Using 0 allows for quick determination that the token is a number and that the following character will tell you what kind of number. That’s why zero is used. It’s for speed.

  • I don’t see a compiler needed for the tutorial. In fact each number has its radix written along with it, as in “hex number 0x1C in binary”. The problem here is three fold. First, 0x1C is not a hex number, 1C is a hex number. Two, many languages do not use the C pre-processor conventions (they are not part of C IIRC). Third, I commend the tutorial author for using upper case for Hex numbers. The C pre-processor encourages a very sloppy hex style by allowing upper and lower case letters. Why is it sloppy? Because upper and lower case are completely different ASCII values and some languages allow arbitrary radix, like base 60, were the upper and lower are actually different numbers.<br />
    <br />
    To be precise in writing about computers it is better practice (can not bring myself to use that horrible “bxxx practices” phrase) to use upper case for hex, and state the radix without using compiler specific prefixes. Besides, those Roman numerals are confusing.

  • the notation will be determined by the compiler that you’re using. For example, Freescale’s software CodeWarrior defaults to decimal if no prefix or suffix is added. Hexidecimal is indicated by adding ‘$’ as a prefix, binary by adding ‘b’ as a suffix, and decimal by adding ’t' as a suffix. That’s for freescale assembly, I assume the C notation would be the same.<br />
    <br />
    A tutorial on binary math would be very useful…<br />
    <br />

  • Why does it have to be 0b and 0x to tell which form its in, not b and x?

    • 0b and 0x are very widely-held convention to distinguish the base you are using. Many programming languages (C, C++, Python, etc.) and much of computer science in general follow this convention. <br />
      <br />
      For instance (you are on your private island or something), you could write numbers as 10101 (base:binary) or 66 (base:hexadecimal). The immediate problem is that as you read left to right, you automatically see 10,101 (decimal) or 66 (decimal) - neither one of which is right.<br />
      <br />
      To distinguish, a prefix is added because your eyes see the prefix first. 0x is used as a prefix for hex notation and 0b is for binary. The examples I listed then become 0b10101 or 0x66.<br />
      <br />
      If you see a number without a prefix, assume base 10 (decimal). 0b is binary (b for binary). 0x is hex (it has an x in it)<br />
      <br />
      Octal (base 8) has BAD prefix notation but fortunately octal is only rarely encountered. Octal is just prefixed with a zero. This is highly ambiguous and VERY prone to misreading, confusion, and error. For instance, if I wrote the number 067, the most common interpretation is to strip the zeroes in front, thus giving a decimal 67. If we were talking octal, this leading zero would mean it would be an octal number.<br />
      <br />
      The number fifty-five in binary, octal, decimal, and hex:<br />
      <br />
      0b110111 = 067 = 55 = 0x37

      • seanroberts: Why does it have to be 0b and 0x to tell which form its in, not b and x?<br /><br />
        <br />
        I understand the need for a prefix,I just want to know why it has to be 0b or 0x instead for just b or x. You were talking about making things ambiguous, and having different types of numbers stat with 0 sounds ambiguous.

        • Remember that it is a computer program (compiler) that normally reads this stuff. So, when it sees a letter after a space, it assumes a word. If it is a numeral, then, it is a number. By default a number is a decimal. If it starts with 0x or 0b then it is a hex or binary number.