# Tutorials: Microcontroller systems (MICSY)

## Numbers and codes

last updated: 01/04/20

For students:

Beginning with this chapter we will come across many "Just do it" tasks. These tasks have to be carried out and have to be documented thoroughly!
Your marks will depend on the documentation!

To better understand parts of this module, first work through the module electronics fundamentals.

### Introduction

Song of this chapter: Kraftwerk > Computerwelt > Nummern

We live in a digital world. Digital comes from digit or digiti in Latin meaning "fingers". Fingers are used to count and nine of them correspond for us to the ten digits 0-9 (symbols) of the decimal system.

If we use numbers we quantize a value, making the step from analog (continuous) to digital (sequence of discrete values). Computers need numbers. We will see later in this course how analog signals are converted to digital signals.

So why did digital electronics won over analog electronics? Analog signals are subject to electronic noise and distortion which can progressively degrade the signal. Digital signals have a finite resolution and can be processed and transmitted without introducing significant additional noise or distortion. Degradation can even be detected and corrected. With the increasing speed of digital circuits and their miniaturization the analog world didn't stand a chance in most applications.

OK it's not the most tingling subject to begin with, but without a good understanding how digital systems calculate and use only two states (high voltage and low voltage) to do all their job, you will not really progress if problems occur in your projects (and they will occur!).

### Numeral systems (wiki)

We have ten fingers, to count from one to ten, an unary numeral system in which every natural number is represented by a corresponding number of symbols (e.g fingers). After the invention of the new symbol `0` (zero), it was possible to develop a positional numeral system because zero is of crucial importance to be able to "skip" a power. Today we use a base-10 numeral system called decimal system with 10 digits from zero to nine. Mankind had other possibilities ;). If we would use our fingers in a binary positional number system with each finger as a position we could count from zero to `1023`. Or why don't we use today a base-20 (vigesimal, fingers and toes) numeral system like in the Mesoamerican Long Count calendar from the Maya?

In a `positional base b numeral system` we get b basic digits (symbols). As zero is included, b-1 natural numerals are used.

Base digits
2 0-1
8 0-7
10 0-9
16 0-9, A-F

Numeral systems with different bases can have sometimes funny names like Quaternary, Nonary, Duodecimal, Tritridecimal or Duosexadecimal. For a list look here.

The binary (base 2) and hexadecimal (base 16) systems are, extensively used in computer science. Sometimes also the octal (base 8) system. The binary system uses only the digits `0` and `1`. The hexadecimal system uses all the digits from the decimal system, plus the letters `A` through `F` (decimal numerals 10 to 15).

A numeral is a sequence of digits, which may be of arbitrary length. Each position in the sequence has a decimal place value. Place values for different bases:

Base place
b 6 5 4 3 2 ones place
Base values
b b5 b4 b3 b2 b1 b0
2 32 16 8 4 2 1
8 32768 4096 512 64 8 1
10 100000 10000 1000 100 10 1
16 1048576 65536 4096 256 16 1

The place value can be calculated with the base:

`Place value = b(place number-1)`

The value of the numeral is calculated by multiplying each digit's value in the sequence by its place value, and summing the results. Let's see some examples:

Base example
2 1101 = 1·8 + 1·4 + 0·2 + 1·1 = 13(10)
8 1101 = 1·512 + 1·64 + 0·8 + 1·1 = 577(10)
10 1101 = 1·1000 + 1·100 + 0·10 + 1·1 = 1101(10)
16 1101 = 1·4096 + 1·256 + 0·16 + 1·1 = 4353(10)

For mathematicians a number is a count that is an idea in our minds. A numeral is a symbol or name that stands for a number. In short: the number is an idea, the numeral is how we write it. In normal language number and numeral are used for the same. But we use always digit when talking about the single symbols that make up numerals.

Because we don't want to confound numbers of different numeral systems, it's a good idea to use subscribed parentheses with the base included: `1001(2) ≠ 1001(10), 1001(2) = 9(10)`.

###### "Just do it" NC1:
• Calculate by hand (note the calculus) the values in decimal for the following numbers: 1010011(2), 4567(8), 53(16), BABA(16).
• There exist positions for numbers less than 1, so that floats are no problem. Calculate by hand (note the calculus) the values in decimal for the following numbers: 11100,11(2), 1100001100,001(8), 7B3A,4(16).
Base number
b 4 3 2 1 -1 -2
Base values
b b3 b2 b1 b0 b-1 b-2
• Read the clock (each column is a binary number hh:mm:ss) and note the result. ### Binary (wiki)

Computers and electronics have no fingers but only two ways to represent the state of anything: high voltage and low (or no) voltage (current, field). So all calculations and manipulations of computers rely on a base-2 number system, the binary numeral system.

In binary we have only two symbols: 0 and 1. But even by using only two symbols we can create any number that a decimal system can.

#### Bit (wiki)

The basic unit of information used in computing and digital communications is the `bit` (BInary Digit). The bit can only have one of two values. To work with bits we use two-state devices like per example a switch. The unit symbol for the bit is `bit`. The two physical states of a binary digit represented by a device can be interpreted as `logical values` (true/false, yes/no), activation states (on/off), any other two-valued attribute. The assignment is a matter of convention, and different assignments may be used even within the same device or program.

In our image the convention is that of the `positive logic`, meaning the higher voltage level represents the value 1 and the lower voltage level represents the value 0.

###### "Just do it" NC2:
• Draw a circuit with a switch like above (opener) using a `negative logic` (see Pull-Up in the tutorial ELEctronics FUndamentals).

#### Counting and converting in binary and hexadecimal

Any number can be represented by a sequence of bits. As seen above we use a positional system, the greater the number the more positions we need. As the number of positions in a binary system can get very high, the hexadecimal system (base 16) is often used by humans to ease the handling. By grouping 4 positions in binary we get one position in hexadecimal.

`Binary` Hex. Dec. | `Binary` Hex. Dec. | `Binary` Hex. Dec. | `Binary` Hex. Dec.
`   0` 0 0 | `10000` 10 16 | `100000` 20 32 | `110000` 30 48
`   1` 1 1 | `10001` 11 17 | `100001` 21 33 | `110001` 31 49
`  10` 2 2 | `10010` 12 18 | `100010` 22 34 | `110010` 32 50
`  11` 3 3 | `10011` 13 19 | `100011` 23 35 | `110011` 33 51
` 100` 4 4 | `10100` 14 20 | `100100` 24 36 | `110100` 34 52
` 101` 5 5 | `10101` 15 21 | `100101` 25 37 | `110101` 35 53
` 110` 6 6 | `10110` 16 22 | `100110` 26 38 | `110110` 36 54
` 111` 7 7 | `10111` 17 23 | `100111` 27 39 | `110111` 37 55
`1000` 8 8 | `11000` 18 24 | `101000` 28 40 | `111000` 38 56
`1001` 9 9 | `11001` 19 25 | `101001` 29 41 | `111001` 39 57
`1010` A 10 | `11010` 1A 26 | `101010` 2A 42 | `111010` 3A 58
`1011` B 11 | `11011` 1B 27 | `101011` 2B 43 | `111011` 3B 59
`1100` C 12 | `11100` 1C 28 | `101100` 2C 44 | `111100` 3C 60
`1101` D 13 | `11101` 1D 29 | `101101` 2D 45 | `111101` 3D 61
`1110` E 14 | `11110` 1E 30 | `101110` 2E 46 | `111110` 3E 62
`1111` F 15 | `11111` 1F 31 | `101111` 2F 47 | `111111` 3F 63

The length of a binary number may be referred to as its bit-length.

##### From binary or hexadecimal to decimal

As seen above the value of the numeral is calculated by multiplying each digit's value in the sequence by its place value, and summing the results.

Base example
2 1101 = 1·8 + 1·4 + 0·2 + 1·1 = 13(10)
16 1101 = 1·4096 + 1·256 + 0·16 + 1·1 = 4353(10)
##### From decimal to binary or hexadecimal (integer)

One method to to convert a decimal number to binary is repeatedly dividing the decimal number by 2, until it is reduced to zero. Every time we divide the remainder of the division becomes a digit in the binary number. To get the remainder is easy because we are dividing by two: If the dividend is even, the remainder will be 0 and if the dividend is odd the remainder is 1.

Example converting `187(10)` to binary:

`187` `/ 2 =` `93` `1`
`93` `/ 2 =` `46` `1`
`46` `/ 2 =` `23` `0`
`23` `/ 2 =` `11` `1`
`11` `/ 2 =` `5` `1`
`5` `/ 2 =` `2` `1`
`2` `/ 2 =` `1` `0`
`1` `/ 2 =` `0` `1`

`187(10) = 10111011(2)`

By grouping 4 bits we get the hexadecimal number: `1011 1011(2) = BB(16) = 11·16 + 11 = 187(10)`.

The same dividing method used for binary numbers can be used to convert decimal numbers to hexadecimal numbers:

Example converting `2019(10)` to hexadezimal:

`2019` `/ 16 =` `126` `3`
`126` `/ 16 =` `7` `14`
`7` `/ 16 =` `0` `7`

`2019(10) = 7E3(16)`

###### "Just do it" NC3:
• Calculate by hand (note the calculus) the binary value of 2019(10).
• As stated above, we get the hexadecimal number by grouping 4 bits to one hexadecimal digit beginning with the least significant 4 bits. Get the hexadecimal number of the binary equivalent of 2019(10) by grouping 4 bits beginning with the lowest bits. Compare the result with the example above.

#### Calculating in binary and hexadecimal

`Rules:`

S1 + S2 = Sum Carry (C)
`0` + `0` = `0` `0`
`0` + `1` = `1` `0`
`1` + `0` = `1` `0`
`1` + `1` = `0` `1`

S1 + S2 + Ci = Sum Carry (C)
`1` + `1` + `1` = `1` `1`

Ci stands for Carry in.

`Examples:`

` 1011(2)` `+`     control in decimal:   `11(10)` `+`
`10011(2)` `19(10)`
`  11 ` `C` `1` `C`
`-----` `--`
`11110(2)` `30(10)`

`  1111(2)` `+`   control in decimal:   `15(10)` `+`
`  1111(2)` `15(10)`
` 10101(2)` `21(10)`
` 1`
` 1 11` `C` `1` `C`
`------` `--`
`110011(2)` `51(10)`

To build a binary adder we need a digital adder circuit. We will see such a circuit in the next chapter.

##### Binary subtraction (direct)

Minuend-subtrahend = difference.

`Rules:`

M - S = Difference Borrower (B)
`0` - `0` = `0` `0`
`0` - `1` = `1` `1`
`1` - `0` = `1` `0`
`1` - `1` = `0` `0`

M - S1 - S2 = Difference Borrower (B)
`0` - `1` - `1` = `0` `1`
`1` - `1` - `1` = `1` `1`

`Examples:`

`11101(2)` `-`           control in decimal:   `29(10)` `-`
` 1010(2)` `10(10)`
`  1 ` `B` `B`
`-----` `--`
`10011(2)` `19(10)`

`111000111(2)` `-`   control in decimal:   `455(10)` `-`
`101001011(2)` `331(10)`
` 1111` `B` `B`
`------` `--`
`001111100(2)` `124(10)`
##### Binary subtraction with two's complement

One drawback of direct subtraction is that borrowing frequently over many positions is tedious and confusing. As our processor has only an digital adders it's by ways more convenient to use a method doing the subtraction by adding the b's (base) complement of the subtrahend (this can be done in all positional numeral systems: e.g tenth complement in a decimal system).

To get the complement the easiest way is often to get b-1-complement and add the number one afterwards. This gets very easy in a binary system because we get the b-1-complement (one's complement) by inverting the subtrahend. To get the two's complement we add the number one.

`Examples:`

Subtrahend One's complement Two's complement
`11101(2)` `00010(2)` + 1 = `00011(2)`
`0000100(2)` `1111011(2)` + 1 = `1111100(2)`

Another advantage of the complements method is that we the minuend can be lesser than the subtrahend which is not possible in the direct method.

`Rules:`

• Add leading zeroes to the subtrahend if it's shorter than the minuend (n bits).
• Calculate the two's complement by inverting the stuffed subtrahend and adding 1.
• Add the complement to the minuend.
• If there is a carry on position n+1 the result is positive. With no carry the result is negative. The absolute value is obtained by calculating the two's complement of the difference.

`Examples:`

We use the same examples as in the direct subtraction:

`29(10) - 10(10) = 19(10)`

stuffed 1's complement 2's complement
`11101(2)` `-`
` 1010(2)`     `01010(2)` `10101(2)` `10110(2)`

`11101(2)` `+`
`10110(2)`
`1` `11 ` `C` `positive`
`-----`
`10011(2)`

`455(10) - 331(10) = 124(10)`

1's complement 2's complement
`111000111(2)` `-`
`101001011(2)`   `010110100(2)` ` 010110101(2)`

`111000111(2)` `+`
`010110101(2)`
`1` `11   111` `C` `positive`
`---------`
`001111100(2)`

In both examples a carry occurred, so the results are positive. Let' try the last example by changing minuend and subtrahend, so that the minuend is lesser:

`331(10) - 455(10) = -124(10)`

1's complement 2's complement
`101001011(2)` `-`
`111000111(2)`   `000111000(2)` ` 000111001(2)`

`101001011(2)` `+`
`000111001(2)`
`0` ` 1111 11` `C` `negative`
`---------`
`110000100(2)`

No carry, so the result is negative. We get the absolute value with the two's complement of the result:

`Result:            110000100(2)`
`One's complement:  001111011(2)`
`Two's complement:  001111100(2) = 124(10)`

To build a binary subtraction circuit we need the digital adder from above and an inverter circuit.

##### Binary multiplication

Multiplicand·multiplier = product (factor·factor = product).

`Rules:`

Md · Mr = Product
`0` · `0` = `0`
`0` · `1` = `0`
`1` · `0` = `0`
`1` · `1` = `1`

This is the truth table of an `AND` gate. The AND gate us a one bit multiplier circuit.

• Each bit of the multiplicand is logically interconnected by an AND with the bits of the multiplier beginning with the least significant bit (`20`).
• The results of the consecutive multiplications (AND's) are shifted by one position to the left and added to the momentary result.

`Example:`

`    11011(2)` `·`      control in decimal:   ` 27(10)` `·`
`     1101(2)` ` 13(10)`
`---------` `---`
`    11011` ` 81`
`   00000` `27`
`  11011` `1` `C`
` 11011` `---`
`11111` `C` `351(10)`
`---------`
`101011111(2)`

To build a binary multiplier we need `AND` gates, shift registers and adder circuits.

##### Binary division

Dividend / by divisor = quotient (numerator / denominator = quotient).

The division is a successive subtraction.

`Rules:`

• The divisor is subtracted step wise from the dividend. Doing this the divisor is shifted by one position to the right after each step and the subtraction is done by the two's complement method.
• To get a one (1) in the quotient, the subtraction must be positive (carry at n+1), or the subtraction is discarded (zero (0) in the quotient).

`Example:`

Let's do the following division: `1011101,11(2) / 110(2)`. The two's complement of the divisor is `001(2)+1 = 010(2)`. If we do a subtraction with 3 positions and `1001(2)+1 = 1010(2)` if we do a subtraction with 4 positions:

` 1011101,110(2)/` `110(2) = 1111,101(2)`   decimal control: `93,75(10) / 6(10) = 15,625(10)`
` 010|||| |||` `6`
` ---|||| |||` `---`
`0111|||| |||` `C` `no carry n+1`: discard `0 ⇩` `33`
` 1011||| |||` `30`
` 1010||| |||` `--`
`1 1  ||| |||` `C` `carry n+1`: positive `1 ⇩` ` 3 7`
` ----||| |||` ` 3 6`
` 01011|| |||` ` ---`
`  1010|| |||` `   15`
` 1 1  || |||` `C` `carry n+1`: positive `1 ⇩` `   12`
`  ----|| |||` `   --`
`  01010| |||` `    30`
`   1010| |||` `    30`
`  1 1  | |||` `C` `carry n+1`: positive `1 ⇩` `    --`
`   ----| |||` `     0`
`   01001 |||`
`    1010 |||`
`   1     |||` `C` `carry n+1`: positive `1 ⇩`
`    ---- |||`
`    0011 1||`
`     101 0||`
`    111   ||` `C` `carry n+1`: positive `1 ⇩`
`     -----||`
`     000 11|`
`      10 10|`
`     0 1   |` `C` `no carry n+1`: discard `0 ⇩`
`      -----|`
`     011 01|`
`       0 110`
`       1 010`
`      11 1` `C` `carry n+1`: positive `1 ⇩`
`       -----`
`       0 000`

To do a binary division we need shift registers, adders ts and inverters.

##### Basic arithmetic operations in hexadecimal

The rules are the same as in decimal calculations. Here two examples:

`Addition`

` ABC(16)` `+`     control in decimal:   `2748(10)` `+`
` 983(16)` `2435(10)`
`11` `C` `1 1` `C`
`-----` `----`
`143F(16)` `5183(10)`

`Subtraction`

`ABC(16)` `-`           control in decimal:   `2748(10)` `-`
`9F3(16)` `2547(10)`
`1 ` `B` `B`
`---` `----`
`0C9(16)` ` 201(10)`

`Multiplication and Division`

As child we learn the decimal multiplication table by heart. To facilitate the hex multiplication you can use a table for hexadecimal multiplication. The division also works as for decimal numbers.

It's easier to do the calculations in binary and convert the results in hexadecimal numbers.

##### Conclusion

To do the four basic arithmetic operations we need:

All these circuits are implemented in the Arithmetic Logic Unit (ALU) of modern processors and controllers.

###### "Just do it" NC4:
• Do the following calculations by hand in decimal, hexadecimal and binary (using two's complement):
`37(10) + 425(10)`
`4477(10) - 425(10)`
• Do the following calculations by hand in decimal and binary (using two's complement):
`121(10) · 425(10)`
`4477(10) / 37(10)`.

#### Nibble, Byte and Word

##### Nibble

Digital circuits, processors and micro-controller are often built to work with a fixed length of bits. First processors worked with 4 bits called a `nibble`, half a byte and big enough to hold a Binary-Coded Decimal (`BCD`, digits 0-9). A nibble is also one digit in hexadecimal!

##### Byte

The `byte` was historically the number of bits used to encode a single character of text in a computer. Often it was also the smallest addressable unit of memory in many computer architectures. As no standards existed until 1993, the byte could have different length (e.g. six bit or 9 bit).

The international standard IEC 80000-13 defined as unit symbol for the byte the upper-case character `B`. A byte has 8 bit permitting the values 0 through 255 (`28 = 256`). A multiple of the unit byte is not the kilobyte, because kilo is defined as thausend (1000 decimal) and does not fit in the binary system. For for quantities of digital information, the binary prefix `Ki(kibi)` (bi for binary!) was defined and is part of part of the International System of Quantities.

Kibi means `210`, or `1024`. One kibibyte is 1024 bytes and the unit symbol for the kibibyte is KiB. Other binary prefixes are `mebi`, `gibi` and `tebi`.

binary prefix unit symbol value difference to decimal in %
kibi KiB 210 = 1024 2.4
mebi MiB 220 = 10242 = 1048576 4.9
gibi GiB 230 = 10243 = 1073741824 7.4
tebi TiB 240 = 10244 = 1099511627776 10
pebi PiB 250 = 10245 = 1125899906842624 12.6
exbi EiB 260 = 10246 = 1152921504606846976 15.3

##### Word

The `word` is the piece of data used by by the instruction set respectively the hardware of a processor. The bit-length of the word (word length) is an important characteristic of the used processor or computer architecture.

The word size varies in modern processors and micro-controllers from 8 to 64 bits (steps of 8 bits).

As we often use fixed length (mostly multiple of 1 byte) to store data in computers, leading zeros are necessary for numbers with less bits. If we per example one byte, the number `101(2)` (5(10)) will be written `00000101(2)`.

Leading zeros are not required but they do help by showing the the bit-length of the number.

##### Negative numbers

Negative numbers are created with the two’s complement (see later). The highest bit ("sign-bit"), is needed to flag the number as a negative number. To get the 2’s complement, the rest of the bits are inverted and 1 is added. As the highest bit is no longer available, the maximal positive number we can get with a byte is only 127.

bytes range unsigned range signed
`1` `0 to 255 (28-1)` `-128 to 127`
`2` `0 to 65535 (216-1)` `-32768 to 32767`
`4` `0 to 4294967295 (232-1)` `-2147483648 to 2147483647`
###### "Just do it" NC5:
• Let's look at our Arduino platforms. Test the following program on an different Arduino platforms (e.g. Teensy 2.0 (Arduino Uno), Arduino Due, ESP32). Make a table in calc or excel to compare the values.

``````  // jdinc5_test_data_types.ino

void setup() {
Serial.begin(115200);
delay(500);
Serial.println("Numbers of bytes for:");
Serial.println("-------- unsigned whole numbers ----");
Serial.print("bool: "); Serial.println(sizeof(bool));
Serial.print("byte: "); Serial.println(sizeof(byte));
Serial.print("uint16_t: "); Serial.println(sizeof(uint16_t));
Serial.print("word: "); Serial.println(sizeof(word));
Serial.print("unsigned int: "); Serial.println(sizeof(unsigned int));
Serial.print("unsigned long: "); Serial.println(sizeof(unsigned long));
Serial.print("unsigned long long: "); Serial.println(sizeof(unsigned long long));
Serial.println("-------- signed whole numbers ------");
Serial.print("char: "); Serial.println(sizeof(char));
Serial.print("short: "); Serial.println(sizeof(short));
Serial.print("int: "); Serial.println(sizeof(int));
Serial.print("long: "); Serial.println(sizeof(long));
Serial.print("long long: "); Serial.println(sizeof(long long));
Serial.println("-------- floating point numbers ----");
Serial.print("float: "); Serial.println(sizeof(float));
Serial.print("double: "); Serial.println(sizeof(double));
Serial.println("-------- special -------------------");
Serial.print("size_t: "); Serial.println(sizeof(size_t));
}

void loop() {}
``````

#### Binary in programming

As seen binary is what drives all electronics. The electronic circuit knows only two states. An important point is the storing of the states respectively our information. In the image above the information (one byte) is stored mechanically in our switches. In computers we need a circuit capable of storing the information. This can be done e.g. with one transistor and one capacitor for volatile dynamic random-access memory (DRAM) or with more transistors to build memory cells with bistable flip-flops in static random-access memory (SRAM). This will be a chapter of it's own in this course :).

Our circuits memorize states. The interpretation of this states is arbitrary. Let's look at an example. We take a double register of our Arduino (ATmega328), filled with the following ones and zeros:

`1011101001100010(2)`

###### "Just do it" NC6:
• Test the following program and open the monitor to watch the output. Look at the data types and interpret the different outputs. Try to figure out why the second character displayed (high-byte) is weird.

``````  // jdinc6_test_numbers.ino

int i = 0b1011101001100010;
bool b = i;
unsigned int ui = i;
float f = i;
char sl = lowByte(i);
char sh = highByte(i);

void setup() {
Serial.begin(115200);
delay(500);
Serial.print("bool:\t\t\t"); Serial.println(b);
Serial.print("unsigned int:\t\t"); Serial.println(ui);
Serial.print("unsigned int (bin):\t");Serial.println(ui,BIN);
Serial.print("unsigned int (oct):\t");Serial.println(ui,OCT);
Serial.print("unsigned int (hex):\t");Serial.println(ui,HEX);
Serial.print("int:\t\t\t");Serial.println(i);
Serial.print("float:\t\t\t");Serial.println(f);
Serial.print("char low byte:\t");Serial.println(sl);
Serial.print("char high byte:\t");Serial.println(sh);
}

void loop() {}
``````

We see that the same bits can mean a number, even in different numeral systems, or character(s) or an instruction of our programming language:

The flash of the micro-controller used for Arduino Uno (where the program is stored) is organized in words of 16 bit. If we put the same ones and zeros in the flash, they will be interpreted as one command line of a program written in machine code. In assembly language this would be the command `out PORTD,r6`, to copy the byte of register six to the eight pins of port D. The assignment of a unique sequence of bits to the representation of each one of a set of numbers, letters or instructions is called a binary code (see next chapter).

##### Data types in Arduino

While programming, it is important to use the right data type! A wrong data type can give erratic results. It's very difficult to find these errors, because they can show up only at certain numbers. So think twice before using a data type. All data needs to be stored, and the memory of micro-controller is very limited. Also the selection of how to store data makes an impact on performance. So select always the smallest variable that is large enough, and make the datatype unsigned where suited. To hold e.g. a digital pin number in Arduino (0-54) an int (-32768 to 32767) is overkill. A byte is largely enough (0-255).

The reference is here.

• `bool` occupies one byte of memory. `00000000(2)` means `false`, all other values mean `true`. Boolean is a non-standard type alias for bool. Use bool instead.

• `byte` stores an 8-bit unsigned number (0 to 255). Other types that mean the same are `unsigned char` and `uint8_t`. Use byte or uint8_t.

• `word` stores an unsigned number, same as `unsigned integer` or `uint16_t`. The lengths must not be the same. The length of `uint16_t` is always 16 bit (0 to 65535). The lengths of `word` and `unsigned integer` depend on the architecture. Use the program from above if you need to get the length of your platform.

• `unsigned long` and `uint32_t` are the same and can be used for big numbers (4 byte: 0 to 4294967295). If we use constants, we must add `ul`or `UL` to the number.

• `int` (integer) is normally our primary data-type for number storage. It is signed, so the highest bit is used to show if the number is negative (1) or not (0). On ATmega based boards (Uno, Teensy 2.0) an `int` is a 16-bit value with the number range from -32768 to 32767. On other boards (Teensy 3.1, ESP8266, ESP32) we have a 32-bit (4-byte) value for `int` (-2147483648 to 2147483647). If we want only 16 bit on all platforms we can use the type `short` (seldom needed). The 8-bit variant of integer is `char` (-128 to 127) mostly used to store characters (see later).

• `long` is used for bigger integers (4 byte, -2147483648 to 2147483647). If we use constants, we must add `l`or `L` to the number.

• `float` is the datatype for floating-point numbers (number with decimal point). Floating-point numbers can be much bigger than integers and are stored in 4 bytes. There range is from -3.4028235·1038 to 3.4028235·1038, but they have only 6-7 decimal digits of precision. Floating point numbers are not exact! so pay attention when comparing `float` numbers. Also the calculations with floating point numbers on the original Arduino platform (ATmega) are much slower than with integer and should be avoided (if needed use an ESP32 instead). Don't forget the decimal point, otherwise the number will be treated as an `int` (see here for details).

• `char` is the data type that stores a character value (1 byte). Characters are stored as signed numbers, so it is possible to do math with them ('A'+1 = 'B'). There encoding can be found in the ASCII chart. Single quotes are used in C to assign characters.

• `double` is normally the bigger `float` with more precision (e.g. up to 15 digits) and 8 byte. This is not true on the original Arduino platform, where double is the same size as float. If you need double use an ESP8266, ESP32 or Teensy3.x).

• `long long`, `unsigned long long`, and `uint64_t` are defined in C but should not be used on the original Arduino platform, because of the restricted amount of memory.

• `String()` constructs an instance of the String class, so we use here object oriented programming (OOP). Because of the little memory of original Arduino boards, the improper use of this data type can make your sketches fragile and unstable. So use Strings() only if you know what you do and on bigger platforms (e.g. ESP32). Better use arrays of `char`.

• `array` is a data type for a collection of variables that are accessed with an index number. For more information on arrays look in the Arduino array reference.

• `void` is only used in function declarations to indicate that the function does not return information to the function from which it is called.

Table with byte-length of data types

data type   Uno (T2.0) Teensy 3.6 ESP8266 ESP32
unsigned whole numbers:
bool 1 1 1 1
byte 1 1 1 1
uint16_t 2 2 2 2
`word` `2` `2` `4` `4`
`unsigned int` `2` `4` `4` `4`
unsigned long 4 4 4 4
unsigned long long 8 8 8 8
signed whole numbers:
char 1 1 1 1
short 2 2 2 2
`int` `2` `4` `4` `4`
long 4 4 4 4
long long 8 8 8 8
floating point numbers:
float 4 4 4 4
double 4 8 8 8
special:
`size_t` `2` `4` `4` `4`
##### Constants and variables in Arduino

Our data is normally stored in variables, because we mostly want to work with the data, and so change this data. In our micro-controller all bytes in the random access memory (RAM) are variables (Arduino Uno 2 kibibyte).

Variables are values that are changing or have the ability to change.

Constants are values which remain unchanged (read-only).

Our read-only memory (ROM, flash) is much bigger (Arduino Uno 32 kibibyte). So if we use constants, it is a good practice to add the `const` keyword to our data type. The compiler will store this data in the flash, saving memory in the SRAM.

In Arduino (C) we must always assign a data type to a variable ore a constant. Her an example with a variable and a constant:

``````    const float PI = 3.1415;
float circ, r;

void setup() {
Serial.begin(115200);
r = 11;
circ = 2*PI*r;
Serial.println(circ);
}

void loop() {}
``````

In our sketch we use also the number `2` as a constant. We can use integer constants or floating point constants.

Without further indications the number is treated as an integer. To make it a floating point constant we have to add a decimal point:

``````    circ = 2.0*PI*r;
``````

If we want to specify an integer constant with another data type we add a `u` or `U` to force the constant into an unsigned data format, a `l` or `L` to force the constant into a long data format, or both for an unsigned long constant.

``````    a = 33u+v;
b = 33L*w;
c = 100000000UL/d;
``````

If we want to add values in other bases than the base 10, we use the special formatters `0b` for binary and `0x` for hexadecimal (B like in the reference is not convenient, because of its limitation to one byte, we use the C++ variant "0b" instead):

``````    int bina = 0b11011101;
uint16_t hexa = 0xFAC3;
``````

If we need to convert one data type to another (also known as cast) we get 6 different functions to do this: `byte()`,`char()`,`float()`,`int()`,`long()` and `word()`.

##### Converting with `Serial.print()`

Often we use the serial terminal for debugging or for showing results if no display is available. The function `Serial.print()` has the ability to convert a number with a second parameter to another base. Try the following program:

``````    int dec_number = 1458;
int neg_dec_number = -1458;

void setup() {
Serial.begin(115200);
delay(500);
Serial.println(dec_number,BIN);
Serial.println(neg_dec_number,BIN);
Serial.println(dec_number,HEX);
Serial.println(neg_dec_number,HEX);
}

void loop() {}
``````
###### "Just do it" NC7:
• Write an Arduino function that converts a positive decimal number (`unsigned int`) to binary. The output will be an array of characters, also known as a C-string (the 32 characters are accessed with the indexes 0-31, the 33 character automatically given to terminate the string (null-terminated string). Use the modulo operator in your program. The following code is already given:

``````  unsigned long dec_number = 1458;
char bin_string = {"00000000000000000000000000000000"};

void setup() {
Serial.begin(115200);
delay(500);
dec2bin_string(dec_number,bin_string);
Serial.println(bin_string);
}

void loop() {}

void dec2bin_string(int dec_number, char bin_string) {
byte remainder;
}
``````
###### "Just do it" NC8:
• In the above "Just do it"-exercise you had to calculate by hand. Write an Arduino program to verify the calculations with the following output in the serial terminal (document the source code and the output):
``````    ------------ ADDITIONS -------------------
37 + 425 = 462
25 + 1A9 = 1CE
100101 + 110101001 = 111001110
------------ SUBTRACTIONS ----------------
4477 - 425 = 4052
117D - 1A9 = FD4
1000101111101 - 110101001 = 111111010100
------------ MULTIPLICATIONS -------------
121 · 425 = 51425
79 · 1A9 = C8E1
1111001 · 110101001 = 1100100011100001
------------ DIVISIONS -------------------
4477 / 37 = 121
117D / 25 = 79
1000101111101 / 100101 = 1111001
``````

### Binary codes (wiki)

The assignment of a unique sequence of bits to the representation of each one of a set of numbers, letters or instructions is called a binary code.

Even the assignment of bits to the binary numeral system is a code. A binary-code working with 8 bit can represent the binary numbers from 0-255. It can also represent 256 different characters or 256 different machine code instructions.

#### BCD-code (wiki)

An often needed code, that is close family with the binary numeral system is the BCD-code. BCD stands for Binary Coded Decimals.

`Decimal-number` `238` `224` `212` `201`
`0` 0 0 0 0
`1` 0 0 0 1
`2` 0 0 1 0
`3` 0 0 1 1
`4` 0 1 0 0
`5` 0 1 0 1
`6` 0 1 1 0
`7` 0 1 1 1
`8` 1 0 0 0
`9` 1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1

One decimal number is represented with a nibble (4 bit) also known as tetrade. From the 16 tetrades only 10 are used. The don't care-states (unused tetrades) are named pseudo-tetrad(e)s.

To show that working with codes is not always straightforward here as example the addition in BCD.

For results less than 10(10) we have no problems. If the result is bigger, we have to deal with carry or a pseudo-tertade. In both cases a correction with the number 6(10) is needed.

`Examples`

`0001 1000(BCD)` `+`   control in decimal:   `18(10)` `+`
`0101 0100(BCD)` `54(10)`
`  1` `C` `1` `C`
`---- ----` `--`
`0110 1100` `+` `72(10)`
`     0110` correction! (pseudo-tetrade)
`   1 1` `C`
`---- ----`
`0111 0010(BCD)`

`0001 1000(BCD)` `+`   control in decimal:   `18(10)` `+`
`0011 1000(BCD)` `38(10)`
` 111` `C` `1` `C`
`---- ----` `--`
`0101 0000` `+` `56(10)`
`     0110` correction! (carry)
` ` `C`
`---- ----`
`0101 0110(BCD)`

Other Tetrade-Codes are e.g. the Gray-code, the Excess-3-code or the Aiken-code.

#### ASCII (wiki)

A very important (and old :)) code, because it is used to represent text in computers, telecommunications equipment, and other devices is the American Standard Code for Information Interchange `ASCII`.

Most modern character-encoding Codes support many additional characters, but support the basic set of 128 ASCII characters (7 Bit).

Interesting are the first 32 codes. These were used for control characters to control devices (such as teletype machines or printers).

Two important control characters used even today are `line feed` (`10(10), 0x0A, LF, '\n'`),and `carriage return` (`13(10), 0x0D, CR, '\r'`).

In the physical media of typewriters and printers, line feed meant "down" and carriage return "across". (two axes of motion).

Line feed, also named `newline` is used to signify the end of a line of text and the start of a new one (↵ Enter key on the keyboard). But carriage return can mean the same in software, so newline in character encoding can be defined as LF or CR or LF and CR combined into one (commonly called CR+LF or CRLF).

Linux and Unix-like systems use LF as newline. Windows and OS/2 (Apple) use CRLF (older systems like Apple II or Commodore C64 used CR only).

##### ASCII-Table

Dec. Oct. Hex Binary Value   Dec. Oct. Hex Binary Value
000 000 000 00000000 NUL (Null char.) 064 100 040 01000000 @
001 001 001 00000001 SOH (Start of Header) 065 101 041 01000001 A
002 002 002 00000010 STX (Start of Text) 066 102 042 01000010 B
003 003 003 00000011 ETX (End of Text) 067 103 043 01000011 C
004 004 004 00000100 EOT (End of Transmission) 068 104 044 01000100 D
005 005 005 00000101 ENQ (Enquiry) 069 105 045 01000101 E
006 006 006 00000110 ACK (Acknowledgment) 070 106 046 01000110 F
007 007 007 00000111 BEL (Bell) 071 107 047 01000111 G
008 010 008 00001000 BS (Backspace) 072 110 048 01001000 H
009 011 009 00001001 HT (Horizontal Tab) 073 111 049 01001001 I
010 012 00A 00001010 LF (Line Feed) 074 112 04A 01001010 J
011 013 00B 00001011 VT (Vertical Tab) 075 113 04B 01001011 K
012 014 00C 00001100 FF (Form Feed) 076 114 04C 01001100 L
013 015 00D 00001101 CR (Carriage Return) 077 115 04D 01001101 M
014 016 00E 00001110 SO (Shift Out) 078 116 04E 01001110 N
015 017 00F 00001111 SI (Shift In) 079 117 04F 01001111 O
016 020 010 00010000 DLE (Data Link Escape) 080 120 050 01010000 P
017 021 011 00010001 DC1 (XON) (Device Control 1) 081 121 051 01010001 Q
018 022 012 00010010 DC2 (Device Control 2) 082 122 052 01010010 R
019 023 013 00010011 DC3 (XOFF)(Device Control 3) 083 123 053 01010011 S
020 024 014 00010100 DC4 (Device Control 4) 084 124 054 01010100 T
021 025 015 00010101 NAK (Negative Acknowledgement) 085 125 055 01010101 U
022 026 016 00010110 SYN (Synchronous Idle) 086 126 056 01010110 V
023 027 017 00010111 ETB (End of Trans. Block) 087 127 057 01010111 W
024 030 018 00011000 CAN (Cancel) 088 130 058 01011000 X
025 031 019 00011001 EM (End of Medium) 089 131 059 01011001 Y
026 032 01A 00011010 SUB (Substitute) 090 132 05A 01011010 Z
027 033 01B 00011011 ESC (Escape) 091 133 05B 01011011 [
028 034 01C 00011100 FS (File Separator) 092 134 05C 01011100 \
029 035 01D 00011101 GS (Group Separator) 093 135 05D 01011101 ]
030 036 01E 00011110 RS (Req to Send)(Rec Sep) 094 136 05E 01011110 ^
031 037 01F 00011111 US (Unit Separator) 095 137 05F 01011111 _
032 040 020 00100000 SP (Space) 096 140 060 01100000 `
033 041 021 00100001 ! 097 141 061 01100001 a
034 042 022 00100010 " 098 142 062 01100010 b
035 043 023 00100011 # 099 143 063 01100011 c
036 044 024 00100100 \$ 100 144 064 01100100 d
037 045 025 00100101 % 101 145 065 01100101 e
038 046 026 00100110 & 102 146 066 01100110 f
039 047 027 00100111 ' 103 147 067 01100111 g
040 050 028 00101000 ( 104 150 068 01101000 h
041 051 029 00101001 ) 105 151 069 01101001 i
042 052 02A 00101010 * 106 152 06A 01101010 j
043 053 02B 00101011 + 107 153 06B 01101011 k
044 054 02C 00101100 , 108 154 06C 01101100 l
045 055 02D 00101101 - 109 155 06D 01101101 m
046 056 02E 00101110 . 110 156 06E 01101110 n
047 057 02F 00101111 / 111 157 06F 01101111 o
048 060 030 00110000 0 112 160 070 01110000 p
049 061 031 00110001 1 113 161 071 01110001 q
050 062 032 00110010 2 114 162 072 01110010 r
051 063 033 00110011 3 115 163 073 01110011 s
052 064 034 00110100 4 116 164 074 01110100 t
053 065 035 00110101 5 117 165 075 01110101 u
054 066 036 00110110 6 118 166 076 01110110 v
055 067 037 00110111 7 119 167 077 01110111 w
056 070 038 00111000 8 120 170 078 01111000 x
057 071 039 00111001 9 121 171 079 01111001 y
058 072 03A 00111010 : 122 172 07A 01111010 z
059 073 03B 00111011 ; 123 173 07B 01111011 {
060 074 03C 00111100 < 124 174 07C 01111100
061 075 03D 00111101 = 125 175 07D 01111101 }
062 076 03E 00111110 > 126 176 07E 01111110 ~
063 077 03F 00111111 ? 127 177 07F 01111111 Nul

##### Escape sequences

An escape sequence is a combination of characters which represents no text. They are supposed to be intercepted by the program and perform a special function. In the C resp. C++ (Arduino) languages, it's a series of 2 or more characters, starting with a backslash (`\`). They can be used directly in a string. Important escape characters:

Special character Escape sequence
line feed `\n`
carriage return `\r`
tabulator `\t`

Example:

``````    Serial.print("Hello\tWorld\n");
``````

#### Seven-segment display (wiki)

Even with always better and cheaper dot matrix displays, seven-segment displays (SSD's) with LED's are a cheap and effective possibility for displaying decimal numerals even in the dark.

A single byte can encode the full state of a 7-segment-display including a dot (8 LED's). ###### "Just do it" NC9:
• We want to use a 7-segment display (5161AS), to display the value of a nibble (4 bit) in hexadecimal. Search the data sheet and draw a circuit to connect the display to the Arduino Uno or Teensy 2.0. We will use one full Arduino Port (portB for Teensy 2.0 or portD for Arduino Uno), so connect segment A to pin 0 of portB (PB0, 20, LSB), segment B to Pin 1 of portB (PB1, 21) etc.. Don't forget the series resistors. Note your calculations.

• Test with an Arduino program that lights one LED after the other. Document the program.

• Next we will light all LED's at once. Tip: To address all Pins of portB we can write `PORTB = 0xFF;` to light all LED's (DDRB = 0xFF replaces all 8 pinMode() commands). Look at the Arduino reference: https://www.arduino.cc/en/Reference/PortManipulation.

• To use our display we will use a decoding lookup table. The value we want to represent gives us the index of the table where we find the right byte to send to our SSD. Complete the following lookup table:

Bits of PortB: 7 6 5 4 3 2 1 0
Segment: `dp` `g` `f` `e` `d` `c` `b` `a` `Byte:` 0 0 1 1 1 1 1 1 `0x3F` 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
• The lookup table is an array of byte. The output byte in the table is accessed by the array index. Test the lookup table with a loop that outputs all 16 values.
###### "Just do it" NC10:
• Let's build a voltmeter with an 4 Digit SSD showing the voltage from from 0 to 5000 mV. We will use a 4 digit SSD with time multiplex and the analog input A0 (0 V-5 V) of a Teensy 2.0 or Arduino Uno.
As seen in electronics fundamentals because of the persistence of vision our eye doesn't see LED's flicker if the frequency is above 50 Hz. This is used for LED POV displays. We will switch the four digits on and off for 2 ms one after the other. This permits to use only 12 pins instead of 33. Look at the data sheet of our 4-digit SSD SH5461AS, calculate the resistors and draw the circuit.

• Connect the 7 segments to portB (PB0-PB6) for Teensy 2.0 or portD for Arduino Uno. The 4 digits are switched with the lowest nibble of portD (Teensy, portB for Arduino Uno). Test the voltmeter program with a potentiometer (outer terminals to 5 V and ground, wiper (mostly the middle terminal) connected to the analog digital converter (ADC) pin A0 (ADC0)).