В 2005 году Arduino произвела фурор в мире DIY. Раньше разработчик гаджета должен был разбираться в программировании, аппаратной архитектуре и схемотехнике — даже чтобы сделать простое устройство. С появлением Arduino мир электроники стал доступен новичкам, а время разработки сократилось в разы.
Iskra JS — следующий шаг в упрощении разработки!
Разработка стала ещё быстрее, код понятнее, освоение проще. Можно сосредоточиться на сути проекта, а не на архитектурных особенностях микроконтроллера, борьбе за память и программировании на C++.
Сейчас не встретить веб-приложений на C++: балом правят PHP, Python, Ruby и JavaScript. Они медленнее C++, но гораздо выразительнее и проще: скорость разработки растёт, а освоить их легче.
Так и Iskra JS: если важны результат и комфортная среда программирования, а оптимизация не является самоцелью — плата Iskra JS станет логичным продолжением разработки устройств на платформе Arduino.
Iskra JS сделана в форм-факторе Arduino R3 — с ней можно использовать те же платы расширения, модули и корпуса. Отличие в микроконтроллере: ARM Cortex-M4 с 1 МБ flash-памяти способен разместить как JavaScript-ядро, так и саму программу.
Ядро прошивается в микроконтроллер при производстве, а программы загружаются через USB-порт. По USB можно и обновить ядро, а через SWD-разъём — полностью перепрошить устройство.
JavaScript и C++ — разные языки, в которых сходства меньше, чем различий. Но после программирования Arduino освоение JavaScript не вызовет проблем.
Как отреагирует компилятор на такой код C++?
#include <Servo.h> Servo myServo; myServo.attach(3); // Err myServo.write(120); // Yargh!
Естественно, ошибкой. attach
и write
вызваны вне рамок setup
или loop
, а код не может исполняться в глобальной области видимости.
В JavaScript код можно и нужно писать на первом уровне:
var myServo = require('@amperka/servo').connect(P3); myServo.write(120);
Этот код выставит сервопривод на 3-м пине в положение на 120°.
В C++ каждая переменная должна обладать явно прописанным типом: int
, bool
, float
, LiquidCrystal
и т. д:
int x = 0; bool b = true; float f = 3.1415926; FantasyShield myShield = FantasyShield(1, 2, 3, 4, 5, 6); void setup() { x = myLCD; // ошибка: x и myShield имеют разные типы }
В JavaScript всё проще: тип переменной устанавливается автоматически, а в ходе выполнения программы переменная даже может изменять свой тип.
var x = 0; var b = true; var f = 3.1415926; var myShield = FantasyShield(1, 2, 3, 4, 5, 6); x = myShield; // Это нормально. x стала объектом-FantasyShield
Функции pinMode
, digitalRead
, digitalWrite
, analogRead
доступны и на Iskra JS. Не нужно учить ничего нового:
Arduino | Iskra JS | |
---|---|---|
Считать цифровой пин | digitalRead(3) | digitalRead(P3) |
Считать аналоговый пин | analogRead(A3) | analogRead(A3) |
Записать в цифровой пин | digitalWrite(3, HIGH) | digitalWrite(P3, HIGH) |
Подать ШИМ-сигнал 50% | analogWrite(3, 127) | analogWrite(P3, 0.5) |
Установить режим пина | pinMode(3, OUTPUT) | pinMode(P3, 'output') |
Не нужно устанавливать режим пина (pinMode
): при обращении к нему ядро выставит режим, основываясь на вызванной функции.
Философия Iskra JS заключается в отказе от использования низкоуровневых функций. Для популярной периферии уже написаны модули, которые позволяют оперировать терминами устройства, а не электрических сигналов.
Так выглядит код простой кнопки:
var myButton = require('@amperka/button').connect(P4); myButton.on('click', function() { console.log("Hey! You've clicked on me!"); });
В C++ строка представляется в виде массива байт-кодов символов со специальным символом конца строки (\x00
). Операции над строками всегда выглядят запутанными:
char str[40]; // нужно задумываться о длинах буферов char val[10]; // перевод числа в строку — отдельная забота itoa(analogRead(A0), val, 10); strcpy(str, "Value: "); // копирование строки — особая функция strcat(str, val); // склеивание тоже if (strcmp(str, "Value: 0") == 0) { // сравнение, как и всё, тоже отдельная функция }
Строки в JavaScript — полноправный тип данных, и оперировать ими можно так же, как и числами.
var str = "Value: " + analogRead(A0); if (str === "Value: 0") { // ... }
Массивы в C++ — просто блоки памяти заданного на этапе компиляции размера. Элемент нельзя добавить или убрать «на лету». Для C++ есть библиотека STL, но она не доступна разработчикам Arduino: работа с массивами выглядит громоздко и неуклюже.
Массив JavaScript — полноправный тип данных (Array
) со своими методами и свойствами. Элементы массива можно добавлять по мере необходимости:
var values = []; while (digitalRead(P4)) { // Метод push добавляет новый элемент // в конец массива values.push(analogRead(A0)); } var sum = 0; // Свойство length содержит текущую длину массива for (var i = 0; i < values.length; ++i) { // Обращение к элементам по индексу происходит // привычным образом sum += values[i]; } var average = sum / values.length;
В JavaScript есть механизм событий, который помогает упростить некоторые задачи. Например, чтобы при нажатии кнопки светодиод переключался в противоположенное состояние, используем код:
// Объект-кнопка умеет генерировать событие "click". // С помощью стандартного метода "on" мы можем подписаться // на интересующее событие, чтобы сделать что-то полезное // при его возникновении myButton.on('click', function() { myLed.toggle(); });
В библиотеках — сила.
Как подключить библиотеку на Arduino? Нужно скопировать исходные файлы в правильную директорию и подключить ее в скетче директивой #include
. После этого становятся доступны классы и функции библиотеки. Однако если в двух библиотеках объявлены символы с одинаковыми именами — возникнет проблема; если обе используют один и тот же таймер — проблема. Если библиотека использует возможности другой библиотеки, забота о зависимостях — отдельная проблема.
Чтобы сделать собственную библиотеку, придется разделить код на файлы *.h
и *.cpp
. Это разделение — историческое следствие недостатков языка C.
В JavaScript и Espruino библиотека подключается встроенной функцией require
с именем библиотеки в качестве параметра.
// Переменная Servo будет содержать объект-библиотеку var Servo = require('@amperka/servo'); Servo.defaultOptions.valueMin = -90; Servo.defaultOptions.valueMax = +90; var servo1 = Servo.connect(P13); var servo2 = Servo.connect(P12); var servo3 = Servo.connect(P11);
Механизм require
ищет код библиотеки на локальном диске, и если он не найден, ищет его в интернете: в репозитории, на GitHub или в каталоге npmjs.org.
Можно забыть об установке библиотек вручную.
В скетчах на Arduino встречаются конструкции вида:
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
Что означают эти параметры? Это номера управляющих пинов, но без документации не разобраться, на каком месте какой.
В JavaScript аналогичная запись выглядит так:
var lcd = LiquidCrystal.connect({ rsPin: P12, rwPin: P11, enablePin: P10, d4Pin: P5, d5Pin: P4, d6Pin: P3, d7Pin: P2 });
Код длиннее, но и читабельность на порядок выше. Помните: код пишется один раз, а читается сто.
В Arduino часто используются функция delay
— она определяет период исполнения кода или позволяет дождаться определённого события. У такого подхода есть существенный недостаток: во время задержки микроконтроллер крутит пустой цикл и не даёт выполняться другому коду. Для микроконтроллера delay
— тяжёлая работа, от которой он не может оторваться.
На Iskra JS нет аналогов delay
. Чтобы управлять временем исполнения кода, существуют функции setTimeout
, setInterval
, digitalPulse
, Pin.writeAtTime
.
Например, чтобы заставить светодиод переключаться раз в секунду, можно воспользоваться setInterval
:
// setInterval будет вызывать функцию каждые 1000 мс. setInterval(function() { led.toggle(); }, 1000);
Пока микроконтроллер не занят исполнением одной функции, он может выполнять основной код или код других периодических функций. Если задач нет, микроконтроллер перейдёт в режим сна и проснётся, когда появится работа. Это позволяет экономить энергию.
У Arduino есть среда программирования Arduino IDE. У Iskra JS — Espruino IDE, установка и работа в которой проще.
Espruino IDE — это приложение на платформе Google Chrome, которое устанавливается буквально в один клик.
Главное окно среды разделено на две части: с одной стороны — аналог Serial Monitor, с другой — поле для кода программы. Программы загружаются в плату нажатием одной кнопки.
Понадобится железо: можно взять Iskra JS или набор Йодо из платы и модулей для экспериментов. К ним подойдут всё те же платы расширения и модули Arduino.
Знания о JavaScript, доступных функциях и объектах можно найти на Wiki. Особого внимания заслуживает документация библиотек и встроенных функций. Они станут основой для новых программ.