美文网首页玩转Arduino树莓派玩转树莓派
使用 JavaScript 对 Arduino 编程

使用 JavaScript 对 Arduino 编程

作者: rollingstarky | 来源:发表于2018-12-03 21:15 被阅读11次

一、向 Arduino 刷入 Firmata 固件

Firmata 是一种开放的类似于 MIDI 的协议。它可以将微控制器(microcontroller)变成“客户端”,通过串口通信直接被“主机”电脑访问和控制。
通过 Firmata 协议,可以在主机上使用 Ruby、Python、JavaScript 等多种语言与刷入了 Firmata 固件的 arduino 板“交流”。

首先安装 firmata-party 工具:
$ npm install -g firmata-party
安装成功后通过 USB 线将 Arduino 板连接至电脑,运行以下命令:

$  firmata-party uno --debug
found uno on port /dev/tty.usbserial-14110
connected
reset complete.
flashing, please wait...
flash complete.

刷写完毕后,可以通过 Firmata Test Program 进行简单的测试。

Firmata Test

二、使用 JavaScript 编程

Blink LED

可以使用如下命令开始一个新的项目:

$ mkdir test && cd test
$ npm init -y
$ npm install --save firmata

编辑源代码文件(blink_led.js)用来控制 LED 闪烁:

// 加载依赖库
var Board = require('firmata');

// 连接初始化
Board.requestPort(function(error, port) {
    if (error) {
        console.log(error);
        return;
    }

    var board = new Board(port.comName);

    // 等待连接
    board.on("ready",function() {
        console.log("Ready!");
        var ledOn = true;

        // 设置 pin 13 为输出引脚
        board.pinMode(13, board.MODES.OUTPUT);

        // 使 LED 闪烁
        setInterval(function() {
            if (ledOn) {
                console.log('ON');
                board.digitalWrite(13, board.HIGH);
            } else {
                console.log('OFF');
                board.digitalWrite(13, board.LOW);
            }
            ledOn = !ledOn;
        }, 1000);
    });
});

运行效果如下:

$ node blink_led2.js
Ready!
ON
OFF
ON
...

代码执行后 arduino 板子上 13 号引脚上接的 LED 开始以 1 秒的间隔闪烁,同时电脑的终端界面不停地输出 ON 和 OFF 表示当前 LED 的开关状态。

Analog Input

Arduino 板子上的 A0 - A5 引脚可以读取模拟输入信号。
示例代码如下:

// 加载依赖库
var Board = require('firmata');

// 引脚定义
const LED = 5;
const POT = 0;

// 初始化变量
var ledOn = 0;
var delay = 0;

// map 函数。将初始的数值范围转变成需要的数值范围
function map(x, in_min, in_max, out_min, out_max)
{
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// 连接初始化
Board.requestPort(function(error, port) {
    if (error) {
        console.log(error);
        return;
    }

    var board = new Board(port.comName);

    // 等待连接
    board.on("ready", function() {

        // 控制 LED 闪烁的 blink() 函数
        function blink() {
            board.digitalWrite(LED, ledOn);
            ledOn = !ledOn;
            setTimeout(blink, delay);
        }

        // 读取并更新可变电阻提供的模拟输入
        board.analogRead(0, function(d) {
            delay = map(d, 0, 1023, 400, 1600);
        });

        blink();
    });
});

线路连接图如下:


线路连接图

即通过 Arduino 板 A0 引脚可以读取模拟输入的功能(连接可变电阻的中间引脚),获取可变电阻的取值(0-1023)。
再通过程序中的 map 函数将 0-1023 的取值转变成 400-1600,作为接在 5 号引脚上 LED 的闪烁频率。

程序运行后,调节可变电阻的旋钮,LED 即以不同的时间间隔(0.4s - 1.6s)闪烁。

PWM (Pulse-Width Modulation)

PWM 即脉宽调制,其机制为:通过 MCU 内部的计时器设置引脚的状态,使该引脚在一个周期内的某段时间保持 HIGH 状态,在该周期内的其余时间保持 LOW 状态。
平均下来看,该引脚的输出电压即介于最低和最高输出电压之间(即 0~5 V 之间)。所以一般可以近似地作为模拟电压输出。

// 加载依赖库
var Board = require('firmata');

// 变量定义
const LED = 5;
var brightness = 0;
var fadeAmount = 5;

// 连接初始化
Board.requestPort(function(error, port) {
    if (error) {
        console.log(error);
        return;
    }

    var board = new Board(port.comName);

    // 等待连接
    board.on("ready", function() {

        // 设置 LED 引脚为 PWM 模式
        board.pinMode(LED, board.MODES.PWM);

        // 每隔 30 ms 提高或降低 LED 亮度,循环执行
        function fadeLed() {
            brightness += fadeAmount;
            if (brightness ==0 || brightness == 255) {
                fadeAmount = -fadeAmount;
            }
            board.analogWrite(LED, brightness);
            setTimeout(fadeLed, 30);
        }
        fadeLed();
    });
});

该程序执行后,5 号引脚上的 LED 灯先是缓慢变亮,达到最亮以后再缓慢变暗。依照此规则循环。

附录:JavaScript 的串口通信

即使 Arduino 板子未刷入 Firmata 固件,运行的是普通的程序。
也可以利用 Node.js 的 serialport 库和串口通信完成 Arduino 与主机的对话。

首先初始化项目并安装依赖库:

$ mkdir test2 && cd test2
$ npm init -y
$ npm install --save-dev serialport
扫描串口设备
$ cat list_ports.js
var serialPort = require("serialport");
serialPort.list(function (error, ports) {
    ports.forEach(function(port) {
        console.log(port.comName);
    });
});
$ node list_ports.js
/dev/tty.Bluetooth-Incoming-Port
/dev/tty.usbserial-14110
从 Arduino 收取数据

首先通过 Arduino IDE 刷入以下 counter.ino 文件,作为发送端程序:

void setup() {
  Serial.begin(9600);
}

int i=0;
void loop() {
  Serial.println(i++);
  delay(1000);
}

上述代码以 1000 ms 的间隔生成从 0 开始不断递增的数字并发送至串口。

电脑端的接收程序 read_port.js 代码如下:

const SerialPort = require('serialport')
const Readline = require('@serialport/parser-readline')
const port = new SerialPort('/dev/cu.usbserial-14110')

const parser = port.pipe(new Readline({ delimiter: '\n' }))
parser.on('data', console.log)
运行效果如下: read_port

发送端不断生成新的数字并发送至串口,接收端通过串口接收该数字后将其打印到终端输出。

向 Arduino 发送数据

首先通过 Arduino IDE 刷入以下 receiver.ino 文件,作为接收端程序:

void setup() {
  Serial.begin(9600);
}

void loop() {
  int incoming = 0;
  if (Serial.available() > 0) {
    incoming = Serial.parseInt();

    if (Serial.read() == '\n') {
      Serial.println(incoming);
    }
  }
}

发送端的 write_port.js 程序代码如下:

var SerialPort = require('serialport');
var Stream = require('stream');
var modem = 'cu.usbserial-14110';
var ws = new Stream();
ws.writable = true;

ws.write = function(data) {
    serialPort.write(data);
};

ws.end = function(buf) {
    console.log('bye');
}

var serialPort = new SerialPort('/dev/' + modem);

process.stdin.pipe(ws);
运行效果如下: write_port

电脑端发送程序运行后($ node write_port.js),打开 Arduino IDE 的 Serial Monitor
在命令行输入任何一个数字并按回车进行确认,Arduino 板子接收到该数字后,又将其打印到串口输出(即 Serial Monitor 中显示的内容)

参考资料

Node.js for Embedded Systems: Using Web Technologies to Build Connected Devices 1st Edition
Node SerialPort

相关文章

网友评论

    本文标题:使用 JavaScript 对 Arduino 编程

    本文链接:https://www.haomeiwen.com/subject/spfqfqtx.html