Началось все с обсуждения с восьмилетней дочерью, что такое компьютер. Давно согласился с Фейнманом, что если вы не можете объяснить ребенку, то, вероятно, не до конца разобрались с вопросом.

Первым делом я пытался рассказать, что компьютеры повсюду - офисные компьютеры, телефоны, умная колонка и даже умный холодильник. Стоп, там же микроконтроллер, и на этом понятии я понял, что мне так просто не получится объяснить разницу.

Я рад, что частично застал эпоху становления компьютерной сферы - лучше понимаешь логику изменений. Мои первые программы на MSX (домашний компьютер, приставка на процессоре Z80) были примитивными командами на BASIC, и я представляю их развитие на текущем “железе” на уже “взрослых” языках типа Go.

Мне привычнее начинать классификацию с того, что близко, например, привычный компьютер это персональный компьютер (ПК). Для меня это всегда было устройством для игр разработки и запуска программ, в нем было устройство ввода - клавиатура, вывода - экран или телевизор (для простоты не будем вспоминать про Altair с его набором индикаторов). С ПК все просто и привычно - мат.плата, процессор, память, накопитель, монитор и клавиатура. Ноутбуки - все то же самое, но с батарейкой.

С серверами, мейнфреймами сложнее не намного. По сути, они же тоже мощные компьютеры, но обычно без монитора и клавиатуры, ориентированные на обработку данных, но принцип и компонентная база идентичны. 

А как же смартфоны, вроде бы совсем отличаются от ПК, другие процессоры, технологии? Несмотря на разную компоновку, этот тип устройств все же близок к ПК, точнее как максимальное развитие темы ноутбуков в сторону миниатюризации. У смартфонов есть все те же компоненты - материнская плата, ЦП и оперативная память. Важным фактором является наличие некоторого набора датчиков (температуры, компаса, местоположения, света и тп). Это же похоже на микроконтроллеры?

Да, но нет. Микроконтроллеры отличаются от привычных компьютеров. Они менее универсальны, создавались для конкретных задач. Их прикладное назначение не нуждается в высокой производительности, в основном не супербыстрые (меньше 100 МГц), операционная система им часто не нужна. Архитектурно они обычно монокристальные: в одном чипе размещены процессор, память, порты ввода-вывода, АЦП, ШИМ, иногда небольшой накопитель EEPROM и многое другое.

Получается такая размытая терминология. Ведь если оставить на материнской плате ПК только центральный процессор и BIOS, то это будет микро макро-контроллер? А если наоборот, запускать программы общего назначения на микроконтроллере, станет ли он тогда похож на ПК?

Вот именно этот кейс мне и захотелось попробовать и перейдя от слов к делу, я выделил свободные выходные. Решил сделать совсем простое устройство на микроконтроллере, на котором можно было разработать примитивную программу и запустить ее. Язык программирования можно было выбрать любой, но для усиления эффекта ностальгии по MSX я прикрутил самый простой BASIC.

В этом я буду далеко не новатор - подобные проекты уже существовали. Мой личный вклад состоял в небольших доработках по адаптации и русификации.

Электроника

Для меня это был познавательный учебный процесс: на каждом этапе объяснял детям, что и для чего нужно. Я старался выбирать самые простые и понятные компоненты, ничего не усложняя и дополнительно не прикручивая. 

Вот мои “кубики”:

  • Древняя Arduino Mega 2560;

  • Знаковый (текстовый) экран от компании МЭЛТ, который может отображать 20 символов в 4 строки;

  • Очень компактная клавиатура от проекта CardKB, работает по I2C.

Второстепенные детальки: 

  • Аккумулятор 18650, плата зарядки и светодиоды;

  • Как потом уже оказалось стабилизатор напряжения на базе платы MT3608, иначе экран сильно тускнеет при просадке аккумулятора;

  • Четыре 5V светодиода, тумблер, 1 сопротивление на 220 Ом и набор проводов.

Я погрузился в доки, но понял, что уже сильно обленился и решил призвать на помощь железного ИИ друга. Благодаря коллегам, такой есть у нас в Озоне на базе модели DeepSeek. Я просто описал, какие компоненты у меня есть, и - о чудо! - за 2 секунды я получил полную схему проводов, от экрана и клавиатуры к Arduino. Выглядело это примерно так:

Самое главное - ИИ детально расписал, что куда подключать в табличном виде:

CardKB (I2C клавиатура)

CardKB

Arduino Mega 2560

GND

GND

5V

5V

SDA

Mega pin 20 (SDA)

SCL

Mega pin 21 (SCL)

I2C-адрес CardKB обычно 0x5F

LCD MT-20S4A-2YLG (HD44780, 4-битный режим)

Пины LCD (стандартные 16 пинов)

Номер пина экрана

Название пина экрана

Куда подключаем

1

VSS

GND

2

VDD

5V

3

VO

GND

4

RS

Mega pin 7

5

RW

GND

6

E

Mega pin 6

11

D4

Mega pin 5

12

D5

Mega pin 4

13

D6

Mega pin 3

14

D7

Mega pin 2

15

A (LED+)

5V через резистор 220 Ом

16

K (LED−)

GND

Arduino Mega 2560

Пин Mega

Куда подключаем

2

LCD D7

3

LCD D6

4

LCD D5

5

LCD D4

6

LCD E

7

LCD RS

10

LED+ 1

11

LED+ 2

12

LED+ 3

13

LED+ 4

20

CardKB SDA

21

CardKB SCL

5V

LCD VDD, CardKB 5V

GND

LCD VSS, RW, K, VO CardKB GND, LED- 1, 2, 3, 4

Вот так красиво оно должно было быть по ТЗ:

И вот что напаял чудо-инженер:

С контуром питания я разбирался позднее, но там все проще - от аккумулятора на разъем BAT +/-, от клемм OUT +/- на входное питание стабилизатора и от стабилизатора - на пины 5V и GND Arduino. 

Схема:

Поделка по факту:

Стабилизатор тонкой отверткой отрегулировал на 5.1V, опять же по рекомендации железного друга.

Сделав небольшие тесты экрана и клавиатуры я понял, что все более-менее работает - можно приступать к корпусу.

Корпус.

Мне хотелось все сделать быстро и просто, поэтому, отринув хипстерский метро - минимализм, я взял за основу проверенный топорный кубизм. В этот раз корпус спроектировать получилось очень быстро, благодаря включению в проект готовых скетчей всех компонент в формате stl или step. Нашлись все кроме экрана, но для МЭЛТ простительно. Покрутив их немного, я быстро нарисовал корпус вокруг компонентов, сделав побольше зазоры на порты и крепления. Проектировал в Plasticity, пока печаталась нижняя часть, проектировал верхнюю, затем по тому же принципу -  финальную крышку. Мой первый корпус, который я не перепечатывал по десять раз - с первой попытки получилось приемлемо.

Сначала разместил клавиатуру, Arduino, тумблер и зарядку, оставил место под стабилизатор. Также сделал 5мм отверстия под светодиоды.

Аккумулятор разместил в задней части корпуса вместе с креплением.

Экран под углом установил на верхней крышке отдельной 3D-моделью.

Я намеренно оставлял большие отверстия для проводов, чтобы не разбирать запаянную схему, а просто закреплять компоненты по месту.

В финальном виде захотел закрыть все эти провода, сделав крышку на “монитор” и заднюю заглушку на аккумулятор.

Еще думал закрыть сверху клавиатуру, но кнопки оказались настолько мелкие, что можно было проиграть в функциональности в угоду дизайну.

Получилось три стола для печати. Суммарное время печати совпало с расчетным - примерно 6 часов. Пластика ушло немного, в основном белого.

Результат печати, честно говоря, порадовал, повезло, что ничего не съехало, поддержки отошли штатно.

Куча проводов достаточно просто зашла в корпус, хорошо что места было много.

Странная дружба народов, на Arduino надпись: “Made in Italy”, а на экране патриотическое “Сделано в России”. Даже жалко закрывать крышкой.

Еще немного суперклея и микрошурупов и вот финальный вид готов.

Теперь приступим к написанию программного обеспечения.

Разрабатываем софт

Точнее говоря, дорабатываем готовый для своих нужд. Для начала я начал искать похожий проект и нашел вот этот:

https://github.com/robinhedwards/ArduinoBASIC

Там немного другое периферийное железо, поэтому требовалось адаптировать проект для i2c клавиатуры и тексто-знакового экрана. Почитав исходники, я понял, что опять без электронного ассистента не обойтись...  Хорошо, что исходники небольшие и архитектурно есть разделение между интерпретатором и условно-редактором.

Скормив исходники ИИ, мои приключения начались. Буквально через несколько уточнений удалось сделать практически работающий код, который мог печатать и запускать простые команды.

Проект состоит из трех основных элементов:

  • Основная программа Arduino с setup / loop main.ino

  • Интерпретатор бейсика basic.cpp

  • Поддержка оборудования host.cpp

Большую часть проблем при обеспечении удобства ввода доставил host.cpp, в нем практически пришлось сочинять текстовый редактор вводимых команд и переменных. Стратегия была такая, что есть экранный буфер в виде массива, некий аналог видеопамяти в компьютерах. Весь вывод ведется именно в него. Например, в случае перехода на следующую строку, часть массива сдвигается вверх с помощью функции memmove, а снизу заполняется пробелами с помощью memset.

Имея такой буфер, можно в любой момент перерисовать экран, выводя символы последовательно. 

Очень понравилось, что в экране есть захардкоженный курсор, его просто требуется включить, сказать - “мигай” и указать, координаты где мигать.

   lcd.cursor();
   lcd.blink();
   lcd.setCursor(curX, curY);

Ввод команд и переменных осуществляется в свой буфер в виде строки. Здесь было сложно учесть, что длинная строка может переехать на следующую строку, а потом с помощью backspace вернуться назад. 

Также еще добавил историю вводимых команд, чтобы не вводить их повторно в случае ошибки. Полноценного курсорного ввода - перемещение по строке я не реализовал, уже явно за рамками данного проекта.

В сам интерпретатор я добавил несколько функций и операторов, как по мне без них было бы скучно - CHR$, SIN, COS, DATA, READ и др.

Следующим этапом, мне очень захотелось сделать возможность печати русского текста. Опишу этот кейс подробнее, потому что это был самый интересны�� вызов в этом проекте. 

Сложностей было несколько:

  • В клавиатуре не хватает кнопок для х, ъ, ж, э, вот не понадобились они англоговорящим товарищам, не нужны..  Пришлось “перенести” их над цифрами 6, 7, 8, 9 и 0.  Но как вводить заглавные буквы? Хорошо, что есть режим на клавиатуре sym для ввода специальных знаков.

  • В обычных компьютерах я привык к таблице ASCII, где есть полные наборы русских букв, но в мире IoT все иначе. Не нужно создавать буквы, если есть похожие английские буквы, а таких оказалось много .. с, o, e, p и т.п. Дольше всего я искал заглавную букву Ь. Вот почему заглавный Ъ есть, а мягкого нет?  Помогла дочь, найдя похожесть английской буквы b в нижнем регистре.

  • Русские буквы разбросаны по таблице в случайном порядке. Насколько я понимаю разработчики экрана искали неиспользуемые в российской технике символы и значки, заменяли на русские. Очень много времени потратил на их поиск. Даже сделал специальную микропрограмму для показа таблицы символов, с запуском fn + 1:

  • Как следствие из вышесказанного - нет надежного источника для хранения русских букв в памяти. Клавиатурные коды содержат одинаковые для обоих регистров коды, а экранных русских букв меньше, чем нужно.

Не думая слишком долго, я взял самую простую кириллическую кодировку DOS CP866 и сделал маппинг в коды экрана и клавиатуры. Выглядит это примерно так:

// Структура для хранения маппинга
struct RuMap {
   unsigned char eng;
   unsigned char rus;
   unsigned char lcd;
};
const RuMap ruMap[] = {
   // Нижний регистр
   {'q', 169, 185}, /* й */  {'w', 230, 229}, /* ц */  {'e', 227, 121}, /* у */
   {'r', 170, 186}, /* к */  {'t', 165, 101}, /* е */  {'y', 173, 189}, /* н */
   {'u', 163, 180}, /* г */  {'i', 232, 193}, /* ш */  {'o', 233, 230}, /* щ */
   {'p', 167, 183}, /* з */  {'a', 228, 228}, /* ф */  {'s', 235, 195}, /* ы */
   {'d', 162, 179}, /* в */  {'f', 160,  97}, /* а */  {'g', 175, 190}, /* п */
   {'h', 224, 112}, /* р */  {'j', 174, 111}, /* о */  {'k', 171, 187}, /* л */
   {'l', 164, 227}, /* д */  {'z', 239, 199}, /* я */  {'x', 231, 192}, /* ч */
   {'c', 225,  99}, /* с */  {'v', 172, 188}, /* м */  {'b', 168, 184}, /* и */
   {'n', 226, 191}, /* т */  {'m', 236, 196}, /* ь */  {',', 161, 178}, /* б */
   {'.', 238, 198}, /* ю */  {'7', 229, 120}, /* х */  {'8', 234, 194}, /* ъ */
   {'9', 166, 182}, /* ж */  {'0', 237, 197}, /* э */
   // Верхний регистр
   {'Q', 137, 166}, /* Й */  {'W', 150, 225}, /* Ц */  {'E', 147, 169}, /* У */
   {'R', 138,  75}, /* К */  {'T', 133,  69}, /* Е */  {'Y', 141,  72}, /* Н */
   {'U', 131, 161}, /* Г */  {'I', 152, 172}, /* Ш */  {'O', 153, 226}, /* Щ */
   {'P', 135, 164}, /* З */  {'A', 148, 170}, /* Ф */  {'S', 155, 174}, /* Ы */
   {'D', 130,  66}, /* В */  {'F', 128,  65}, /* А */  {'G', 143, 168}, /* П */
   {'H', 144,  80}, /* Р */  {'J', 142,  79}, /* О */  {'K', 139, 167}, /* Л */
   {'L', 132, 224}, /* Д */  {'Z', 159, 177}, /* Я */  {'X', 151, 171}, /* Ч */
   {'C', 145,  67}, /* С */  {'V', 140,  77}, /* М */  {'B', 136, 165}, /* И */
   {'N', 146,  84}, /* Т */  {'M', 156,  98}, /* Ь */  {'<', 129, 160}, /* Б */
   {'>', 158, 176}, /* Ю */  {'&', 149,  88}, /* Х */  {'*', 154, 173}, /* Ъ */
   {'(', 134, 163}, /* Ж */  {')', 157, 175}, /* Э */
};

Далее я сделал специальную комбинацию клавиш для переключения языка - fn + пробел и глобальную переменную для языка. При вводе с клавиатуры в случае русского языка делаю маппинг букв eng в коды rus (кодировка 866).

При выводе же текста на экран делаю другой маппинг из 866 в коды символов МЭЛТ.

Весь исходный код я выложил в GitHub, модельки соответственно в MakerWorld. 

https://github.com/nicolas-vp/mega_basic

https://makerworld.com/en/models/2399263-arduino-computer-with-basic

Выводы

  • Выходные прошли задорно, никакой бэкенд на Go не заменит удовольствие от отладки кода на C на самом устройстве.

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

  • Наконец-то я оценил практичность рудимента в виде нумерации строк на BASIC с помощью 10, 20, 30..  На маленьком экране корректировать программу быстрее, просто запоминая номер строки для правки.

  • С ИИ создавать электронику стало одно удовольствие, меньше времени тратишь на даташиты, на рутину, где ты не специалист. Для меня, бекенд-разработчика, код на C/CPP конечно похож на Go, но есть нюанс.. Мои познания в электронике минимальны, но вместе с ИИ мы справились.

Позже, развивая аутентичность проекта, я добавил ещё пищалку (PC Speaker), внешнюю память EEPROM и сделал подпрограмму для визуального выбора нот. Но это уже за рамками данной статьи.

Чек-лист

Нашел у себя книгу “Современный компьютер”, Москва “Мир”, 1986. Есть подозрение, что современного там мало уже осталось за 40 лет, но есть определение персонального компьютера с характеристиками. Посмотрим, удовлетворяет ли спроектированное устройство этим критериям.

Персональный компьютер - это небольшая ЭВМ, основой которой служит микропроцессор; иначе говоря, это микро-ЭВМ. Однако не все микро-ЭВМ являются персональными. Микро-ЭВМ может быть ориентирована на решение одной задачи, например на управление станком или регулирование подачи топлива в автомобильный двигатель; она способна обрабатывать тексты, использоваться в качестве телевизионного игрового устройства или карманного калькулятора, который в принципе даже нельзя назвать компьютером. Персональный же компьютер - это нечто иное.

Действуя как самостоятельная вычислительная машина, он предоставляет в распоряжение индивидуального пользователя самые разнообразные функциональные возможности.

В дальнейшем мы будем полагать, что персональный компьютер представляет собой систему, обладающую следующими характеристиками:

1. Стоимость всей системы менее 5 тыс. долл.

Запас по стоимости успешно пройден более чем в 50 раз. 

2. В состав системы входит периферийная память в виде кассетных накопителей на магнитной ленте (НМЛ) или магнитных дисках (НМД), либо она должна иметь возможность подключаться к аналогичным устройствам других систем.

Есть EEPROM 4kb, внешний EEPROM 32kb (его даже можно извлечь) можно сказать, что условно - да.

3. Микропроцессор способен функционировать совместно с памятью объемом по крайней мере 64 килобайт.

В текущей сборке только 8kb на борту, из которых сам интерпретатор забрал почти половину. Ограничение легко обойти, взяв аналогичную по размеру и стоимости плату Arduino DUE с 64kb.

4. Компьютер способен работать с программами, написанными по крайней мере на одном из языков программирования высокого уровня, таких, как Бейсик, Фортран или Кобол. В языках этого типа инструкции могут записываться с весьма высокой степенью абстракции без учета конкретного характера машинных операций.

Да, Basic присутствует.

5. В компьютере обязательно наличие операционной системы, которая упрощает его взаимодействие с человеком в режиме диалога; компьютер немедленно (или по крайней мере быстро) реагирует на запросы или действия оператора.

Оператор может в режиме диалога взаимодействовать с компьютером, используя клавиатуру.

6. Такие машины рассчитаны главным образом на широкую продажу и предназначены в первую очередь для тех, кто раньше не имел дела с компьютерами.

Сложно уже найти людей, кто раньше не имел дела с компьютерами, но скорее да, специальных навыков не нужно.

7. Система достаточно универсальна, что дает возможность выполнять обширный набор программ для различных приложений; она не ориентирована на решение какой-либо одной задачи или обслуживание только определенной категории пользователей.

Да, можно разработать широкий спектр программ.

Чек-лист почти пройден и удалось разработать ПК на базе микроконтроллера - поставленную задачу можно считать решенной.