Arduino与JavaScript开发实例-WS2812控制

WS2812控制

文章目录

1、WS2812简单介绍

WS2812是一款智能控制LED光源,控制电路和RGB芯片集成在一个5050个元件的封装中。 它内部包括智能数字端口数据锁存器和信号整形放大驱动电路。 还包括一个精密内部振荡器和一个12V电压可编程恒流控制部分,有效保证像素点光色高度一致。

数据传输协议采用单 NZR 通信方式。 像素上电复位后,DIN 口接收控制器的数据,第一个像素采集初始 24 位数据,然后发送到内部数据锁存器,其他数据通过内部信号整形放大电路整形后送到下一个级联
像素通过 DO 端口。 每个像素传输后,信号减少24bit。 像素采用自动整形传输技术,使得像素级联数不受信号传输的限制,只取决于信号传输的速度。

LED具有驱动电压低、环保节能、亮度高、散射角大、一致性好、功耗低、寿命长等优点。 集成在LED上面的控制芯片使电路更加简单,体积小,安装方便。

2、Firmata协议简单介绍

Firmata 是一种协议,用于通过计算机(或智能手机/平板电脑等)上的软件与微控制器进行通信。该协议可以在任何微控制器架构上的固件以及任何计算机软件包上的软件中实现(参见下面的客户端库列表)。

Firmata 基于 midi 消息格式,其中命令字节为 8 位,数据字节为 7 位。例如,midi 通道压力(命令:0xD0)消息是 2 个字节长,在 Firmata 中,命令 0xD0 用于启用数字端口(8 个引脚的集合)的报告。 midi 和 Firmata 版本都是 2 个字节长,但含义明显不同。在 Firmata 中,消息中的字节数必须符合相应的 midi 消息。然而,Midi System Exclusive (Sysex) 消息可以是任意长度,因此在整个 Firmata 协议中使用最为显着。

3、Johnny-Five简单介绍

Johnny-Five 是 JavaScript 机器人和物联网平台。 Johnny-Five 最初由 Rick Waldron 于 2012 年创建,由充满热情的软件开发人员和硬件工程师组成的社区维护。 超过 75 位开发人员为构建强大、可扩展和可组合的生态系统做出了贡献。

Johnny-Five 已经使用各种 Arduino 兼容板进行了测试。 对于非基于 Arduino 的项目,可以使用特定于平台的 IO 插件。 IO 插件允许 Johnny-Five 代码以平台使用的任何语言与任何硬件进行通信!

4、Electron简单介绍

Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 ChromiumNode.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。

本次实例将实现在Electron基础上,通过Johnny-Five和Firmata协议与Arduino开发板通信,驱动控制WS2812 LED灯带。

5、硬件准备

  • Arduino Mega2560开发板一块
  • WS2812灯带一条
  • 杜邦线若干
  • 数据线一条

将WS2812的DIN引用连接到Arduino Mega2560的引脚6,WS2812的GND和VCC引脚分别连接到Arduino Mega2560的GND和VCC引脚。

6、软件准备

  • VS Code IDE
  • Arduino IDE
  • NodeJs(本次使用的版本为v16.13.0)
  • Visual Studio 2019
  • Electron(本次使用版本为v17.0.1)

前面的文章已经对Arduino与JavaScript开发环境已经做了详细描述,请参考:Arduino与JavaScript开发实例-开发环境搭建

由于Firmata固件内置不支持WS2812驱动,因此需要为Arduino开发板烧写支持驱动WS2812的Firmata固件。具体方法如下:

  • 1)安装nodebots-interchange:
1
2
npm -g install nodebots-interchange

  • 2)连接Arduino开发板到电脑,烧写固件:
1
2
interchange install git+https://github.com/ajfisher/node-pixel -a mega --firmata

该命令将从网络下载支持Arduino Mega2560开发板的固件并下载到开发板上。另外,如果需要显示指定开发板的串口端口,则在命令行中执行如下命令:

1
2
interchange install git+https://github.com/ajfisher/node-pixel -a mega -p COM3 --firmata

本次实例将使用到node-pixel支持库,由于该库依赖使用Firmatajohnny-five库版本过低,导致firmatajohnny-five库依赖的serialport库无法本地编译通过,因此安装node-pixel库的步骤如下:

+ 1)直接下载node-pixel库源码:https://github.com/ajfisher/node-pixel
+ 2)由于本次实例使用node-pixel库与johnny-five库,因此只需要更改node-pixel库的`package.json`文件即可。即将:

 
1
2
3
4
5
"peerDependencies": {
"firmata": "^0.19.1",
"johnny-five": "^2.0.0"
},

更改为:
1
2
3
4
5
"peerDependencies": {
"firmata": "^2.3.0",
"johnny-five": "^2.1.0"
},

然后,将node-pixel库复制到`node_modules`目录。注意不能在命令行中运行`npm install node-pixel`,否则会导致安装失败。

7、代码实现

Electron的package.json文件内容,请参考前面文章,在这里不重复介绍了。

7.1 Electron应用程序页面(index.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LED-RGB控制</title>
<script>window.$ = window.jQuery = require('jquery');</script>
<script src="../js/bootstrap-5.1.3-dist/js/bootstrap.min.js"></script>
<script src="../js/bootstrap-slider/dist/bootstrap-slider.min.js"></script>
<script>
window.echarts = require('echarts');
</script>
<link href="../js/bootstrap-5.1.3-dist/css/bootstrap.min.css" rel="stylesheet"></link>
<link href="../js/bootstrap-slider/dist/css/bootstrap-slider.min.css" rel="stylesheet"></link>
</head>
<body>
<div class="row">
<div class="col-md">
<div class="panel panel-default">
<div class="panel-heading">颜色选择</div>
<div class="panel-body">
<input type="color" class="form-control form-control-color" id="led-rgb-color-picker"
value="#563d7c">
</div>
<div class="panel-footer" id="led-rgb-value-title">当前颜色值:#563d7c</div>
</div>
</div>
<div class="col-md">
<div class="panel panel-default">
<div class="panel-heading">RGB单通道颜色控制</div>
<div class="panel-body">
<div class="row">
<label class="form-check-label" for="led-r-intensity-slider-d">R:</label>
<input id="led-r-intensity-slider" data-slider-id='led-r-intensity-slider-d' type="text" data-slider-min="0"
data-slider-max="255"
data-slider-step="1" data-slider-value="255"/>
</div>
<div class="row">
<label class="form-check-label" for="led-g-intensity-slider-d">G:</label>
<input id="led-g-intensity-slider" data-slider-id='led-g-intensity-slider-d' type="text" data-slider-min="0"
data-slider-max="255"
data-slider-step="1" data-slider-value="255"/>
</div>
<div class="row">
<label class="form-check-label" for="led-b-intensity-slider-d">B:</label>
<input id="led-b-intensity-slider" data-slider-id='led-b-intensity-slider-d' type="text" data-slider-min="0"
data-slider-max="255"
data-slider-step="1" data-slider-value="255"/>
</div>
</div>
<div class="panel-footer" id="led-rgb-intensity-title"></div>
</div>
</div>
</div>
<script src="../js/renderer/led\_ws2812\_renderer.js"></script>
</body>

页面效果如下:

在这里插入图片描述

7.2 页面逻辑控制代码(led_ws2812_renderer.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
const { ipcRenderer } = require('electron')

$('#led-rgb-color-picker').on('change',() => {
let hexColor = $('#led-rgb-color-picker').val()
console.log(hexColor)
let rgbColor = hexToRGB(hexColor)
ipcRenderer.send('led-ws2812',{color:rgbColor})
$('#led-rgb-value-title').html('当前颜色值:' + hexColor)
})

// WS2812
var ledColorRedIntensitySlider = $('#led-r-intensity-slider').bootstrapSlider().on('change',() => {
let red = $('#led-r-intensity-slider').bootstrapSlider('getValue')
let green = $('#led-g-intensity-slider').bootstrapSlider('getValue')
let blue = $('#led-b-intensity-slider').bootstrapSlider('getValue')
let rgbColor = {
red:red,
green:green,
blue:blue
}
ipcRenderer.send('led-ws2812',{color:rgbColor})
})

var ledColorGreenIntensitySlider = $('#led-g-intensity-slider').bootstrapSlider().on('change',() => {

let red = $('#led-r-intensity-slider').bootstrapSlider('getValue')
let green = $('#led-g-intensity-slider').bootstrapSlider('getValue')
let blue = $('#led-b-intensity-slider').bootstrapSlider('getValue')
let rgbColor = {
red:red,
green:green,
blue:blue
}
ipcRenderer.send('led-ws2812',{color:rgbColor})
})

var ledColorBlueIntensitySlider = $('#led-b-intensity-slider').bootstrapSlider().on('change',() => {

let red = $('#led-r-intensity-slider').bootstrapSlider('getValue')
let green = $('#led-g-intensity-slider').bootstrapSlider('getValue')
let blue = $('#led-b-intensity-slider').bootstrapSlider('getValue')
let rgbColor = {
red:red,
green:green,
blue:blue
}
ipcRenderer.send('led-ws2812',{color:rgbColor})
})

function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}

function hexToRGB(hexColor){
var color = {}
color.red = parseInt(hexColor.substr(1,2),16)
color.green = parseInt(hexColor.substr(3,2),16)
color.blue = parseInt(hexColor.substr(5,2),16)
return color
}

7.3 主程序逻辑控制代码(main.js)

Electron应用程序初始化,请参考前面文章。下面将介绍主程序中WS2812控制逻辑。在main.js文件中添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const five = require('johnny-five')
const pixel = require('node-pixel')
const board = new five.Board({port:'COM12',repl:false})

board.on('ready',() => {
console.log('board inited')
const ws2812 = new pixel.Strip({
board: board, // 连接的开发板对象
controller: "FIRMATA", // 控制协议
strips: [ {pin: 6, length: 9}, ], // WS2812连接到Arduino开发板引脚6,灯珠数量为9
gamma: 2.8, // 设置gamma值,WS2812显示效果会更好
});

// 监听WS2812连接状态
ws2812.on('ready',() => {
console.log('ws2812 strip is ready')
})

// 监听渲染进程事件
ipcMain.on('led-ws2812',(event,arg) => {
let rgbColor = arg.color
// 设置颜色
ws2812.color([rgbColor.red,rgbColor.green,rgbColor.blue])
// 显示
ws2812.show()
})
})

文章来源: https://iotsmart.blog.csdn.net/article/details/124962926