# Методический план урока: из чисел — в картинку (TFT-экран ST7735)

**Паспорт урока**

| Параметр | Значение |
|---|---|
| **Место в курсе** | Components, урок 6 — завершает блок исполнительных устройств |
| **Длительность** | 45 мин |
| **Возраст** | 13–17, материал двухуровневый |
| **Оборудование** | ESP32, экран ST7735 128×160, 7 проводов — на пару; проектор для разбора кода |
| **Предварительные знания** | `setup`/`loop`, работа с библиотекой, понятие шины (SPI или I2C) |
| **Предмет** | Информатика (кодирование данных, двоичные числа), физика (свет и цвет) |

## Образовательные цели

По итогам урока **ученик умеет**:

| № | Цель | Блум | Миллер | Чем доказывается |
|---|---|---|---|---|
| 6.1 | Объяснить, как из чисел получается изображение | понимать | знает как | Ответ через сетку пикселей |
| 6.2 | Собрать цвет в формате RGB565 и проверить результат | применять | **делает** | Свой цвет на экране совпал с задуманным |
| 6.3 | Объяснить назначение провода DC | понимать | знает как | Ответ через «команда или данные» |
| 6.4 | Вывести на экран текст, фигуры и простую анимацию | применять | **делает** | Работающая программа своей задумки |
| 6.5 | Объяснить, почему анимация требует стирания предыдущего кадра | анализировать | показывает как | Предсказывает «хвост» до запуска |

> **Чего на этом уроке делать НЕ надо.** Не разбирать протокол SPI побайтово и не
> углубляться в устройство библиотеки Adafruit. Ученик должен понять **связь
> «число → пиксель → картинка»** и научиться рисовать. Тайминги шины — материал
> курса схемотехники.

## Что должно быть готово заранее

- [ ] Экран подключён и проверен лично: прошивка [main.cpp](src/main.cpp) выводит все четыре демонстрации
- [ ] Проверена распиновка по [WIRING.md](WIRING.md) — у ST7735 семь проводов, и перепутать легко
- [ ] На проекторе открыты [tft_display.h](include/tft_display.h) (таблица цветов) и [main.cpp](src/main.cpp)
- [ ] Распечатана таблица RGB565 или выведена на доску
- [ ] Лупа или увеличенное фото экрана — для блока 1

> **Полезный реквизит — лупа.** Через неё на экране видны отдельные субпиксели:
> красный, зелёный, синий. Абстракция «картинка состоит из точек» превращается в
> наблюдаемый факт за десять секунд, и это сильнее любого слайда.

## Сценарий занятия (45 минут)

| Время | Блок | Что делает педагог | Что делают ученики |
|---|---|---|---|
| 0–6 | **Завязка** | Даёт лупу, задаёт вопрос про миллионы картинок | Смотрят, находят точки |
| 6–14 | **Пиксель и цвет** | Разбирает RGB565 на доске | Собирают свой цвет на бумаге |
| 14–20 | **Провод DC** | Ведёт к идее «команда или данные» | Формулируют гипотезу |
| 20–34 | **Практика** | Запускает четыре демонстрации | Прошивают, меняют, наблюдают |
| 34–40 | **Анимация и хвост** | Убирает стирание кадра | Предсказывают и проверяют |
| 40–45 | **Итог и ДЗ** | Фиксирует связку число → пиксель | Записывают в журнал |

> **Ключевой методический принцип — сначала на бумаге, потом на экране.** Цвет
> собирается в тетради как двоичное число, и только затем проверяется на железе.
> Если начать с кода, ученик будет подбирать цвета наугад и не поймёт, откуда
> берутся шестнадцатеричные константы.

---

## Блок 1. Завязка (0–6 мин)

Экран показывает картинку. Раздать лупы (или показать увеличенное фото).

> «Телевизор показывает миллионы разных изображений. Внутри у него только
> электроника, которая умеет включать и выключать точки. Как из „включено —
> выключено“ получается фильм?»

Дать посмотреть в лупу. Видны отдельные светящиеся точки, у каждой три цвета.

> «Вот они. У нашего экрана таких точек **128 в ширину и 160 в высоту**. Сколько
> всего?»

Считают: **20 480**. Число достаточно большое, чтобы впечатлить, и достаточно
маленькое, чтобы уложиться в голове.

### Что обычно происходит

| Реакция | Что делать |
|---|---|
| «Там внутри картинка хранится» | «А если я покажу то, чего никто не рисовал заранее?» |
| «Это как мозаика» | **Хорошая аналогия**, закрепить: каждый камешек своего цвета |
| Пытаются сосчитать точки в лупе | Поощрить: перейти к умножению 128 × 160 |

---

## Блок 2. Пиксель и цвет (6–14 мин)

### 2.1. Базовый уровень (13–14 лет)

> «Каждая точка светится своим цветом. Цвет получается смешением трёх ламп:
> красной, зелёной и синей. Меняя их яркость, получаем любой оттенок.»

Проверить на лупе: белый участок экрана — горят все три, чёрный — не горит ни одна.

**Задача:** какой цвет получится, если зажечь красную и зелёную, а синюю погасить?
Обычно отвечают «коричневый» или «оранжевый». Правильный ответ — **жёлтый**, и это
неожиданно. Проверяем на экране константой `COLOR_YELLOW`.

### 2.2. Углублённый уровень (15–17 лет)

Ввести формат хранения:

> «Цвет — это число. У нашего экрана на цвет отводится **16 бит**: пять на
> красный, **шесть на зелёный**, пять на синий. Формат так и называется —
> RGB565.»

| Канал | Бит | Диапазон |
|---|---|---|
| Красный | 5 | 0…31 |
| **Зелёный** | **6** | **0…63** |
| Синий | 5 | 0…31 |

Главный вопрос блока:

> «Почему зелёному досталось на бит больше? Он что, важнее?»

Ответ: **да, для глаза важнее**. Человеческий глаз различает оттенки зелёного
тоньше, чем красного и синего — эволюционное наследие. Лишний бит потрачен там,
где его заметят.

Разбор на доске:

$$\text{цвет} = (R \ll 11) \mathbin{|} (G \ll 5) \mathbin{|} B$$

Проверяем на известной константе `COLOR_RED = 0xF800`:

```
0xF800 = 1111 1 000000 00000
           R=31  G=0    B=0   → чистый красный ✓
```

**Задание в тетради (обязательное, 3 минуты):** собрать фиолетовый — много
красного, немного синего, зелёного ноль. Например, R = 31, B = 15, G = 0.

$$(31 \ll 11) \mathbin{|} (0 \ll 5) \mathbin{|} 15 = \mathtt{0xF80F}$$

Проверить на экране. Совпало — формат понят.

---

## Блок 3. Провод DC (14–20 мин)

Показать [WIRING.md](WIRING.md): у экрана семь проводов, среди них **DC**.

> «У датчиков на I2C проводов данных два. Тут — отдельный провод с именем DC.
> Зачем ему лишний?»

Аналогия, которая снимает вопрос:

> Представь, что тебе по телефону диктуют цифры без пауз и пояснений:
> «пятьсотдвадцатьтринадцатьсемь». Где номер телефона, где сумма, где просьба
> что-то сделать? Непонятно.
>
> DC — это голос, который перед каждой порцией говорит: **«дальше команда»** или
> **«дальше данные»**. Одна и та же восьмёрка байтов будет понята по-разному в
> зависимости от того, что сказал DC.

Разбор — [THEORY.md, раздел 2](THEORY.md#2-spi--лишний-провод-dc-как-чип-понимает-команда-это-или-данные).

> **Инженерный вывод, который стоит записать.** Данные сами по себе не несут
> смысла — смысл задаёт контекст. В протоколах этот контекст передают либо
> отдельной линией (как DC), либо специальными байтами-маркерами внутри потока.
> Та же идея встретится в [разборе протокола NMEA](/docs/sensors/navigation/neo-6-8/)
> у GPS и в CRSF у пульта [БПЛА](/docs/uav/02-algorithms/crsf-and-channels/).

---

## Блок 4. Практика: четыре демонстрации (20–34 мин)

Прошить [main.cpp](src/main.cpp) и разобрать по очереди.

| № | Что на экране | Что обсудить |
|---|---|---|
| 1 | **Текст** — `showMessage()` | Почему экран очищается целиком, а не стирается старый текст? |
| 2 | **Сетка линий** — `drawLine()` в цикле | Как меняется угол каждой линии, почему они выходят из одной точки |
| 3 | **Бегущий круг** — `fillCircle()` дважды | Второй вызов рисует **чёрным** — стирает предыдущее положение |
| 4 | **Динамический текст** — `millis() / 1000` | Почему число нельзя передать напрямую и нужен `snprintf` |

### Задания по уровням

| Уровень | Задание | Критерий |
|---|---|---|
| **Базовый** | Изменить цвета и текст сообщения на свои | На экране своя надпись своим цветом |
| **Базовый+** | Собрать в тетради ещё два цвета (оранжевый, бирюзовый) и проверить | Совпало с задуманным |
| **Средний** | Нарисовать простую фигуру из линий — домик, звезду | Фигура узнаваема |
| **Средний+** | Сделать «индикатор загрузки»: полоса растёт слева направо | Полоса растёт плавно, без мигания всего экрана |
| **Продвинутый** | Анимация с двумя объектами, движущимися с разной скоростью | Оба движутся, хвостов нет |
| **Продвинутый+** | Вывести показания любого датчика из [раздела Sensors](/docs/sensors/) на экран | Числа обновляются в реальном времени |

---

## Блок 5. Анимация и «хвост» (34–40 мин)

Главный эксперимент урока. **Сначала предсказание, потом запуск.**

> «В демонстрации 3 круг бежит по экрану. В коде два вызова `fillCircle`: первый
> рисует круг цветом, второй — чёрным по старому месту. Что будет, если убрать
> второй?»

Дать записать прогноз, потом закомментировать строку и прошить.

На экране остаётся **след из кругов** — «хвост». Ничего не стёрлось, потому что
стирать никто не просил.

> **Вывод, который стоит проговорить.** Экран не «показывает объект» — он хранит
> то, что на нём нарисовали, пока не нарисуют поверх. Анимация — это не движение
> фигуры, а **стирание и перерисовка** много раз в секунду. Ровно так работает
> любая компьютерная графика, от игр до интерфейса телефона.

Для продвинутых — вопрос на подумать:

> «Стирать весь экран перед каждым кадром — просто, но медленно: 20 480 точек. Как
> сделать быстрее?»

Ответ: стирать только то, что изменилось — прямоугольник вокруг старого положения.
Этот приём называется **частичной перерисовкой**, и на нём держится плавность
интерфейсов. Разбор — [THEORY.md, раздел 4](THEORY.md#4-почему-нельзя-просто-перерисовать-один-пиксель).

---

## Ответы на вопросы, которые прозвучат

**«Зачем свой класс `TFTDisplay`, если библиотека Adafruit уже всё умеет?»**
Библиотека универсальная, с большим API — в нём легко утонуть. `TFTDisplay` даёт
узкий набор методов под учебные задачи: проще объяснить, проще пользоваться.
В реальных проектах так делают постоянно — прячут сложное за понятным.

**«Почему у экрана нет Python-визуализатора, как у датчиков?»**
Потому что экран **сам и есть визуализация**. У датчика числа иначе не увидеть,
а здесь результат виден сразу.

**«Что будет, если нарисовать круг радиусом больше экрана?»**
Библиотека обрежет по границам, программа не упадёт. Стоит проверить
экспериментально и обсудить, почему это удобнее аварийного завершения.

**«Можно вывести фотографию?»**
Можно, но она занимает 20 480 × 2 байта ≈ **40 КБ** — это много для памяти ESP32.
Поэтому картинки либо хранят на SD-карте, либо сжимают, либо рисуют примитивами.
Хороший повод обсудить, почему изображения вообще научились сжимать.

**«Экран цветной, а сколько всего цветов?»**
$2^{16} = 65\,536$. Звучит много, но настоящая фотография использует $2^{24} \approx 16$
миллионов — на градиентах разница заметна полосами. Это цена экономии памяти.

---

## Итог урока (30 секунд)

1. Картинка — это **сетка точек**, у каждой свой цвет-число.
2. Цвет в RGB565 — **16 бит**, и зелёному дан лишний бит, потому что глаз к нему
   чувствительнее.
3. Анимация — это **стирание и перерисовка**, а не движение фигуры.

## Проверка понимания (экспресс, 2 минуты)

| Вопрос | Ожидаемый ответ |
|---|---|
| Сколько точек на экране 128×160? | 20 480 |
| Почему зелёному 6 бит, а не 5? | Глаз различает зелёные оттенки тоньше |
| Зачем провод DC? | Различает команду и данные в общем потоке |
| Почему за фигурой остаётся хвост? | Старое изображение не стёрли |

## Типичные затруднения

| Затруднение | Причина | Что делать |
|---|---|---|
| Путают порядок проводов | Их семь, названия похожи | Сверять по [WIRING.md](WIRING.md), подписать маркером |
| Подбирают цвета наугад | Пропустили задание в тетради | Вернуться к формуле и собрать цвет руками |
| Ждут, что фигура «сама» сотрётся | Опыт работы с готовыми интерфейсами | Эксперимент с хвостом из блока 5 |
| Передают число в `printAt` напрямую | Не видят разницы между числом и строкой | Показать `snprintf` в демонстрации 4 |
| Экран белый или не включается | Питание или подсветка | Проверить 3,3 В и провод подсветки |

## Домашнее задание

**Обязательная часть:** найти дома три устройства с экранами разного качества
(телефон, микроволновка, часы) и описать, чем они отличаются: сколько точек, есть
ли цвет, видно ли отдельные пиксели.

**Базовый уровень:** собрать в тетради коды ещё трёх цветов по формуле RGB565 и
проверить их на следующем занятии.

**Средний:** придумать экран статуса для устройства: что выводить, каким цветом,
что должно мигать. Нарисовать макет на клетчатой бумаге 128×160.

**Продвинутый:** прочитать [THEORY.md, раздел 4](THEORY.md#4-почему-нельзя-просто-перерисовать-один-пиксель)
и письменно объяснить, почему полная перерисовка экрана даёт мерцание, а
частичная — нет.

## Связь с курсом

| Что дальше | Где |
|---|---|
| Вывод показаний датчика на экран | [Датчики](/docs/sensors/) — любой модуль |
| Протоколы и разграничение команд и данных | [NMEA у GPS](/docs/sensors/navigation/neo-6-8/), [CRSF в БПЛА](/docs/uav/02-algorithms/crsf-and-channels/) |
| Двоичное представление данных | [Nand2Cpu, модуль 2](/docs/circuit_design/nand2cpu/module_2/) |
| Адресные светодиоды: тоже цвет числом | [LED_adress](../LED_adress/README.md) |

Этот урок закрывает блок исполнительных устройств: плата умеет светить, звучать и
показывать. Дальше — датчики, и связка «измерил → обработал → показал» становится
основой любого проекта.

## Чек-лист педагога перед уроком

- [ ] Экран подключён и проверен, все четыре демонстрации работают
- [ ] Лупа или увеличенное фото экрана готовы
- [ ] Таблица RGB565 на доске или распечатана
- [ ] Код открыт на проекторе: `tft_display.h` с константами цветов и `main.cpp`
- [ ] Заготовлен вариант с закомментированным стиранием — для блока 5
- [ ] Провода подписаны или разложены по порядку: семь штук легко перепутать
