Arduino与JavaScript开发实例-LED基础控制-(点亮、关闭、PWM及FadeIn和FadeOut)

LED基础控制-(点亮、关闭、PWM及FadeIn和FadeOut)

文章目录

Johnny-Five库中的Led 类构造了表示连接到物理板上的单个 Led 的对象。本次实例将演示如何在Electron的基础上通过Johnny-Five库与Arduino开发板通信,并实现控制LED点亮、关闭、PWM、及FadeIn和FadeOut。

1、硬件准备

  • Arduino Mega2560开发板一块
  • 发光LED一个
  • 杜邦线若干
  • 数据线一条

硬件接线如下:

在这里插入图片描述

2、软件准备

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

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

3、代码实现

3.1 LED对象创建

3.1.1 参数
  • pin:LED引脚的数字或字符串地址(数字/PWM)。 对于只有开/关状态的LED,请使用数字引脚。
1
2
3
const five = require('johnny-five')
let led = new five.Led(13)

对于具有开/关状态的LED,以及与间隔或颜色相关的状态(脉冲、亮度、RGB 等),请使用PWM引脚。

  • General Options:属性参数对象
属性名称 类型 值/描述 默认值 是否必要
pin Number LED引脚。LED 连接到的引脚的编号地址。 yes
controller String 控制器,默认为”PCA9685”。 "DEFAULT" no
board Object Instance LED 连接到的板实例。 仅当您的项目中安装了多个板时才需要 First board mounted no
  • **PCA9685 Options (PCA9685控制器)**:属性参数的对象
属性名称 类型 值/描述 默认 是否必要
address Number I2C设备地址。 0x04 no
3.1.2 初始化
1
2
3
4
5
6
7
8
// 只有一个引脚
var led = new five.Led(13);

// 具有 pin 属性的选项对象
new five.Led({
pin: 13
});

使用PCA9685控制器初始化

1
2
3
4
5
new five.Led({
controller: "PCA9685",
pin: 0, // PCA9685的0引脚
});

3.1.3 调用

LED闪烁

1
2
3
4
5
6
7
8
9
// LED闪烁
var five = require("johnny-five");
var board = new five.Board();

board.on("ready", function() {
var led = new five.Led(13);
led.blink();
});

多开发板控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 多个开发板
var five = require("johnny-five");
var board1 = new five.Board();
var board2 = new five.Board();

board1.on("ready", function() {
var led1 = new five.Led(board1, 13);
led.blink();
});

board2.on("ready", function() {
var led2 = new five.Led(board2, 13);
led.blink();
});

PCA9685控制器

1
2
3
4
5
6
7
8
9
10
11
12
var five = require("johnny-five");
var board = new five.Board();

board.on("ready", function() {
var led = new five.Led({
controller: "PCA9685",
pin: 0,
});

led.blink()
});

3.2 Electron代码实现

1)package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"name": "Arduino Firmata Electron",
"version": "0.0.1",
"main": "main.js",
"dependencies": {
"bootstrap": "^5.1.3",
"echarts": "^5.3.0",
"jquery": "^3.6.0",
"socket.io": "^4.4.1",
"ws": "^8.5.0",
"mqtt": "^4.3.6",
"johnny-five": "^2.1.0",
"path": "^0.12.7",
"react": "^17.0.2",
"react-bootstrap": "^2.2.0",
"react-dom": "^17.0.2",
"react-scripts": "^5.0.0"
}
}

2)页面布局(index.html)

Electron应用程序的页面通过Bootstrap、Bootstrap Slider插件、JQuery实现。代码如下:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LED控制</title>
<script>window.$ = window.jQuery = require('jquery');</script>
<script src="../bootstrap-5.1.3-dist/js/bootstrap.min.js"></script>
<script src="../bootstrap-slider-master/dist/bootstrap-slider.min.js"></script>
<script>
window.echarts = require('echarts');
</script>
<link href="../bootstrap-5.1.3-dist/css/bootstrap.min.css" rel="stylesheet"></link>
<link href="../bootstrap-slider-master/dist/css/bootstrap-slider.min.css" rel="stylesheet"></link>
</head>

<body>
<div class="row">
<div class="col-md-2">
<div class="panel panel-default" style="width:128px;height:256px">
<div class="panel-heading text-center">LED开关</div>
<div class="panel-body">
<button type="button" class="btn" id="led-btn">
<image src="../images/led\_off.png" id="led-ctr-bg-img"></image>
</button>
</div>
<div class="panel-footer text-center" id="led-controller-title">打开LED</div>
</div>
</div>
<div class="col-md-2">
<div class="panel panel-default" style="width:128px;height:256px">
<div class="panel-heading text-center">LED闪烁</div>
<div class="panel-body">
<button type="button" class="btn" id="led-blink-btn">
<image src="../images/led\_off.png" id="led-blink-bg-img"></image>
</button>
</div>
<div class="panel-footer text-center" id="led-controller-blink-title">打开闪烁</div>
</div>
</div>
<div class="col-md-2">
<div class="panel panel-default" style="width:512px;height:256px">
<div class="panel-heading text-center">LED PWM</div>
<div class="panel-body">
<div class="row">
<div class="col d-flex flex-row">
<label class="form-check-label" for="led-pulse-slider-d">延时</label>
<input id="led-pulse-slider" data-slider-id='led-pulse-slider-d' type="text" data-slider-min="100"
data-slider-max="5000"
data-slider-step="100" data-slider-value="1000"/>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="led-pulse-stop-cb">
<label class="form-check-label" for="led-pulse-stop-cb">自动停止</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="led-pulse-anim-cb">
<label class="form-check-label" for="led-pulse-anim-cb">动画效果</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="led-pulse-fade-cb">
<label class="form-check-label" for="led-pulse-fade-cb">淡入淡出</label>
</div>
</div>
</div>
<div class="row">
<div class="clo d-flex flex-row">
<button type="button" class="btn btn-primary" id="led-pulse-btn">开始</button>

</div>
</div>
</div>
<div class="panel-footer text-center" id="led-controller-pulse-title"></div>
</div>

</div>
</div>
<div class="row">
<div class="col-md-2">
<div class="panel panel-default" style="width:512px;height:256px">
<div class="panel-heading ">LED亮度调节</div>
<div class="panel-body">
<label class="form-check-label" for="led-brightness-slider-d">亮度</label>
<input id="led-brightness-slider" data-slider-id='led-brightness-slider-d' type="text" data-slider-min="0"
data-slider-max="255"
data-slider-step="1" data-slider-value="128"/>
</div>
<div class="panel-footer" id="led-controller-brightness-title">当前亮度:128</div>
</div>
</div>
</div>
<script src="../../static/js/renderer/led\_controll\_renderer.js"></script>
</body>

</html>

上面代码实现的页面效果如下:

在这里插入图片描述

3)页面逻辑控制(renderer.js)

由于johnny-five库调用到serialport库(nodejs addon),Electron v14+后不支持在渲染进程中直接调用,只能在主进程中调用。为了johnny-five库正常使用,可以通过Electron的进程间通信方式实现,即通过Electron的ipcMainipcRender来实现渲染进程与主进程间的通信。

导入类或库

1
2
const { ipcRenderer } = require('electron')

LED开关控制

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
// LED ON/OF
$('#led-btn').on('click',() => {
if(!ledState){
// 向主进程发送led-on事件
ipcRenderer.send('led-on','');
console.log('led on')
}else{
// 向主进程发送led-off事件
ipcRenderer.send('led-off','')
console.log('led off')
}

// 更新LED状态和页面更新
ledState = !ledState
if(ledState){
$('#led-ctr-bg-img').attr('src','../images/led\_on.png')
$('#led-controller-title').html('关闭LED')
}else{
$('#led-ctr-bg-img').attr('src','../images/led\_off.png')
$('#led-controller-title').html('打开LED')
}

// 更新LED闪烁状态和页面更新
isLedBlinking = false
$('#led-blink-bg-img').attr('src','../images/led\_off.png')
})

LED闪烁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// LED闪烁
$('#led-blink-btn').on('click', () => {
if(!isLedBlinking){
// 向主进程发送led-blink-start事件,500毫秒间隔
ipcRenderer.send('led-blink-start',{delay:500})
// 更新UI
$('#led-controller-blink-title').html('停止闪烁')
$('#led-blink-bg-img').attr('src','../images/led\_blink.gif')
console.log('start blinking')
}else{
// 向主进程发送led-blink-stop事件,500毫秒间隔
ipcRenderer.send('led-blink-stop',{delay:-1})
// 更新UI
$('#led-controller-blink-title').html('开始闪烁')
$('#led-blink-bg-img').attr('src','../images/led\_off.png')
console.log('stop blink')
}
isLedBlinking = !isLedBlinking
// 更新UI
ledState = false
$('#led-ctr-bg-img').attr('src','../images/led\_off.png')
$('#led-controller-title').html('打开LED')
})

LED PWM控制

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
var ledPulseValue = 1000
// 初始化Bootstrap Slider并注册change事件
var ledPWMSlider = $('#led-pulse-slider').bootstrapSlider().on('change',() => {
// 获取当前Slider的值
ledPulseValue = $('#led-pulse-slider').bootstrapSlider('getValue')
console.log('led pulse:' + ledPulseValue)
})

$('#led-pulse-btn').on('click',() =>{
// 获取延时值(毫秒)
let stopForDelay = $('#led-pulse-stop-cb').is(':checked');
// 是否启用动画方式
let isAnimate = $('#led-pulse-anim-cb').is(':checked')
// 是否启用淡入和淡出方式
let isFade = $('#led-pulse-fade-cb').is(':checked')

// 向主进程发送led-pulse命令
ipcRenderer.send('led-pulse',{
delay:ledPulseValue,
stopAfterDelay:stopForDelay,
isAnimate:isAnimate,isFade:isFade})

// 更新UI
isLedBlinking = false
$('#led-blink-bg-img').attr('src','../images/led\_off.png')
$('#led-controller-blink-title').html('开始闪烁')

ledState = false
$('#led-ctr-bg-img').attr('src','../images/led\_off.png')
$('#led-controller-title').html('打开LED')

console.log('led pulse:' + ledPulseValue)
})

LED亮度控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// LED 亮度
var ledBrightness = 128;
// 初始化Bootstrap Slider
var ledBrightnessSlider = $('#led-brightness-slider').bootstrapSlider().on('change',() => {
// 获取当前亮度值
ledBrightness = $('#led-brightness-slider').bootstrapSlider('getValue')
console.log('led brightness:' + ledBrightness)
// 向主进程发送led-brightness命令
ipcRenderer.send('led-brightness',{brightness:ledBrightness})

// 更新UI
$('#led-controller-brightness-title').html('当前亮度:' + ledBrightness)
isLedBlinking = false
$('#led-blink-bg-img').attr('src','../images/led\_off.png')
$('#led-controller-blink-title').html('开始闪烁')

ledState = false
$('#led-ctr-bg-img').attr('src','../images/led\_off.png')
$('#led-controller-title').html('打开LED')

console.log('led pulse:' + ledPulseValue)
})

4)应用程序入口(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
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
62
63
64
const { app, BrowserWindow,ipcMain } = require('electron')
const path = require('path')
const url = require('url')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow() {

// Create the browser window.
mainWindow = new BrowserWindow({
width: 1024,
height: 600,
backgroundColor: "#ccc",
webPreferences: {
nodeIntegration: true, // to allow require
contextIsolation: false, // allow use with Electron 12+
preload: path.join(__dirname, 'preload.js')
}
})

// and load the index.html of the app.
mainWindow.loadURL(url.format({
pathname: path.join(__dirname+'/static/html', 'led\_control.html'),
//pathname:path.join(\_\_dirname,'index.html'),
protocol: 'file:',
slashes: true
}))

// Open the DevTools.
mainWindow.webContents.openDevTools()

// Emitted when the window is closed.
mainWindow.on('closed', function() {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}



// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', function() {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
app.quit()
})

app.on('activate', function() {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})

LED控制响应实现

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
const five = require('johnny-five')

const board = new five.Board({port:'COM12',repl:false})

board.on('ready',() => {
console.log('board inited')
const led = new five.Led(13)
let isLedBlinking = false;

// LED打开
ipcMain.on('led-on', (event, arg) =>{
console.log('led on')
led.stop() // 关闭内部定时器
led.on()
})

// LED关闭
ipcMain.on('led-off',(event,arg) => {
console.log('led off')
led.off()
})

// LED闪烁开始
ipcMain.on('led-blink-start',(event,arg) => {
var delay = arg.delay
led.stop() // // 关闭内部定时器
console.log('led start to bink:delay = ' + delay + ' ms');
led.blink(delay)
isLedBlinking = true
})

// LED闪烁关闭
ipcMain.on('led-blink-stop',(event,arg) => {
console.log('led stop blink');
led.stop()
isLedBlinking = false
})

// LED PWM控制
ipcMain.on('led-pulse',(event,arg) =>{
let delay = arg.delay // 延时
let stopForDelay = arg.stopAfterDelay // PWM输出完成后关闭定时器
let isAnimate = arg.isAnimate // 动画方式输出
let isFade = arg.isFade // 淡入淡出
console.log(arg)

led.stop() // // 关闭内部定时器
if(isAnimate && !isFade){
led.pulse({
easing: "linear",
duration: delay,
cuePoints: [0, 0.2, 0.4, 0.6, 0.8, 1],
keyFrames: [0, 10, 0, 50, 0, 255],
onstop() {
console.log("Animation stopped");
}
});
}else if(isFade && !isAnimate){
function fadeNext(){
led.fadeIn(delay)
console.log('fadeNext:fadeIn')
board.wait(delay,() => {
led.fadeOut(delay,fadeNext)
console.log('fadeNext:fadeOut')
})

}
led.on()
led.fadeOut(delay,fadeNext) // 淡出、启动回调循环
console.log('fadeNext:fadeOut')
}else{
led.fade()
}

if(stopForDelay){
board.wait(delay,() => {
led.stop().off() // 停止LED定时器并关闭LED
})
}
})

// LED亮度控制
ipcMain.on('led-brightness',(event,arg) => {
let brightness = arg.brightness
led.stop()
led.brightness(brightness)
console.log('brightness:' + brightness)
})
})


4、运行结果

在这里插入图片描述

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