Digital Systems 3 min read

Binary, hex and decimal

A register doesn't hold "ten"; it holds a pattern of bits. Decimal, binary and hex are three ways to write that same pattern, and hex wins in embedded work because each digit is exactly four bits.

Left: 10 is divided by 2 repeatedly. 10 ÷ 2 = 5 remainder 0, 5 ÷ 2 = 2 remainder 1, 2 ÷ 2 = 1 remainder 0, 1 ÷ 2 = 0 remainder 1. Reading the remainders from the bottom up gives 1010. Right: the bits 1010 sit under the place values 8, 4, 2 and 1; adding the places that hold a 1 gives 8 + 2 = 10. The four bits 1010 are also one hex digit, A.
Divide by 2 and read the remainders upwards; add the place values to go back.

Decimal to binary

Binary uses only the digits 0 and 1, one per bit. To convert a decimal number, divide it by 2 and write down the remainder, then divide the quotient again, until the quotient is 0. The remainders, read from the last to the first, are the binary digits: 10 becomes 1010.

Binary to decimal

Each bit has a place value, doubling from the right: 1, 2, 4, 8 and so on. Add the place values of the bits that are 1. For 1010 that is 8 + 2 = 10. Eight bits reach 255, and sixteen reach 65,535, which is where the limits of uint8_t and uint16_t come from.

Why hex

Binary is exact but long; a 32-bit register is 32 digits. Hexadecimal uses sixteen digits, 0 to 9 and A to F, so one hex digit is exactly four bits. Group the bits in fours from the right and write one hex digit per group: 1010 is 0xA, and a 32-bit register is eight hex digits. Octal groups three bits per digit; you will mostly meet it in Unix file permissions.

DecimalBinaryOctalHex
0000000
1000111
2001022
3001133
4010044
5010155
6011066
7011177
81000108
91001119
10101012A
11101113B
12110014C
13110115D
14111016E
15111117F
bases.pyPython
n = 10print(bin(n), oct(n), hex(n))print(int("1010", 2), int("0xA", 16))
Output
0b1010 0o12 0xa
10 10