Arduinoを USB/HIDデバイス(仮想キーボード)として活用する(第二回）

##本記事について
　Arduinoを USB/HIDデバイスとして活用する第二回です。[第一回はここ](https://qiita.com/pronechia/items/b7a3722391af8e04e292)。マイコンの特徴である定時処理を作ってみました。BME280で測定した温度を Browserに定時間毎に数値表示する、リアルタイムモニターを紹介します。

2020/04/03 実行方法とソースコードの編集について説明を追加しました。
2020/04/10 ブラウザーは、Microsoft Edge,Chromeに対応しました。
##第二回）「ArduinoをUSB/HIDデバイスとした、Browserによるリアルタイムモニター」　
　Arduinoを GoodUSB として利用する例として、これからは、Browserと連携したアプリケーションに取り組みます。
今回から、マイコンはArduino互換 Adafruit Trinket M0を使用します。その理由は、複数機能を組み込む場合、 ATmega32U4では、プログラムを格納するフラッシュメモリーサイズの余裕がなくなる心配があるため、フラッシュメモリーサイズが比較的大きい、ATSAMD21G18Aを使うことにしました。ATSAMD21G18Aを使っている標準ボードは、Arduino M0がありますが、ここでは小型で比較的入手しやすい、Trinket M0 を使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592438/f21ecf0f-627a-5f75-fe57-1405d800730c.png)
##機能概要
 TrinketM0で収集した気温を文字列としてPCのブラウザーにHID/USB出力することにより気温をブラウザーに表示する、リアルタイム・モニターを実現しました。
・Setup処理
　・SWの押下を待ってWebデータのURLをHID/USB出力する。
　・所定時間後待って、Loop処理に移行
・Loop処理
　・定時間隔毎、処理を繰り返し実施
　・I2Cデバイス(BME280)から気温を取集
　・定時間隔毎に「ラベル文字列」「気温文字列」「単位文字列」をHID/USB出力
##準備するもの
　PC (Windows10) ブラウザーは、Microsoft Edge,Chrome
　Adafruit Trinket M0
　開発環境は  Windows版の Arduino IDE v1.8.9
　WebServer(任意)
##全体の仕組み
 htmlをWebサーバーに置いておく。内部のローカルサーバーでもよい。Adafruit Trinket M0には、テスト用のSWがあり、温度・湿度などを測定するBME280をI2C接続する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592438/10639b96-993e-e0b0-fb27-3696ee930b53.png)
WebServerは、WindowsPCのローカルにapacheを立てて確認しました。
##ハード構成
 Adafruit Trinket M0 周りのハード構成を示す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592438/87840e92-cbae-5f06-eec9-1ab38b8cd1b8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592438/e634b7df-65b8-d8d4-bff8-fb82ce1efa9d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592438/c03e8635-3672-eda7-8c5a-8bcff898cfbb.png)

##ソフトウエア
```ruby:apl_usbhid_TrinketM0_02Wondows.ino
/*
 *公開第二回）リアルタイムモニター
 * 2020/04/01 Windows/MAC
 * 2020/04/03 ライブラリを分離。設定説明追記
 * 2020/04/10 I2Cエラー時も動かすが値ゼロ。URL入力後、TABを出す、Chrome動作確認
 */
// WindowsPC用

//環境に合わせて内容を確認または修正すること　ーーここから -----------------------------
//①BME280 I2Cアドレスの設定　（0x76 or 0x77 のどちらか）
#define BME280DEVADDR 0x76
//#define BME280DEVADDR 0x77
//②Webserverに合わせて、ＵＲＬを記述すること
//String g_url_string = "http'//192.168.xxx.xxx/xxxxxxxx.htm"; //内部WebServer用
String g_url_string = "http'//localhost/example0201.htm"; //localhost用
//③ハード設定
#define LED_PIN 13
#define SW_PIN  1
//環境に合わせて内容を確認または修正すること　ーーここまで -----------------------------

#define WCS_DELAY_T1 150 //T1 ブラウザー応答時間150
#define WCS_DELAY_GAMEN 3000  //URLたたいてから画面が表示されるまで待つ
#include <Wire.h>
#include <ZeroTimer.h>
#include <SparkFunBME280.h>
#include "lib_keyboard.h"

BME280 mySensor;
int16_t g_pass;  //HID出力したら後の待ち時間を制御する。 pass1=20msec pass2=40msec ...
boolean g_I2CNormal;
volatile int g_i; //timerカウント
//
//
//
void setup(){  
  pinMode(LED_PIN,OUTPUT);
  pinMode(SW_PIN, INPUT_PULLUP);
  Wire.begin();
  sub_kbd_begin(1);  //Windows用に初期化
  //sub_kbd_begin(2);  //Mac用に初期化
  delay(100); //HIDデバイス、I2Cデバイスの初期化待ち
  sub_fw_Blink(LED_PIN, 3, 50); //動き始めたことを知らせる
  digitalWrite(LED_PIN, HIGH);  //明確に点灯
  mySensor.setI2CAddress(BME280DEVADDR);
  //BME280の初期化ができない場合、値ゼロで動かす
  if (mySensor.beginI2C() == false) g_I2CNormal = false;
  else                              g_I2CNormal = true;
  g_pass = 1;
  g_i = 0;
  while (sub_fw_SWcheck(SW_PIN) == 0); //SWが押されるまで待つ
  sub_fw_timerset();  //タイマー起動
}
```
環境に合わせて、以下の内容を確認または修正してください
①BME280 I2Cアドレスの設定　（0x76 or 0x77 のどちらか有効にすること）
　//#define BME280DEVADDR 0x76
　//#define BME280DEVADDR 0x77

②Webserverに合わせて、ＵＲＬを記述すること
　//String g_url_string = "http'//192.168.xxx.xxx/xxxxxxxx.htm"; //内部WebServer用
　//String g_url_string = "http'//localhost/example0201.htm"; //localhost用

③ハード設定が間違いないか確認
　LED_PIN 13
　SW_PIN  1

```ruby:loop処理
//
//main loop
//
void loop(){

  // 40msec毎に処理を行う
  if (sub_fw_event(2)) sub_proc();
}
//
//USB/HID処理
//
void sub_proc() {
  static byte s_command = 0; //処理振り分け
  static byte s_first = 0;
  
  //待ち時間がゼロになるまで何もしない。
  if (g_pass-- >= 0 ) return;
  //処理振り分け
  if (s_command == 0) { 
    s_command = 1;
    s_first = 1;
    sub_initurl(); //一回だけ実施
  } else if (s_command == 1) { 
    s_command = 2;
    sub_out_kbd(10);  //start
  } else if (s_command == 2) {
    sub_out_kbd(11); //センサー値UP
    s_command = 1; //繰り返し
  } else {
    ; //その他は何もしない。
  }
  //次への待ち時間設定
  if (s_command == 1) {
    if (s_first == 1) {
      g_pass = 50; //40msec*50= 2sec
      s_first = 0;
    } else {
      g_pass = 200; //40msec*200= 8sec    
    }
  } else {
    g_pass = 25; //40msec*25= 1sec
  }
}
（以下、省略。ソースコードを参照ください）
```
　ソースコードは、[GitHub](https://github.com/pronechia/apl_usbhid_TrinketM0_02)から取り出すことができます。 Windows用とMac用にわかれています。各フォルダー内のすべてのファイルを同一フォルダに保存して、Arduino IDE でコンパイルしてください。
注意）
・BME280のI2Cアドレスが間違った場合は、LEDが点滅し、先に進みません。
・ツール／ボードの設定は、 Adafruit Trinket M0 です。
・サンプルのHTMLファイルは、htmlフォルダにあります。
##実行
 準備
・WebServerが使えて、PCと接続できていること。
　WindowsPCのapacheを立てることが簡単かと思います。（下記参考欄）
・既定のブラウザーは、Microsoft Edge または、Chromeになっていること。
・WindowsPCの入力モードは、英数字である必要があります。日本語モードになっていないことを確認してください。
1.PCに Adafruit Trinket M0 をUSB接続し、SW押下で動き出す

2.Windowsキー  + ‘r’　でcmd窓を開き、URL文字列を入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592438/f201f337-54fe-1434-a778-998902d29810.png)
3.定時間隔で以下を繰り返す
・ ‘Start’ + Tab + Enterを入力する
・ラベル + Tab + 測定した温度 + Tab + 単位  + Tab + Enter　を入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592438/88a7ccae-d0f7-1687-6c0c-93b84a4f2288.png)

##まとめ
 ArduinoをUSB/HIDデバイスとして、Browserによるリアルタイムモニターが確認できた。マイコン制御としての基本的な仕組みを確認するため、次回は Browserから  Arduinoへの下り電文に挑戦します。
##参考
WindowsPCにapacheを立てる場合の例は、以下を参考にしました。
　https://www.adminweb.jp/apache/install/

Trinket M０の開発環境については、以下を参考にしました。
　https://www.denshi.club/cookbook/arduino/trinketm0/trinket-m01arduino-ide.html

２つのライブラリが必要です。以下を参考にしました。
　・ZeroTimer.h
　　　https://ehbtj.com/electronics/arduino-zero-timer-interrupt-library/
　・SparkFunBME280.h
　　　BME280のライブラリーは豊富にでているので、GitHubなどで探してみてください。