VSCode でマイコンをシミュレートする話

この記事は [EEIC Advent Calendar 2023](https://qiita.com/advent-calendar/2023/eeic) の14日目の記事として書かれています。

手元環境: MacBook Air (M1), macOS Ventra 13.1
ソースコードは [github](https://github.com/yuriko0505/Microcomputer_Simulator) に載せています。

## 目次
- [事の経緯](#事の経緯)
- [シミュレーション](#hello-wokwi)
    - [Lチカ](#まずはlチカ)
    - [スイッチ](#スイッチ)
    - [ブザー](#ブザー)
    - [Wi-Fi接続とディスプレイ](#Wi-Fi接続とディスプレイ)
    - [センサー類](#センサー類)
- [おわりに](#おわりに)


## 事の経緯
EEIC3年の yuimyun です。
私は今、後期実験でIoTデバイスをいじっています。
デバイスは、マイコンボード ESP One (Wifi通信モジュール ESP8266 搭載) と実験用に組まれたアプリケーションボードを組み合わせたものです。
ESP One は Arduino と互換性のあるボードで、Arduino IDE で開発が可能です。

https://www.switch-science.com/products/2620

しかしこの Arduino IDE 、なんだか使い勝手が微妙です。
また、せっかくの機会なので ESP One を買うのアリだなと思ったのですが、絶妙なお値段、、
使い慣れたエディタ[^1]でコードを書きつつ、シミュレーションまでできちゃったりしないかな〜と検索をかけました。

## Hello Wokwi

https://wokwi.com/

ありました。
Wokwi はマイコンをシミュレートするツールで、Web版・VSCode版・CLI版をサポートしています。
全ての機能が無料で利用可能で、Arduino・ESP32・STM32・Pi Pico のシミュレートが可能です。
早速遊んでみましょう！

## 準備
Wokwi を VSCode で利用するために、以下のツールが必要です:
- VSCode
- PlatformIO
- Wokwi

どれもわかりやすい導入解説記事が多数ありますので、ここでは割愛させていただきます。

シミュレーションに使うボードですが ESP One そのものは Wokwi でサポートされていません。
そこで、今回は代わりに ESP32 を使うことにします。


## まずはLチカ
Lチカとは「LED をチカチカさせること」で、マイコン界隈での Hello World です。
シミュレートするまでの手順としては、
- シミュレートに使うボードを設計する
- スケッチ(プログラムのこと)を書く
- `pio` でビルドする
- `F1`キーを押してstart simulation する

となります。
ボードの設計は `diagram.json` で部品や配線を指定していくのですが、Web版WokwiでGUIで配置してからその`diagram.json` をコピペしてくると簡単で早いと思います。
左のようなコードを書き、ビルドをしたら`F1`キーですぐにシミュレートすることができます！

:::note info
配布のプロジェクトでは、`diagram.json` の記述、実行プログラムの作成、ビルドまでを `make led` で行うようにしています。以降も同様です。
:::

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586526/9fb97c6b-ccea-c371-e787-8e64931565b3.png" width=70%>

※ ちなみに、抵抗の値もカスタマイズ可能ですが、それによってLEDの明るさが変わることはありません。

## スイッチ
次にタクトスイッチ(押しボタン)を使ってみます。
ついでに、パソコンとボードでデータをやり取りするシリアル通信もやってみましょう。
ボタンが押されたら、シリアルコンソールに今まで押された回数が出力されるようにします。
手順は先ほどと同様です。

:::note warn
シリアル通信をする際、`diagram.json` で
```
"connections": [
    [ "esp:TX", "$serialMonitor:RX", "", [] ],
    [ "esp:RX", "$serialMonitor:TX", "", [] ],
    ...
  ]
```
の設定が必要です。Arduino では特に指定することなくシリアル通信ができます。
:::

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586526/588458cf-0764-ce85-e7cc-59462decd72b.png" width=70%>

スイッチは、クリックすることで押すことができます。
コンソールに数字が出力され、ボタン押下検知もシリアル通信も上手くできていることがわかります。
ちなみに、Wokwi ではデフォルトでバウンシング（≒ チャタリング）をシミュレートするようになっています。

参考 → [wokwi-pushbutton Reference](https://docs.wokwi.com/parts/wokwi-pushbutton)

ところで、3や5が出力されるべきところで妙な文字列を吐いていますね……[^2]

## ブザー
ピンが HIGH のときにブザーON、LOW のときにブザーOFFとなるようにします。
ここで、Wokwi の数少ない注意点として、電子部品があまり充実していないという問題があります。
例えば、上記の機能を実装するためにトランジスタが必要ですが、用意されていないため Relay 回路モジュールで代替することになります。

参考 → [Relay Module Reference](https://docs.wokwi.com/parts/wokwi-relay-module)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586526/47329b98-ba05-69a7-7172-8cebb7f392db.png" width=70%>

Relay 回路に入力が入ると、モジュールの LED が緑色に点灯します。
それに合わせてブザーが実際に鳴ります。
鳴っている時に音符が飛ぶので、視覚的にもわかります。
また、`tone` 関数を使えば任意の周波数の音を出すことができます。

## Wi-Fi接続とディスプレイ
ESP シリーズは Wi-Fi に接続することが可能です。
クライアントとして、何かサーバに接続してみましょう！
ここでは NTP につないでみようと思います。
NTP(Network Time Protocol) とは、ネットワーク上のコンピュータシステム間で時刻同期させるための通信プロトコルです。
ここから時刻を取得することで、マイコンの時刻合わせができます。
そして今回は、その時刻を OLED ディスプレイに表示してみます。

Wi-Fi 通信のシミュレーションのために、Wokwi から 仮想アクセスポイント "Wokwi-GUEST" が用意されているので、接続先の Wi-Fi はここに指定します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586526/be57194f-f170-579f-9bdf-7a2b60343c5b.png" width=70%>

上手く接続できると、このように時間が表示されます。

:::note warn
Wokwi は名前解決が少々苦手なようです。
```
[WiFiUdp.cpp:172] beginPacket(): could not get host from dns: 0
```
のようなエラーが出る場合、直接 IP アドレスを指定してあげると良いです。
:::


## センサー類
Wokwi では各種センサーも用意されています。
ここでは照度(LDR)センサーと人感(PIR)センサーを紹介します。
### 照度(LDR)センサー
Wokwi の LDR センサーは抵抗値やガンマ値をカスタマイズ可能です。
シミュレーション時のデフォルト照度は 500 lux で、センサーをクリックすると表示されるスライダーで照度を変化させることができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586526/2a485c6d-8d3b-97cd-61fd-ffe4ac924739.png" width=70%>

### 人感(PIR)センサー
LDR センサー同様、センサーのパラメータの調整が可能で、感知の遅延時間や不感時間をカスタマイズできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586526/1334f346-8697-92d4-d2a8-44f26cab8da0.png" width=70%>

センサーをクリックすると `Simulate motion` というボタンが出現します。
これをクリックすることでモーションをシミュレートできます。

センサーをシミュレートする意味あるの？という気がしますが、
- アナログ値の受け取りができるか確認できる
- 入力値に対する処理後の値が妥当か確認できる
- センサーを含むスケッチを、シミュレーション用に書き換える必要がない

などのメリットがありそうです。

## おわりに
Wokwi にはここで紹介した以外にも様々な部品が用意されています。
コーディングや tex 打ち[^3]に疲れた時、マイコンと戯れて[^4]みてはいかがでしょうか？


[^1]: 私は普段 VSCode を使用していますが、Vim 派や Emacs 派も尊重しています（平和主義）。
[^2]: 好きな四字熟語は「Fizz Fizz Buzz Buzz」です。
[^3]: LaTeX で文書を作成すること。最近はTypstがアツいらしいです。
[^4]: 戯れると言えば、VSCodeの拡張機能 "vscode-pets" がおすすめです。インストールすると、VSCode の画面内にﾈｺﾁｬﾝやカニ、トトロなどが来てくれます。