Несколько месяцев назад завершился мой проект по изготовлению USB-клавиатуры. Среди прочего, я выполнил дизайн электронных схем, спроектировал печатную плат, запрограммировал прошивку, сделал макет в CAD и произвёл сборку устройства. В результате получилась удобная клавиатура, которую я использую ежедневно и ласково называю KeeBee:
![](https://habrastorage.org/r/w780q1/webt/ad/2w/y9/ad2wy9hofgppmzgmk_a7fqobizo.jpeg)
Клавиатура KeeBee в окончательном виде
Несколько целей проекта:
На работе я в основном разрабатываю программное обеспечение для облачных сервисов, где отсутствует много слоёв реального оборудования. Поэтому очень приятно избавиться от некоторых абстракций и опуститься на аппаратный уровень: здесь реальные электронные устройства, которые можно потрогать и использовать.
Мне очень нравятся минималистичные клавиатуры в стиле OLKB Planck и Preonic, которые за счёт ортолинейного расположения клавиш получаются очень компактными. Ещё я сразу знал, что хочу использовать переключатели Cherry MX Brown. Имея виду эти два компонента дизайна, я начал играть с ключевыми макетами в OpenSCAD. Это отличный инструмент с открытым исходным кодом, который работает скорее как язык программирования, чем WYSIWYG-интерфейс для мышки.
Взяв размеры элементов из документации Cherry MX, я сделал макет верхней пластины, затем добавил переключатели и клавиши, чтобы получить представление о том, как будет выглядеть окончательный результат. Верхняя пластина находится над печатной платой клавиатуры и служит хорошим стабилизатором для переключателей.
Дизайн верхней пластины:
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/dd7/e5c/0d0/dd7e5c0d0f409136cd386b09e6f1cb9b.png)
После добавления клавиш:
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/247/053/a3e/247053a3edee7464dcaf24b343dc2be4.png)
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/6bc/8fb/e4b/6bc8fbe4b1620d728838609fecc836f1.png)
В качестве основного микроконтроллера я выбрал STM32F042K6T6. Это около трёх долларов за чип, если брать от одной штуки. У него достаточно контактов для матрицы сканирования 69 клавиш (всего 32 контакта). Он работает на процессоре ARM Cortex M0 и содержит специальную USB-периферию для отправки USB-сигнала, не загружая этой задачей основной процессор. Я купил dev-плату Nucleo для прототипирования с этим чипом, прежде чем интегрировать его в дизайн своей печатной платы. Nucleo очень удобно легла на макетную плату и запиталась по USB.
Я разместил на макетной плате маленькую цепь на четыре клавиши, чтобы протестировать диодный контур, который я изучал. Игнорируя USB-сторону уравнения, на первом шаге требовалось заставить переключатели Cherry надёжно включать и выключать четыре соответствующих светодиода при нажатии кнопок.
![](https://habrastorage.org/r/w780q1/webt/6z/ks/xw/6zksxwfpdqzy4winp9vk3if_kd0.jpeg)
Матрица сканирования — это такая техника, которую нужно использовать, когда у вас больше переключателей, чем контактов на микроконтроллере.
Когда матрица удовлетворительно заработала, пришло время поработать над USB.
Встроенный цикл прошивки по сути такой:
Из main.cc:
Компонент
Повозившись некоторое время, я всё-таки заставил клавиатуру с четырьмя клавишами корректно идентифицировать себя как USB HID (Human Interface Device) и все нажатия правильно передавались на ноутбук:
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/901/712/4b7/9017124b76d06f097826194838cc06e2.png)
Регистрация в качестве USB-вендора и получение официального device id дорого стоит. Если у вас просто любительский проект, то придётся захватить идентификатор какого-нибудь похожего устройства. Я подумал, что “Gear Head” звучит круто, тем более они выпускают клавиатуры, поэтому выбрал их.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/457/e29/628/457e296280138ee96564ca190685c836.png)
Получив более-менее работающую прошивку и рабочий прототип, пришло время составить схему и дизайн печатной платы в KiCAD и сделать реальную печатную плату. Когда я добился, что схема для 4 кнопок работает, осталась относительно простая задача соединить всё вместе:
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/82c/4e9/047/82c4e9047e47a8b5c7f9d71979fb1643.png)
После разработки схему и установки площадок для компонентов нужно произвести макет реальной печатной платы:
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/433/7db/515/4337db515b6a1672924dc9c0e527b20e.png)
KiCAD умеет красиво рендерить будущую плату в 3D:
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/6b8/73a/15f/6b873a15ffb39ac5033f68bfac74722c.png)
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/bb3/caa/3bd/bb3caa3bd098b51889b4db0aeebfd4c0.png)
Есть много отличных учебников по KiCAD. Я начал с отличной видеосерии Getting to Blinkey 4.0 от Криса Гэммела, где он подробно разъясняет все этапы создания схемы светодиодного юлинкера в KiCAD от начала до конца.
Доведя схему и дизайн печатной платы до удовлетворительного уровня, я начал размещать кучу заказов:
День, когда пришла посылка с платой, самый лучший:
![](https://habrastorage.org/r/w780q1/webt/58/zh/tq/58zhtqbwaxb5-dfy2vxzrkg14uu.jpeg)
![](https://habrastorage.org/r/w780q1/webt/0e/il/ln/0eillnhgbfcciaovcjl3hwushyq.jpeg)
JLCPCB очень доступный сервис. Этот дизайн с доставкой DHL из Китая обошёлся менее чем в $30, а весь процесс от загрузки файлов до прихода посылки занял чуть больше недели.
Шурин взял DXF-файлы из OpenSCAD и забросил их в лазерный резак:
![](https://habrastorage.org/r/w780q1/webt/xr/ww/4i/xrww4ips2bdp6lonon3vxcl8dji.jpeg)
Получив все детали, я начал сборку. Первый шаг — сборка компонентов печатной платы: паяльник для больших электронных компонентов и паяльная станция для поверхностного монтажа маленьких компонентов, таких как микроконтроллер STM32.
Общее время сборки платы составило около трёх часов — большую часть заняла пайка 70 диодов и переключателей.
Я добавил хедер для JTAG-отладки, через который подключил JLINK Edu mini для прошивки микроконтроллера с помощью OpenOCD.
Затем пришло время окончательного тестирования и финальной сборки:
![](https://habrastorage.org/r/w780q1/webt/hy/yx/w3/hyyxw3ukirnhihemampdyqi9fh0.jpeg)
![](https://habrastorage.org/r/w780q1/webt/jn/te/zv/jntezvouheop_oqkcylzgvriaj4.jpeg)
![](https://habrastorage.org/r/w780q1/webt/bt/zn/nu/btznnuwjhqasmyfimlchnur8vki.jpeg)
Сын решил, что это отличный поезд для его животных:
![](https://habrastorage.org/r/w780q1/webt/uy/nl/d1/uynld1ae660x2w5um-nta3rvwvy.jpeg)
![](https://habrastorage.org/r/w780q1/webt/zs/ih/4w/zsih4wdyjnnzezye3e06row6zyi.jpeg)
От первоначальной идеи до окончательной сборки проект занял около трёх месяцев. Было исключительно полезно в качестве хобби сделать то, что я до сих пор ежедневно использую на работе.
Все файлы проекта опубликованы на GitHub, в том числе исходники прошивки, схемы печатных плат, список материалов и модели CAD.
Спасибо за чтение и приятных хаков!
![](https://habrastorage.org/webt/ad/2w/y9/ad2wy9hofgppmzgmk_a7fqobizo.jpeg)
Клавиатура KeeBee в окончательном виде
Несколько целей проекта:
- Самостоятельное создание схемы.
- Написание прошивки клавиатуры.
- Узнать, как работает протокол USB.
На работе я в основном разрабатываю программное обеспечение для облачных сервисов, где отсутствует много слоёв реального оборудования. Поэтому очень приятно избавиться от некоторых абстракций и опуститься на аппаратный уровень: здесь реальные электронные устройства, которые можно потрогать и использовать.
Исследование и макет CAD
Мне очень нравятся минималистичные клавиатуры в стиле OLKB Planck и Preonic, которые за счёт ортолинейного расположения клавиш получаются очень компактными. Ещё я сразу знал, что хочу использовать переключатели Cherry MX Brown. Имея виду эти два компонента дизайна, я начал играть с ключевыми макетами в OpenSCAD. Это отличный инструмент с открытым исходным кодом, который работает скорее как язык программирования, чем WYSIWYG-интерфейс для мышки.
Взяв размеры элементов из документации Cherry MX, я сделал макет верхней пластины, затем добавил переключатели и клавиши, чтобы получить представление о том, как будет выглядеть окончательный результат. Верхняя пластина находится над печатной платой клавиатуры и служит хорошим стабилизатором для переключателей.
Дизайн верхней пластины:
![](https://habrastorage.org/getpro/habr/post_images/dd7/e5c/0d0/dd7e5c0d0f409136cd386b09e6f1cb9b.png)
После добавления клавиш:
![](https://habrastorage.org/getpro/habr/post_images/247/053/a3e/247053a3edee7464dcaf24b343dc2be4.png)
![](https://habrastorage.org/getpro/habr/post_images/6bc/8fb/e4b/6bc8fbe4b1620d728838609fecc836f1.png)
Прототипирование платы и проектирование прошивки
В качестве основного микроконтроллера я выбрал STM32F042K6T6. Это около трёх долларов за чип, если брать от одной штуки. У него достаточно контактов для матрицы сканирования 69 клавиш (всего 32 контакта). Он работает на процессоре ARM Cortex M0 и содержит специальную USB-периферию для отправки USB-сигнала, не загружая этой задачей основной процессор. Я купил dev-плату Nucleo для прототипирования с этим чипом, прежде чем интегрировать его в дизайн своей печатной платы. Nucleo очень удобно легла на макетную плату и запиталась по USB.
Я разместил на макетной плате маленькую цепь на четыре клавиши, чтобы протестировать диодный контур, который я изучал. Игнорируя USB-сторону уравнения, на первом шаге требовалось заставить переключатели Cherry надёжно включать и выключать четыре соответствующих светодиода при нажатии кнопок.
![](https://habrastorage.org/webt/6z/ks/xw/6zksxwfpdqzy4winp9vk3if_kd0.jpeg)
Матрица сканирования — это такая техника, которую нужно использовать, когда у вас больше переключателей, чем контактов на микроконтроллере.
Когда матрица удовлетворительно заработала, пришло время поработать над USB.
Встроенный цикл прошивки по сути такой:
- Просканировать все клавиши в матрице.
- Сопоставить расположение кнопок с соответствующими символами в выбранной раскладке (QWERTY, Dvorak и т. д.).
- Взять результат сопоставления, сгенерировать пакеты USB HID Report и отправить на периферийное устройство USB.
- Включить светодиод на клавиатуре, если клавиша нажата, выключить — если нет.
Из main.cc:
static void scan_and_update() {
scan_matrix.Scan(key_scans, row_count, column_count);
keyboard.SendReport(
key_pipeline.MapKeyScans(key_scans, key_count));
update_key_press_status();
}
int main() {
Init();
status_led.SetOk(true);
while (true) {
scan_and_update();
}
}
Компонент
keyboard.SendReport
фактически передаёт пакеты USB-хосту. Я упорно пытался заставить USB правильно работать. В этом протоколе много нетривиальных слоёв, которые требуют точного тайминга и правильной идентификации устройства. В итоге пришлось запустить Wireshark, чтобы прослушать все USB-пакеты, поступающие на мой ноутбук Linux и выяснить, где что потерялось. Поиск в интернете практически ничего не дал, на большинство вопросов отвечают примерно так: «Вероятно, ваше USB-устройство сломалось, нужно купить новое». Если вы на самом деле пытаетесь сконструировать USB-устройство, такие ответы не очень полезны. Мне оставалось только погрузиться в объёмные спецификации USB с большим количеством незнакомой терминологии.Повозившись некоторое время, я всё-таки заставил клавиатуру с четырьмя клавишами корректно идентифицировать себя как USB HID (Human Interface Device) и все нажатия правильно передавались на ноутбук:
![](https://habrastorage.org/getpro/habr/post_images/901/712/4b7/9017124b76d06f097826194838cc06e2.png)
Регистрация в качестве USB-вендора и получение официального device id дорого стоит. Если у вас просто любительский проект, то придётся захватить идентификатор какого-нибудь похожего устройства. Я подумал, что “Gear Head” звучит круто, тем более они выпускают клавиатуры, поэтому выбрал их.
![](https://habrastorage.org/getpro/habr/post_images/457/e29/628/457e296280138ee96564ca190685c836.png)
Схема и печатная плата
Получив более-менее работающую прошивку и рабочий прототип, пришло время составить схему и дизайн печатной платы в KiCAD и сделать реальную печатную плату. Когда я добился, что схема для 4 кнопок работает, осталась относительно простая задача соединить всё вместе:
![](https://habrastorage.org/getpro/habr/post_images/82c/4e9/047/82c4e9047e47a8b5c7f9d71979fb1643.png)
После разработки схему и установки площадок для компонентов нужно произвести макет реальной печатной платы:
![](https://habrastorage.org/getpro/habr/post_images/433/7db/515/4337db515b6a1672924dc9c0e527b20e.png)
KiCAD умеет красиво рендерить будущую плату в 3D:
![](https://habrastorage.org/getpro/habr/post_images/6b8/73a/15f/6b873a15ffb39ac5033f68bfac74722c.png)
![](https://habrastorage.org/getpro/habr/post_images/bb3/caa/3bd/bb3caa3bd098b51889b4db0aeebfd4c0.png)
Есть много отличных учебников по KiCAD. Я начал с отличной видеосерии Getting to Blinkey 4.0 от Криса Гэммела, где он подробно разъясняет все этапы создания схемы светодиодного юлинкера в KiCAD от начала до конца.
Заказ печатной платы и компонентов
Доведя схему и дизайн печатной платы до удовлетворительного уровня, я начал размещать кучу заказов:
- Все компоненты из списка материалов: переключатели, светодиоды, диоды, микроконтроллеры и т. д. Я обычно заказываю такие штуки на DigiKey.
- Сама печатная плата. Довольно много сервисов готовы недорого изготовить вам прототип. У меня отличный опыт работы с OshPark и JLCPCB. Для этого проекта я выбрал JLCPCB из-за цены на такой размер, а ещё потому что они разрешили выбрать синее покрытие.
- Все остальные детали: крышки и прочее. Для этого проекта мой шурин помог лазером вырезать верхнюю и нижнюю клавиатурные пластины из 1/4” акриловых листов. Для остальных частей можно использовать онлайновые сервисы лазерной резки и 3D-печати, если нет доступа к оборудованию.
День, когда пришла посылка с платой, самый лучший:
![](https://habrastorage.org/webt/58/zh/tq/58zhtqbwaxb5-dfy2vxzrkg14uu.jpeg)
![](https://habrastorage.org/webt/0e/il/ln/0eillnhgbfcciaovcjl3hwushyq.jpeg)
JLCPCB очень доступный сервис. Этот дизайн с доставкой DHL из Китая обошёлся менее чем в $30, а весь процесс от загрузки файлов до прихода посылки занял чуть больше недели.
Шурин взял DXF-файлы из OpenSCAD и забросил их в лазерный резак:
![](https://habrastorage.org/webt/xr/ww/4i/xrww4ips2bdp6lonon3vxcl8dji.jpeg)
Окончательная сборка
Получив все детали, я начал сборку. Первый шаг — сборка компонентов печатной платы: паяльник для больших электронных компонентов и паяльная станция для поверхностного монтажа маленьких компонентов, таких как микроконтроллер STM32.
Общее время сборки платы составило около трёх часов — большую часть заняла пайка 70 диодов и переключателей.
Я добавил хедер для JTAG-отладки, через который подключил JLINK Edu mini для прошивки микроконтроллера с помощью OpenOCD.
Затем пришло время окончательного тестирования и финальной сборки:
![](https://habrastorage.org/webt/hy/yx/w3/hyyxw3ukirnhihemampdyqi9fh0.jpeg)
![](https://habrastorage.org/webt/jn/te/zv/jntezvouheop_oqkcylzgvriaj4.jpeg)
![](https://habrastorage.org/webt/bt/zn/nu/btznnuwjhqasmyfimlchnur8vki.jpeg)
Сын решил, что это отличный поезд для его животных:
![](https://habrastorage.org/webt/uy/nl/d1/uynld1ae660x2w5um-nta3rvwvy.jpeg)
![](https://habrastorage.org/webt/zs/ih/4w/zsih4wdyjnnzezye3e06row6zyi.jpeg)
Итоги
От первоначальной идеи до окончательной сборки проект занял около трёх месяцев. Было исключительно полезно в качестве хобби сделать то, что я до сих пор ежедневно использую на работе.
Все файлы проекта опубликованы на GitHub, в том числе исходники прошивки, схемы печатных плат, список материалов и модели CAD.
Спасибо за чтение и приятных хаков!