linclip が 2021年02月15日19時24分37秒 に編集
コメント無し
本文の変更
@[youtube](https://www.youtube.com/watch?v=lIP_NmHyhS4) # はじめに ケーブル不要、直接USB端子に挿せるミニマムなPC用ボリューム・コントローラー。PCのボタンで操作するよりも直感的かつスピーディに音量を調整できます。 これまでATmega32U4でいくつか作ってきたのですが、直接PCのUSB端子に挿せるDigiSparkというとても小さなボードがあることを知り、DigiSparkで新たに作り直しました。 # 用意したもの - DigiSpark - ロータリーエンコーダー(スイッチ付き) - ノブ - ピンソケット - ピンヘッダー - 抵抗(10kΩ) - ハサミで切れる!薄型ユニバーサル基板 音量をコントロールするだけなら、普通のロータリーエンコーダーでいいのですが、モード切替でほかの操作をすることも考えて、スイッチ付きを選んでいます。 今回は音量のほか、スクロールもできるようにしてみました(ボタンで切替)。 DigiSparkには今回使用したタイプのほかに、MicroUSB端子が出ているものもあります。ケーブルで接続したい場合はそちらを選択してください。 # 配線 DigiSparkのボードに直接はんだ付けしたのはピンソケットのみ。ユニバーサル基板にピンヘッダーとロータリーエンコーダー、抵抗をはんだ付けします。 以下のように配線します。図の左がロータリーエンコーダー、右がDigiSpark。ロータリーエンコーダーから、3本の端子が出ている側が回転を検出するためのもの。2本の端子が出ている側が、スイッチです。 P0とP2 はプログラムでプルアップできますが、P1はプルアップできないので、抵抗を使っています(プルアップできないのに気づかず、無駄に時間がかかってしまいました)。 ![配線](https://camo.elchika.com/558e3b7e913ca47c1a39c0d6baff47726ccd4ccf/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34303631396238372d373831332d346334382d613433632d6439653963323937393766612f66313665616662392d363433362d346437332d616261332d313838653962383664646663/) はんだ付け後の写真です。 ![表](https://camo.elchika.com/30f544877cf980e3d68eaf01022d809049dd724d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34303631396238372d373831332d346334382d613433632d6439653963323937393766612f62626435613534622d306263382d343030312d393064362d353737363734376133383434/) ![裏](https://camo.elchika.com/d0656b5a36c9a07b782f2b80f5523370c811ff04/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34303631396238372d373831332d346334382d613433632d6439653963323937393766612f35303030666364372d653835322d346137342d383534362d623265613461653466613130/) # プログラム DigiSparkのプログラミングはArduino IDEが使用できます。
Adfruitが紹介しているTrinklet用プログラムを参考にしました。ロータリーエンコーダーまわりはほぼそのまま。スイッチによる切替や搭載LEDの処理をいろいろ試してみました。
Adfruitが紹介しているTrinklet用プログラムを参考にしました。ロータリーエンコーダーまわりはほぼそのまま。スイッチによる切替やLEDの処理などいろいろ試してみました。
https://learn.adafruit.com/trinket-usb-volume-knob
USB端子に挿して実際にコントローラーとして動作するまでには数秒かかります。準備ができたことを示すため、DigiSpark搭載のLEDを点滅させてみました。
## 使用したライブラリ Adafruit-Trinket-USB https://github.com/adafruit/Adafruit-Trinket-USB/ ## コード ``` #include "TrinketHidCombo.h" #define PIN_ENCODER_A 2 #define PIN_ENCODER_B 0 #define TRINKET_PINx PINB static uint8_t enc_prev_pos = 0; static uint8_t enc_flags = 0; #define PIN_LED 1 // LEDピン #define PIN_BUTTON 1 // ボタンピン int button_state = 0; // ボタンの状態 int button_state_old = 0; // ボタンの状態 前の値 int mode = 0; // モード void setup() {
pinMode(PIN_BUTTON, INPUT); pinMode(PIN_ENCODER_A, INPUT_PULLUP); pinMode(PIN_ENCODER_B, INPUT_PULLUP); TrinketHidCombo.begin(); // start the USB device engine and enumerate
// 準備ができたら点滅 pinMode(PIN_LED, OUTPUT); for (int i=0; i < 5 ; i++){ digitalWrite(PIN_LED, HIGH); delay(60); digitalWrite(PIN_LED, LOW); delay(60); }
// set button as input pinMode(PIN_BUTTON, INPUT); pinMode(PIN_ENCODER_A, INPUT_PULLUP); pinMode(PIN_ENCODER_B, INPUT_PULLUP); TrinketHidCombo.begin(); // start the USB device engine and enumerate
if (digitalRead(PIN_ENCODER_A) == LOW) { enc_prev_pos |= (1 << 0); } if (digitalRead(PIN_ENCODER_B) == LOW) { enc_prev_pos |= (1 << 1); } } void loop() { int8_t enc_action = 0; // 1 or -1 if moved, sign is direction uint8_t enc_cur_pos = 0; if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_A)) { enc_cur_pos |= (1 << 0); } if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_B)) { enc_cur_pos |= (1 << 1); } if (enc_cur_pos != enc_prev_pos) { if (enc_prev_pos == 0x00) {
// this is the first edge
if (enc_cur_pos == 0x01) { enc_flags |= (1 << 0); } else if (enc_cur_pos == 0x02) { enc_flags |= (1 << 1); } } if (enc_cur_pos == 0x03) { enc_flags |= (1 << 4); } else if (enc_cur_pos == 0x00) { if (enc_prev_pos == 0x02) { enc_flags |= (1 << 2); } else if (enc_prev_pos == 0x01) { enc_flags |= (1 << 3); } if (bit_is_set(enc_flags, 0) && (bit_is_set(enc_flags, 2) || bit_is_set(enc_flags, 4))) { enc_action = 1; } else if (bit_is_set(enc_flags, 2) && (bit_is_set(enc_flags, 0) || bit_is_set(enc_flags, 4))) { enc_action = 1; } else if (bit_is_set(enc_flags, 1) && (bit_is_set(enc_flags, 3) || bit_is_set(enc_flags, 4))) { enc_action = -1; } else if (bit_is_set(enc_flags, 3) && (bit_is_set(enc_flags, 1) || bit_is_set(enc_flags, 4))) { enc_action = -1; }
enc_flags = 0; // reset for next time } } enc_prev_pos = enc_cur_pos; if (enc_action > 0) { // RIGHT switch(mode){ case 0: default: TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_UP); TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_UP); break; case 1: TrinketHidCombo.pressKey(0, KEYCODE_PAGE_DOWN); //PAGE DOWN TrinketHidCombo.pressKey(0, 0); break; } } else if (enc_action < 0) { // LEFT switch(mode){ case 0: default: TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_DOWN); TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_DOWN); break; case 1: TrinketHidCombo.pressKey(0, KEYCODE_PAGE_UP); //PAGE UP TrinketHidCombo.pressKey(0, 0); break; } } else { TrinketHidCombo.poll(); // do nothing, check if USB needs anything done } // button button_state = digitalRead(PIN_BUTTON); if(button_state != button_state_old){ if(button_state == HIGH){ //button ON mode ++; if(mode > 1) { mode = 0; } delay(200); } else { //button OFF delay(200); } button_state_old = button_state; } }
``` # 注意点 今回使用したDigiSparkはそのままUSB端子に挿せるのですが、PCのUSB端子のバネの具合によっては、基板面が水平にならず、ノートPCのディスプレイをたたむ際にノブがぶつかってしまいます。そのため、スペーサーとなるものが必要になります。そこで、「おゆまる」というお湯でやわらかくなるプラスチックねんどを挟み込んでいます。もっとスマートな方法もあると思いますが、ひとまず手持ちのもので済ませました。 また、スイッチを活用しようとしたため、予期せぬ負荷が端子にかかることもありそうです。PCの形状に合わせて下側にもなんらかのスペーサーを付けたほうがいいと思われます。不安ならケーブル接続タイプを。 # おわりに スクロールは、アプリケーションによって動作が異なり、けっこういろいろな使い方ができます。画像処理ソフトなら拡大・縮小、動画編集ならコマ送り・コマ戻しに使えるので、思いのほか便利です。 もちろん、今回の音量やスクロールだけでなく、さまざまな機能を割り当てることができます。よく使用するアプリケーションに合わせてカスタムコントローラーを作るのはとても楽しいです。