D16 - 「脉冲×宽度×调变」

这个章节要开始建立「PWM 输出视窗」。

何谓 PWM

名为「脉冲宽度调变」(Pulse-width modulation)。PWM 本质上算是一种数位讯号,但是透过调整频宽的方式,可以产生类似「类比讯号」的效果,是一种非常方便的技术,被大量应用在调速、通讯等等场合。

更详细的说明可以参考以下连结:
PWM 脉冲宽度调变

建立 PWM 输出视窗

内容大多可复用先前数位、类比功能视窗,所以过程大同小异 ∠( ᐛ 」∠)_

window-example.vue 复制一份後改个名字,建立 window-analog-input.vue

src\components\window-pwm-output.vue

<template lang="pug">
base-window.window-pwm-output(
  :pos='pos',
  header-icon-color='light-green-4',
  body-class='c-col p-20px pt-20px',
  title='PWM 输出功能'
)
</template>

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

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

export default {
  name: 'WindowPwmOutput',
  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,将右键选单内加入『新增「PWM 输出视窗」』选项,并引入组件。

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 输出视窗」

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';

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

加入视窗内容

一样加入 base-select-pin.vue

src\components\window-pwm-output.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: 'WindowPwmOutput',
  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-pwm-output.vue <template lang="pug">

base-window.window-pwm-output(
  :pos='pos',
  header-icon-color='light-green-4',
  body-class='c-col p-20px pt-20px',
  title='PWM 输出功能'
)
  base-select-pin(color='light-green-4')

Untitled

接着便是提供脚位清单了,在 computed 增加 supportPins,提供支援 PWM 功能的脚位。

src\components\window-pwm-output.vue <script>

import { mapState } from 'vuex';

// ...

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

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

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

      return boardPins.filter((pin) =>
        pin.capabilities.some((capability) => PWM === capability.mode)
      );
    },
  },
  // ...
};

src\components\window-pwm-output.vue <template lang="pug">

base-window.window-pwm-output(
  :pos='pos',
  header-icon-color='light-green-4',
  body-class='c-col p-20px pt-20px',
  title='PWM 输出功能'
)
  base-select-pin(:pins='supportPins', color='light-green-4')

D16 - PWM 输出脚位 select options.gif

可以看到只有 Pin 3、5、6、9、10、11,比对一下 Uno 脚位,会注意到这些脚位数字旁边都有个「~」符号,这些符号便是 PWM 功能的意思。

D16 - Uno PWM 脚位.png

储存建立脚位

接下来依样是储存建立脚位的部分。

  • 增加 existPins 变数,储存目前已建立脚位
  • 绑定 base-select-pin.vueselected 事件,接收被选择的脚位。

src\components\window-pwm-output.vue <script>

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

import { mapState } from 'vuex';

import mixinWindow from '@/mixins/mixin-window';

import BaseWindow from '@/components/base-window.vue';
import BaseSelectPin from '@/components/base-select-pin.vue';

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

export default {
  name: 'WindowPwmOutput',
  // ...
  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-pwm-output.vue <template lang="pug">

base-window.window-pwm-output(
  :pos='pos',
  header-icon-color='light-green-4',
  body-class='c-col p-20px pt-20px',
  title='PWM 输出功能'
)
  base-select-pin(
    :pins='supportPins',
    color='light-green-4',
    @selected='addPin',
    @err='handleErr'
  )

聪明的读者们一定注意到了「这里的步骤和数位、类比视窗都一样」,所以大家也可以将这些重复内容抽出、建立 mixin。( ‧ ∀ ‧)ノ╰(‧ ∀ ‧ )

试试有没有正常。

D16 - PWM 输出视窗选择脚位.gif

轻松愉快的完成 PWM 视窗,再来一样进入建立控制组件环节。

总结

  • 成功建立 PWM 输出视窗。
  • 引入 base-select-pin 组件,用於选择脚位。
  • 储存选择脚位清单。

以上程序码已同步至 GitLab,大家可以前往下载:

GitLab - D16


<<:  帆船与海

>>:  D-Day -- 我覆盖魔法牌 结束这回合!

【领域展开 30 式】 完赛习得 30 式,去年与今年的比较回顾

感谢老天又让我有机会参加铁人赛,虽然今年一样面临了新的工作环境,但还是保有挑战与坚持的心态,BTW ...

GCP Container Registry

Container Registry 今天说一下如何在GCP上建立Docker Image私仓(Do...

PMI PMP 练习测试 - 在实际 PMP 考试中确认成功

如今,大多数有抱负的专业人士都获得了认证。你可以说它已经成为一种趋势,但更重要的是它是一种必需品。因...

Day14 Vue directives(v-for)上

用v-for把阵列转成元素 一开始我们先把items的资料容给见出来 接下来呢我们用v-for=&q...

【Day24】闭包(Closure)

今天我要讲解的是闭包(Closure),在进入之前我们先来看一段程序码, 首先准备一个随机生成字串的...