iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Modern Web

你渴望連結嗎?將 Web 與硬體連上線吧!系列 第 14

D13 - 「類比×電壓×輸入」

本系列文已改編成書「Arduino 自造趣:結合 JavaScript x Vue x Phaser 輕鬆打造個人遊戲機」,本書改用 Vue3 與 TypeScript 全面重構且加上更詳細的說明,

在此感謝 iT 邦幫忙、博碩文化與編輯小 p 的協助,歡迎大家前往購書,鱈魚在此感謝大家 (。・∀・)。

若想 DIY 卻不知道零件去哪裡買的讀者,可以參考此連結 。( •̀ ω •́ )✧


接下來我們開始建立「類比輸入視窗」。

何謂類比訊號

和數位訊號只有 0 與 1 兩種狀態不同,類比訊號是連續的訊號,實際上自然界的物理量都屬於類比訊號,例如:聲音、光、電壓等等。

更詳細的定義與說明可以參考以下連結:
wiki - 類比訊號
wiki - 數位訊號

Uno 上的類比輸入指的是「電壓」訊號,Uno 可以讀取 0 至 5V 的電壓並轉換為數位訊號回傳。

具體實現方式為透過 ADC(Analog to Digital Convert)轉換電壓訊號,Uno 使用的轉換器解析度為 10 位元,所以會將 0 至 5V 的電壓轉換為 0 至 1023(2 的 10 次方 - 1)的數值呈現。

建立類比輸入視窗

window-example.vue 複製一份後改個名字,建立 window-analog-input.vue

src\components\window-analog-input.vue

<template lang="pug">
base-window.window-analog-input(
  :pos='pos',
  headerIconColor='red-3',
  body-class='c-col p-20px pt-20px',
  title='類比輸入功能'
)
</template>

<style lang="sass">
.window-analog-input
  width: 300px
  height: 400px
</style>

<script>
import BaseWindow from '@/components/base-window.vue';
import mixinWindow from '@/mixins/mixin-window';

export default {
  name: 'WindowAnalogInput',
  components: {
    'base-window': BaseWindow,
  },
  mixins: [mixinWindow],
  props: {},
  data() {
    return {
      id: this.$vnode.key,
    };
  },
  provide() {
    return {
      id: this.id,
    };
  },
  computed: {},
  watch: {},
  created() {
    console.log(`[ ${this.$options.name} created ] id : `, this.id);
  },
  mounted() {},
  methods: {},
};
</script>

忽然發現其實 data() 中的 idprovide() 內容在每個 window 也都重複出現,所以一樣遷移至 mixin-window 中。

src\mixins\mixin-window.js

/**
 * 標準 window 共用內容
 */

export default {
  props: {
    pos: {
      type: Object,
      default() {
        return {
          x: 0,
          y: 0,
        };
      },
    },
  },
  data() {
    return {
      id: this.$vnode.key,
    };
  },
  provide() {
    return {
      id: this.id,
    };
  },
}

並將 window-analog-input.vuewindow-digital-io.vuewindow-example.vue 已遷移的部份刪除。

src\components\window-analog-input.vue <script>

import BaseWindow from '@/components/base-window.vue';
import mixinWindow from '@/mixins/mixin-window';

export default {
  name: 'WindowAnalogInput',
  components: {
    'base-window': BaseWindow,
  },
  mixins: [mixinWindow],
  props: {},
  data() {
    return {};
  },
  computed: {},
  watch: {},
  created() {
    console.log(`[ ${this.$options.name} created ] id : `, this.id);
  },
  mounted() {},
  methods: {},
};

內容變得更清爽了!

接著回到 app.vue,將右鍵選單內加入『新增「類比輸入視窗」』選項,並引入組件。

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
          | 新增「類比輸入視窗」

src\app.vue <script>

// ...

import WindowDigitalIo from '@/components/window-digital-io.vue';
import WindowAnalogInput from '@/components/window-analog-input.vue';

export default {
  name: 'App',
  components: {
    'dialog-system-setting': DialogSystemSetting,
    'window-digital-io': WindowDigitalIo,
		'window-analog-input': WindowAnalogInput,
  },
  // ...
};

加入視窗內容

「選擇腳位的下拉選單」已經建立完成,直接引入 base-select-pin.vue

src\components\window-analog-input.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: 'WindowAnalogInput',
  components: {
    'base-window': BaseWindow,
    'base-select-pin': BaseSelectPin,
  },
  mixins: [mixinWindow],
  props: {},
  data() {
    return {};
  },
  computed: {},
  watch: {},
  created() {
    console.log(`[ ${this.$options.name} created ] id : `, this.id);
  },
  mounted() {},
  methods: {},
};

src\components\window-analog-input.vue <template lang="pug">

base-window.window-analog-input(
  :pos='pos',
  headerIconColor='red-3',
  body-class='c-col p-20px pt-20px',
  title='類比輸入功能'
)
  base-select-pin(color='red-3')

https://ithelp.ithome.com.tw/upload/images/20240118/20140213SbPb7d6MsC.png

元件複用的感覺真好 ヾ(◍'౪`◍)ノ゙

接著便是提供腳位清單資料作為 base-select-pin.vue 的 options 顯示,在 computed 增加 supportPins,提供支援類比功能腳位清單。

src\components\window-analog-input.vue <script>

import { mapState } from 'vuex';

// ...

import { PinMode } from '@/script/utils/firmata.utils';
const { ANALOG_INPUT } = PinMode;

export default {
  name: 'WindowAnalogInput',
  // ...
  computed: {
    ...mapState({
      boardPins: (state) => state.board.info.pins,
    }),

		// 支援功能的腳位
    supportPins() {
      /** @type {PinInfo[]} */
      const boardPins = this.boardPins;

      return boardPins.filter((pin) => {
        const hasMode = pin.capabilities.some(
          (capability) => ANALOG_INPUT === capability.mode
        );

        return hasMode;
      });
    },
  },
  // ...
};

src\components\window-analog-input.vue <template lang="pug">

base-window.window-analog-input(
  :pos='pos',
  headerIconColor='red-3',
  body-class='c-col p-20px pt-20px',
  title='類比輸入功能'
)
  base-select-pin(:pins='supportPins', color='red-3')

看看結果如何。

D13 - 類比輸入腳位 select options.gif

可以看到只剩下 Pin 14 到 Pin 19。

儲存建立腳位

這個部分基本上與「數位 I/O 視窗」相同。

  • 增加 existPins 變數,儲存目前已建立腳位
  • 綁定 base-select-pin.vueselected 事件,接收被選擇的腳位。

src\components\window-analog-input.vue <script>

/**
 * @typedef {import('@/types/type').PinInfo} PinInfo
 */

// ...

export default {
  name: 'WindowAnalogInput',
  // ...
  data() {
    return {
      /** @type {PinInfo[]} */
      existPins: [],
    };
  },
  // ...
  methods: {
		/** 新增腳位
     * @param {PinInfo} pin
     */
    addPin(pin) {
      if (!pin) return;

      this.$store.commit('window/addOccupiedPin', {
        id: this.id,
        pin,
      });

      this.existPins.push(pin);
    },
		/** 移除腳位
     * @param {PinInfo} pin
     */
    deletePin(pin) {
      if (!pin) return;

      this.$store.commit('window/deleteOccupiedPin', {
        id: this.id,
        pin,
      });

      const index = this.existPins.findIndex(
        (existPin) => existPin.number === pin.number
      );
      this.existPins.splice(index, 1);
    },

    /** 接收錯誤訊息 */
    handleErr(msg) {
      this.$q.notify({
        type: 'negative',
        message: msg,
      });
    },
  },
};

src\components\window-analog-input.vue <template lang="pug">

base-window.window-analog-input(
  :pos='pos',
  headerIconColor='red-3',
  body-class='c-col p-20px pt-20px',
  title='類比輸入功能'
)
  base-select-pin(
    :pins='supportPins',
    color='red-3',
    @selected='addPin',
    @err='handleErr'
  )

試試看效果如何。

D13 - 類比輸入視窗選擇腳位.gif

太棒了!再來就是建立類比輸入控制組件,顯示類比輸入數值。

總結

  • 成功建立類比輸入視窗。
  • 引入 base-select-pin 組件,用於選擇腳位。
  • 儲存選擇腳位清單。

以上程式碼已同步至 GitLab,大家可以前往下載:

GitLab - D13


上一篇
D12 - 「數位×IN×OUT」:建立控制組件
下一篇
D14 - 「類比×電壓×輸入」:Arduino 類比功能(analog)
系列文
你渴望連結嗎?將 Web 與硬體連上線吧!33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言