Когда JavaScript встречает железо: новое слово в embedded
Когда мы говорим "embedded разработка", в голове обычно всплывают ассоциации с Си, голым металлом, ассемблерными вставками и бесконечными дебаггинг-сессиями с осциллографом. А теперь представьте, что вы пишете прошивку для умного датчика температуры, используя TypeScript. Звучит как фантастика? А зря.
Мир встраиваемых систем переживает тихую революцию. Современные микроконтроллеры обзавелись достаточным объемом памяти и тактовой частотой, чтобы выполнять скриптовые языки. А TypeScript с его статической типизацией и богатой экосистемой становится идеальным кандидатом для embedded-проектов, где важна надежность и читаемость кода.
В этой статье мы разберем, как TypeScript проникает в мир embedded, какие инструменты для этого нужны, и напишем реальный код для управления светодиодом через GPIO. Поехали!
Почему TypeScript, а не C или Python?
Классический выбор для embedded — это C. Он быстр, предсказуем и жрет мало памяти. Но у него есть темная сторона: управление памятью вручную, отсутствие нормальной типизации на уровне компилятора и "ад" с макросами. Python (MicroPython) проще, но медленный и динамический — вы узнаете о баге только в рантайме, когда устройство зависнет где-нибудь на полке.
TypeScript предлагает золотую середину:
- Строгая типизация — компилятор ловит ошибки на этапе сборки. Никаких случайных
stringвместоnumberв регистрах микроконтроллера. - Современный синтаксис — async/await, дженерики, интерфейсы. Код становится самодокументируемым.
- Экосистема npm — тысячи библиотек, которые можно адаптировать под железо.
- Безопасность типов — вы точно знаете, что передаете в функцию
setPin(17, HIGH), а неsetPin("17", true).
Конечно, TypeScript не заменит C для высоконагруженных систем реального времени. Но для IoT-датчиков, умных лампочек, метеостанций и прототипов — это идеальный выбор.
Инструментарий: что нужно для старта
Чтобы писать на TypeScript под железо, нам понадобится среда выполнения, которая умеет интерпретировать JavaScript на микроконтроллере. Самые популярные варианты:
- JerryScript — легковесный JS-движок от Samsung. Занимает ~1 МБ Flash.
- Espruino — специализированная прошивка для STM32 и ESP32. Поддерживает TypeScript через транспиляцию.
- Moddable SDK — мощный фреймворк для IoT с поддержкой TypeScript "из коробки".
Мы будем использовать Espruino на плате ESP32 (или Raspberry Pi Pico с прошивкой Espruino). Это самый простой способ попробовать TypeScript в embedded без паяльника и даташитов.
Установка и настройка
- Скачайте прошивку Espruino для вашей платы с официального сайта.
- Прошейте плату через USB (используйте утилиту
esptoolдля ESP32). - Установите Node.js и npm, если еще не установлены.
- Установите
espruino-cliглобально:npm install -g espruino-cli. - Создайте проект:
mkdir my-embedded-ts && cd my-embedded-ts && npm init -y. - Установите TypeScript:
npm install --save-dev typescript @types/espruino.
Теперь у вас есть TypeScript-проект, который знает о типах Espruino! Создайте файл tsconfig.json:
{
"compilerOptions": {
"target": "ES2015",
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src",
"types": ["espruino"]
},
"include": ["src/**/*"]
}
Пишем первый код: мигаем светодиодом
Классика embedded — "Hello World" в виде мигающего светодиода. Создадим файл src/blink.ts:
import { Pin, setInterval } from 'espruino';
// Интерфейс для конфигурации пина
interface LedConfig {
pin: number;
interval: number;
}
// Функция инициализации светодиода
function setupLed(config: LedConfig): Pin {
const led = new Pin(config.pin);
led.mode('output');
return led;
}
// Функция для переключения состояния
function toggleLed(led: Pin): void {
const currentState = led.read();
led.write(currentState === 0 ? 1 : 0);
}
// Главная функция приложения
function main(): void {
const ledConfig: LedConfig = {
pin: 2, // GPIO2 на ESP32 — обычно встроенный LED
interval: 500 // мигаем каждые 500 мс
};
const led = setupLed(ledConfig);
console.log('LED initialized on pin', ledConfig.pin);
// Устанавливаем интервал
setInterval(() => {
toggleLed(led);
}, ledConfig.interval);
}
// Запускаем
main();
Теперь скомпилируем TypeScript в JavaScript: npx tsc. В папке dist появится blink.js. Загрузим его на плату:
espruino-cli --board ESP32 --port /dev/ttyUSB0 dist/blink.js
Светодиод на GPIO2 начнет мигать. Поздравляю, вы только что написали embedded-программу на TypeScript!
Работа с датчиками: I2C и TypeScript
Мигать светодиодом — весело, но давайте подключим реальный датчик, например, BME280 (температура, влажность, давление). Работаем через шину I2C. TypeScript с его типизацией идеально подходит для работы с регистрами.
Подключение датчика
Создадим файл src/bme280.ts:
import { I2C, Pin } from 'espruino';
// Типы для данных с датчика
interface SensorData {
temperature: number;
humidity: number;
pressure: number;
}
// Адреса регистров BME280
const REGISTERS = {
CHIP_ID: 0xD0,
RESET: 0xE0,
CTRL_HUM: 0xF2,
CTRL_MEAS: 0xF4,
CONFIG: 0xF5,
PRESS_MSB: 0xF7,
TEMP_MSB: 0x