接下来我们要利用「 PWM」与「RGB LED」设计调色盘功能。
首先来认识一下新朋友 - 「RGB LED」
电子助教:「所以为甚麽要把三种 LED 合在一起?( ´ ▽ ` )ノ」
鳕鱼:「这就是一个很长的故事了。很久以前,R LED 与 G LED 的祖先们发生了不可告人的...」
电子助教:「不要瞎掰好吗,明明就是为了要混色!(°c_,°`)」
鳕鱼:「你明明就知道是问个毛线喔... ('◉◞⊖◟◉` )」
需要准备以下设备与零件:
三用电表 * 1
面包板 * 1
RGB LED * 1
推荐大家买这种模组式的 RGB LED,因为上面已经配好电阻,可以直接接线。
老样子要检查小夥伴们是否正常。
测试方式与一般 LED 概念相同。
若有任一种颜色没有亮,表示此颜色之 LED 损坏,请换一个 RGB LED。
以下为参考接线方式,可以不用完全相同,只要效果相同即可。
使用 Uno 板子上的 5V 为 +、GND 为 -。
将 window-example.vue
复制一份後改个名字,建立 window-app-rgb-led-palette.vue
。
调色盘相关档案建立一个 src\components\window-app-rgb-led-palette\
资料夹整理。
src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue
<template lang="pug">
base-window.window-app-rgb-led-palette(
:pos='pos',
header-icon-color='blue-grey',
header-icon='r_palette',
body-class='c-col h-330px',
title='RGB LED 调色盘'
)
</template>
<style lang="sass">
</style>
<script>
import mixinWindow from '@/mixins/mixin-window';
import BaseWindow from '@/components/base-window.vue';
export default {
name: 'WindowAppRgbLedPalette',
components: {
'base-window': BaseWindow,
},
mixins: [mixinWindow],
props: {},
data() {
return {};
},
computed: {},
watch: {},
created() {
console.log(`[ ${this.$options.name} created ] id : `, this.id);
},
mounted() {},
methods: {},
};
</script>
接着回到 app.vue
,将右键选单内加入『新增「RGB LED 调色盘」』选项,并引入组件。
src\app.vue <template lang="pug">
.screen(@click='handleClick')
// ...
// 右键选单
q-menu(context-menu, content-class='border-radius-s')
q-list.min-w-260px
q-item(@click='addWindow("window-digital-io")', clickable, v-close-popup)
q-item-section
| 新增「数位 I/O 视窗」
q-item(@click='addWindow("window-analog-input")', clickable, v-close-popup)
q-item-section
| 新增「类比输入视窗」
q-item(@click='addWindow("window-pwm-output")', clickable, v-close-popup)
q-item-section
| 新增「PWM 输出视窗」
q-separator
q-item(
@click='addWindow("window-app-rgb-led-palette")',
clickable,
v-close-popup
)
q-item-section
| 新增「RGB LED 调色盘」
src\app.vue <script>
// ...
import WindowDigitalIo from '@/components/window-digital-io.vue';
import WindowAnalogInput from '@/components/window-analog-input.vue';
import WindowPwmOutput from '@/components/window-pwm-output.vue';
import WindowAppRgbLedPalette from '@/components/window-app-rgb-led-palette/window-app-rgb-led-palette.vue';
export default {
name: 'App',
components: {
'dialog-system-setting': DialogSystemSetting,
'window-digital-io': WindowDigitalIo,
'window-analog-input': WindowAnalogInput,
'window-pwm-output': WindowPwmOutput,
'window-app-rgb-led-palette': WindowAppRgbLedPalette,
},
// ...
};
增加以下程序:
base-select-pin.vue
。data()
ledPin
储存 RGB 3 个脚位。colorVal
储存目前颜色。methods
handleErr(msg)
处理错误讯息src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue <script>
import mixinWindow from '@/mixins/mixin-window';
import BaseWindow from '@/components/base-window.vue';
import BaseSelectPin from '@/components/base-select-pin.vue';
export default {
name: 'WindowAppRgbLedPalette',
components: {
'base-window': BaseWindow,
'base-select-pin': BaseSelectPin,
},
mixins: [mixinWindow],
props: {},
data() {
return {
ledPin: {
r: null,
g: null,
b: null,
},
colorVal: '',
};
},
computed: {},
watch: {},
created() {
console.log(`[ ${this.$options.name} created ] id : `, this.id);
},
mounted() {},
methods: {
handleErr(msg) {
this.$q.notify({
type: 'negative',
message: msg,
});
},
},
};
src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue <template lang="pug">
base-window.window-app-rgb-led-palette(
:pos='pos',
header-icon-color='blue-grey',
header-icon='r_palette',
body-class='c-col h-330px',
title='RGB LED 调色盘'
)
.h-full.overflow-hidden
.setting-form
.text-14px.mb-14px
| 设定 RGB LED 脚位
.led-item
q-icon(name='r_emoji_objects', color='red-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.r',
color='red-2',
placeholder='点击选择',
@err='handleErr'
)
.led-item
q-icon(name='r_emoji_objects', color='green-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.g',
color='green-2',
placeholder='点击选择',
@err='handleErr'
)
.led-item
q-icon(name='r_emoji_objects', color='blue-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.b',
color='blue-2',
placeholder='点击选择',
@err='handleErr'
)
src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue <style lang="sass">
@import '@/styles/quasar.variables.sass'
.window-app-rgb-led-palette
width: 300px
.setting-form
position: absolute
padding: 30px
width: 100%
height: 100%
.led-item
display: flex
align-items: center
margin-bottom: 10px
.q-icon
margin-right: 14px
设定栏位外观完成。
功能需求为:
src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue <script>
/**
* @typedef {import('@/script/modules/port-transceiver').default} PortTransceiver
*
* @typedef {import('@/types/type').PinInfo} PinInfo
* @typedef {import('@/types/type').PinCapability} PinCapability
*/
import { mapState } from 'vuex';
// ...
import { PinMode } from '@/script/utils/firmata.utils';
const { PWM } = PinMode;
export default {
name: 'WindowAppRgbLedPalette',
// ...
watch: {
'ledPin.r': {
handler(newVal, oldVal) {
this.handlePinSelect(newVal, oldVal);
},
},
'ledPin.g': {
handler(newVal, oldVal) {
this.handlePinSelect(newVal, oldVal);
},
},
'ledPin.b': {
handler(newVal, oldVal) {
this.handlePinSelect(newVal, oldVal);
},
},
},
// ...
computed: {
...mapState({
boardPins: (state) => state.board.info.pins,
/** @type {PortTransceiver} */
portTransceiver: (state) => state.core.transceiver,
}),
/** 支援功能的脚位 */
supportPins() {
/** @type {PinInfo[]} */
const boardPins = this.boardPins;
return boardPins.filter((pin) =>
pin.capabilities.some((capability) => PWM === capability.mode)
);
},
/** 判断所有 Pin 脚是否选择完成 */
isSettingOk() {
return Object.values(this.ledPin).every((pin) => pin);
},
},
// ...
methods: {
// ...
/** 处理脚位选择事件,回报 Vuex 新增、移除占用脚位
* @param {PinInfo} newVal
* @param {PinInfo} oldVal
*/
handlePinSelect(newVal, oldVal) {
if (newVal) {
this.$store.commit('window/addOccupiedPin', {
id: this.id,
pin: newVal,
});
}
if (oldVal) {
this.$store.commit('window/deleteOccupiedPin', {
id: this.id,
pin: oldVal,
});
}
},
},
};
将每个 base-select-pin
传入 supportPins
。
src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue <template lang="pug">
base-window.window-app-rgb-led-palette(
:pos='pos',
header-icon-color='blue-grey',
header-icon='r_palette',
body-class='c-col h-330px',
title='RGB LED 调色盘'
)
.h-full.overflow-hidden
.setting-form
.text-14px.mb-14px
| 设定 RGB LED 脚位
.led-item
q-icon(name='r_emoji_objects', color='red-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.r',
:pins='supportPins',
color='red-2',
placeholder='点击选择',
@err='handleErr'
)
.led-item
q-icon(name='r_emoji_objects', color='green-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.g',
:pins='supportPins',
color='green-2',
placeholder='点击选择',
@err='handleErr'
)
.led-item
q-icon(name='r_emoji_objects', color='blue-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.b',
:pins='supportPins',
color='blue-2',
placeholder='点击选择',
@err='handleErr'
)
尝试看看。
成功!再来就是自动切换画面的部分,我们使用 transition
达成效果。
src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue <template lang="pug">
base-window.window-app-rgb-led-palette(
:pos='pos',
header-icon-color='blue-grey',
header-icon='r_palette',
body-class='c-col h-330px',
title='RGB LED 调色盘'
)
.h-full.overflow-hidden
// 设定完成後,显示这一区
transition(name='switch-right')
.text-30px.absolute(v-if='isSettingOk') (´,,•ω•,,)
// 设定完成前,显示设定栏位
transition(name='switch-left')
.setting-form(v-if='!isSettingOk')
.text-14px.mb-14px
| 设定 RGB LED 脚位
.led-item
q-icon(name='r_emoji_objects', color='red-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.r',
:pins='supportPins',
color='red-2',
placeholder='点击选择',
@err='handleErr'
)
.led-item
q-icon(name='r_emoji_objects', color='green-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.g',
:pins='supportPins',
color='green-2',
placeholder='点击选择',
@err='handleErr'
)
.led-item
q-icon(name='r_emoji_objects', color='blue-5', size='34px')
base-select-pin.w-full(
v-model='ledPin.b',
:pins='supportPins',
color='blue-2',
placeholder='点击选择',
@err='handleErr'
)
定义过场动画。
src\components\window-app-rgb-led-palette\window-app-rgb-led-palette.vue <style lang="sass">
@import '@/styles/quasar.variables.sass'
.window-app-rgb-led-palette
width: 300px
// ...
.switch-left-enter-active, .switch-left-leave-active
transition-timing-function: cubic-bezier(0.945, -0.290, 0.165, 1.360)
transition-duration: 0.8s
pointer-events: none
.switch-left-enter, .switch-left-leave-to
transform: translateX(100%) !important
opacity: 0 !important
.switch-right-enter-active, .switch-right-leave-active
transition-timing-function: cubic-bezier(0.945, -0.290, 0.165, 1.360)
transition-duration: 0.8s
pointer-events: none
.switch-right-enter, .switch-right-leave-to
transform: translateX(-100%) !important
opacity: 0 !important
实测效果。
成功切换画面了!✧*。٩(ˊᗜˋ*)و✧*。
下一章节进入实作彩球的部分!
以上程序码已同步至 GitLab,大家可以前往下载:
图片来源 这标题虽然有点耸动, 但也是"软件资讯业"的业态发展趋势, 虽然新闻...
前情提要: 看完记忆体储存差异,现在要来谈谈全域污染这件事。 基本scope概念 所谓的范畴Scop...
写在前面 still placeholder still placeholder still pla...
关於 时区 因为取资料的方式都以时间线的方式取得(http, websocket) 所以时区是一个必...
反弹球 ( 乒乓球 ) 教学原文参考:反弹球 ( 乒乓球 ) 这篇文章会介绍,如何在 Scratch...