Chars (PI5)e
Here is the English translation of the text with content verification:
---
- Drawing Characters on the Raspberry Pi**
After implementing a function to set individual pixels, we now want to teach the Raspberry Pi to display text on the screen. Texts consist of characters that the computer does not inherently recognize. Like a human, the computer must first "learn" how each character looks before it can display it. These characters are defined in a specific code that the computer understands. One of the most widely used codes is the ANSI character code.
- The ANSI Character Code**
The ANSI character code we are using here is an extension of the original ASCII code. While ASCII originally used only 7 bits per character, ANSI extends this to 8 bits, which equals one byte. The ANSI code was developed when computers needed to communicate over networks and ensure that both sides used the same characters. The first 128 characters in the ANSI code match the ASCII code, but characters 128 to 255 can vary depending on the code page used.
Here, we use "Codepage 437," which was originally developed by IBM for MS-DOS computers and is still used today in the Windows command line.
| | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 0A | 0B | 0C | 0D | 0E | 0F | | --- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | | 0x0 | NUL| ☺ | ☻ | ♥ | ♦ | ♣ | ♠ | • | ◘ | ○ | ◙ | ♂ | ♀ | ♪ | ♫ | ☼ | | 0x1 | ► | ◄ | ↕ | ‼ | ¶ | § | ▬ | ↨ | ↑ | ↓ | → | ← | ∟ | ↔ | ▲ | ▼ | | 0x2 | Space | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | | 0x3 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | | 0x4 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | | 0x5 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | | 0x6 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | | 0x7 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | DEL | | 0x8 | Ç | ü | é | â | ä | à | å | ç | ê | ë | è | ï | î | ì | Ä | Å | | 0x9 | É | æ | Æ | ô | ö | ò | û | ù | ÿ | Ö | Ü | ¢ | £ | ¥ | ₧ | ƒ | | 0xA | á | í | ó | ú | ñ | Ñ | ª | º | ¿ | ⌐ | ¬ | ½ | ¼ | ¡ | « | » | | 0xB | ░ | ▒ | ▓ | │ | ┤ | ╡ | ╢ | ╖ | ╕ | ╣ | ║ | ╗ | ╝ | ╜ | ╛ | ┐ | | 0xC | └ | ┴ | ┬ | ├ | ─ | ┼ | ╞ | ╟ | ╚ | ╔ | ╩ | ╦ | ╠ | ═ | ╬ | ╧ | | 0xD | ╨ | ╤ | ╥ | ╙ | ╘ | ╒ | ╓ | ╫ | ╪ | ┘ | ┌ | █ | ▄ | ▌ | ▐ | ▀ | | 0xE | α | ß | Γ | π | Σ | σ | µ | τ | Φ | Θ | Ω | δ | ∞ | φ | ε | ∩ | | 0xF | ≡ | ± | ≥ | ≤ | ⌠ | ⌡ | ÷ | ≈ | ° | • | · | √ | ⁿ | ² | ■ |
- Creating a Font**
To enable the computer to display characters, we need to show it what each character looks like. To do this, we create a kind of database where each character is described as an 8x8 pixel pattern.
For example, the file describing these characters might look like this:
```c /* 8x8 FONT by Satyria */
@ Dimension, noch verzichten wir auf die Dimensionen @.int 8 @ x @.int 8 @ y
@ Data @ 0: NULL .byte 0b00000000 .byte 0b00000000 .byte 0b00000000 .byte 0b00000000 .byte 0b00000000 .byte 0b00000000 .byte 0b00000000 .byte 0b00000000
...
@ 65: "A" .byte 0b00011000 .byte 0b00111100 .byte 0b00111100 .byte 0b01100110 .byte 0b01111110 .byte 0b11000011 .byte 0b11000011 .byte 0b00000000
@ 66: "B" .byte 0b11111100 .byte 0b01100110 .byte 0b01100110 .byte 0b01111100 .byte 0b01100110 .byte 0b01100110 .byte 0b11111100 .byte 0b00000000 ```
In this example, the character "A" is described as an 8x8 pixel pattern, where each byte represents a row of the pattern. Each bit in this byte stands for a pixel: A set bit (1) means that the pixel is drawn, while an unset bit (0) means that the pixel remains transparent.
My example for the font is saved as "ms8x8font.fon" in the include directory.
- Drawing Characters on the Screen**
After defining what each character looks like, we need to write a function to display these characters on the screen. We call this function "DrawChar." It will be given the character to draw as well as the position (x, y) on the screen.
First, we save the passed values so that they are not overwritten by other functions:
```asm //void DrawChar(char c, u32 x0, u32 y0) //Draws a character at position x0, y0 on the screen .globl DrawChar DrawChar: stp x29, x30, [sp, -16]! stp x20, x21, [sp, -16]! stp x10, x11, [sp, -16]! stp x12, x13, [sp, -16]! stp x14, x15, [sp, -16]! mov x29, sp
// Save the position first
mov w20, w1 // x0 mov w21, w2 // y0 ```
Next, we calculate the pointer to the character we want to draw. The font is stored in the data section and has the label "font." To determine the exact position of the desired character, we shift the value of the character 3 bits to the left (equivalent to multiplying by 8 since each character has 8 rows) and add it to the base pointer:
```asm
// Calculate the pointer to the correct character
ldr x10, =font lsl w0, w0, #3 add x10, x10, x0 ```
Now that we have the pointer to the character, we use two nested loops to iterate through the 8x8 pixel pattern:
```asm
//for (w11 = 0; w11 < FONT_HEIGHT; w11++)
mov w11, #0 1: cmp w11, #FONT_HEIGHT bge 2f
//for (w12 = 0; w12 < FONT_WIDTH; w12++)
mov w12, #0 3: cmp w12, #FONT_WIDTH bge 4f ```
Within the inner loop, the current byte of the row we are drawing is loaded into `w13`. To check the relevant bit, the byte is shifted to the right (`lsr`), so that the bit to be checked is at position 0. Then it is checked with an `and` instruction to see if this bit is set:
```asm
// Check the bit using the following formula: // (Row >> (7 - BitPos)) & 1;
ldrb w13, [x10,
w11]
ldr w14, =7 sub w14, w14, w12 lsr w13, w13, w14 tst w13, #1 beq 5f ```
If the bit is set, we calculate the corresponding coordinates on the screen and call the `SetPixel` function to set the pixel at that position:
```asm
// Draw the pixel
add w13, w20, w12 add w14, w21, w11 bl SetPixel 5: ```
This process is repeated for every row of the character. After each row is completed, the function loops back and moves to the next row. Once all rows are drawn, the function exits:
```asm
// Jump back to the inner loop
add w12, w12, #1 b 3b 4:
// Jump back to the outer loop
add w11, w11, #1 b 1b 2: ```
Finally, we restore the saved values and return:
```asm ldp x14, x15, [sp], 16 ldp x12, x13, [sp], 16 ldp x10, x11, [sp], 16 ldp x20, x21, [sp], 16 ldp x29, x30, [sp], 16 ret ```
This is how the `DrawChar` function draws a character on the screen.
---
This translation maintains the technical integrity and context of the original text while ensuring the content is accurate.