ArduinoでUSB接続のPC音量調整ボタンを作る方法

## 本記事について
Arduinoという、手軽にマイコンを使った電子工作ができる、マイコン機器開発ボードがあります。
本記事では、そのArduinoを使って、PCの音量を大・小・消音できる、USB接続の音量調整ボタンの作り方についてまとめました。

## 使用するArduino
Arduinoには色々な種類があるのですが、「ATmega32U4」というマイコンを搭載した「Arduino Micro」を使います。
ATmega32U4はUBSを扱う機能が備わっていて、ArduinoでUSB機器を作ることができます。

## 回路図
回路は単純で、ピン7・8・9をGNDにつなぐボタンがあり、それぞれのボタンが、PCの音量を大・小・消音にするボタンになります。

![VolumeControlButton_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/100574/db5faa02-84f1-c4c3-46ba-ea14222593c2.png)

続いてプログラム手順に入る前に、HIDというものについて簡単に説明します。

## HIDについて
USBを使ってどんな機器を作るかは開発者の自由なのですが、マウスやキーボードなどのよく使われるUSB機器は、HID（Human Interface Device）として予めUSBの規格で定義されています。

HID機器のデバイスドライバーはPCのOSに標準で入っているので、HID機器はどのPCでもつなぐだけで、追加のプログラムをインストールすることなしに使うことができます。

幸い音量調整ボタンもHIDで定義されているので、今回はそちらのHID機器として音量調整ボタンを作成しました。


## 音量調整ボタンのHIDについて
音量調整ボタンは、HIDでは「キーボード」ではなく、「コンシューマーコントロール」という別カテゴリーの機能扱いになるので、ArduinoにあるUSBキーボードのライブラリを使って、音量調整ボタンを押すということはできません。

また、キーボードやマウスのライブラリはArduinoのIDE（Arduinoの開発ツール）に入っているのですが、コンシューマーコントロールのライブラリはないので、他のライブラリを参考にしながら、別途実装する必要があります。

では、具体的なプログラム手順に入ります。

## プログラム手順
### メインプログラム（スケッチ）
下記メインプログラムを任意の名前で作成します。

```cpp:VolumeControlButton.ino
#include "ConsumerControl.h"

u8 previousButtonState = 1;  // 連打防止フラグ

void setup() {
  pinMode(7, INPUT_PULLUP);  // 音量大にするピン7
  pinMode(8, INPUT_PULLUP);  // 音量小にするピン8
  pinMode(9, INPUT_PULLUP);  // 音量消音にするピン9
}

void loop() {
  if(digitalRead(7)==LOW){
    ConsumerControl.press(VOLUME_UP); // 音量大ボタンを押す
    ConsumerControl.release(); // ボタンを離す
    delay(100);

  } else if(digitalRead(8)==LOW){
    ConsumerControl.press(VOLUME_DOWN); // 音量小ボタンを押す
    ConsumerControl.release(); // ボタンを離す
    delay(100);

  } else if(digitalRead(9)==LOW){
    if(previousButtonState==0){
      ConsumerControl.press(VOLUME_MUTE);  // 音量消音ボタンを押す
      previousButtonState = 1;

    } else {
      ConsumerControl.release(); // ボタンを離す
      previousButtonState = 1;
    }
  }else {
    if(previousButtonState==1){
      ConsumerControl.release(); // ボタンを離す
      previousButtonState = 0;
    }
  }
}
```

### コンシューマーコントロールプログラム
下記の「ConsumerControl.h」「ConsumerControl.cpp」を、上記のメインプログラムと同じフォルダに置きます。

```cpp:ConsumerControl.h
#include "HID.h"

#define REPORT_ID 1
#define VOLUME_UP 0
#define VOLUME_DOWN 1
#define VOLUME_MUTE 2

class ConsumerControl_
{
public:
  ConsumerControl_(void);
  void press(u8 buttonBit);
  void release(void);
};

extern ConsumerControl_ ConsumerControl;
```

```cpp:ConsumerControl.cpp
#include "ConsumerControl.h"

static const uint8_t _hidReportDescriptor[] PROGMEM = {
  0x05, 0x0c, // USAGE_PAGE (Consumer)
  0x09, 0x01, // USAGE (Consumer Control)
  0xa1, 0x01, // COLLECTION (Application)
  0x85, REPORT_ID, // REPORT_ID (X)
  0x15, 0x00, // LOGICAL_MINIMUM (0)
  0x25, 0x01, // LOGICAL_MAXIMUM (1)
  0x09, 0xe9, // USAGE (Volume Increment)
  0x09, 0xea, // USAGE (Volume Decrement)
  0x09, 0xe2, // USAGE (Mute)
  0x75, 0x01, // REPORT_SIZE (1)
  0x95, 0x03, // REPORT_COUNT (3)
  0x81, 0x02, // INPUT (Data,Var,Abs)
  0x75, 0x01, // REPORT_SIZE (1)
  0x95, 0x05, // REPORT_COUNT (5)
  0x81, 0x03, // INPUT (Const,Var,Abs)
  0xC0 //   END_COLLECTION
};

ConsumerControl_::ConsumerControl_(void)
{
  static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
  HID().AppendDescriptor(&node);
}

void ConsumerControl_::press(u8 buttonBit)
{
  u8 m[1];
  m[0]=(1 << buttonBit);
  HID().SendReport(REPORT_ID, m, sizeof(m));
}

void ConsumerControl_::release()
{
  u8 m[1];
  m[0]=0;
  HID().SendReport(REPORT_ID, m, sizeof(m));
}

ConsumerControl_ ConsumerControl;
```

## 実行
後は、ArduinoのIDEでプログラム（スケッチ）をコンパイルしてAdruinoに転送して書き込めば、USB接続のPC音量調整ボタンができあがります。

書き込んだプログラムはArduinoをPCから外しても永続するので、Arduinoを他のPCに挿しても音量調整ボタンとして認識されて使うことができます。

## 応用
メインプログラムの中で、音量調整を行っている部分は

- ``ConsumerControl.press(＜ボタン名＞)``で「ボタン名」の音量調整ボタンを押す
- ``ConsumerControl.release()``で全ての音量調整ボタンを解除

だけですので、メインプログラムを書き換えて、好みのPC音量調整機器を作ることもできます。

また、HIDは1つのUSB機器に対して複数持つことも可能なため、キーボードのライブラリと組み合わせて、音量調整もできるキーボードを作ることも可能かと思います。

## 元記事
- [ArduinoでUSB接続のPC音量調整ボタンを作る方法](https://www.kwbtblog.com/entry/2018/12/17/054646)