PICA Tower(ピカ・タワー)をCircuitPythonで光らせる

この記事は[MicroPython Advent Calendar 2017](https://qiita.com/advent-calendar/2017/micropython)の24日目の投稿です。

# PICA Tower(ピカ・タワー)

12月24日なので、クリスマスっぽいものということで[PICA Tower(ピカ・タワー)](https://www.elekit.co.jp/product/AW-864)をオモチャ箱から取り出してきました。これは、イーケイジャパンと福岡県立福岡工業高等学校の、共同開発プロジェクトのもので、PICのCプログラミング教材として使うことを意図しているようです。

![IMG_4270.JPG](https://qiita-image-store.s3.amazonaws.com/0/106817/45a484e7-c222-827d-2f2d-7be05a3fe860.jpeg)

中身はキットで、たくさんのLEDと抵抗、メッキ線、ICソケットなどをはんだ付けします。けっこう面倒です。できあがったものは以下で、何ができるかといえばLチカ豪華版+CDSによる環境光検知です。

![IMG_4271.MOV.gif](https://qiita-image-store.s3.amazonaws.com/0/106817/ffc48886-fa98-150a-678a-3ae3746b032c.gif)

これをプログラミングの教材として使うための[プログラミングマニュアル](　https://www.elekit.co.jp/software/SW-1010)も用意されています。

# Arduino　M0に挿す

このキットのちょっと気がきいているのは、上のLED部と下のPIC基板部が分離可能で、しかもArduinoフォーム・ファクタに対応しているので、LED部をArduino UNOなどに挿して使えることです。ここからMicroPythonの話につなげますが、MicroPythonの派生であるAdafruit CircuitPythonがサポートしているボードにArduino Zeroがあります。手持ちのArduino M0 ProはArduino Zero Proの同等品であるので、今回はCircuitPythonを入たArduino M0でピカ。タワーを光らせてみます。

まずはLED部とPIC基板部を分離し、Arduino M0 Proを用意します。

![IMG_4275.JPG](https://qiita-image-store.s3.amazonaws.com/0/106817/e5e6e130-9804-2553-3967-634b12cb13a9.jpeg)

LED部をArduino M0 Proに挿します。何の問題もなく挿さります。

![IMG_4276.JPG](https://qiita-image-store.s3.amazonaws.com/0/106817/cf669dfa-6a6b-6f39-421d-fad1157003d7.jpeg)

# Arduino M0 ProにCircuitPythonをインストール

[CircuitPythonのリリースサイト](https://github.com/adafruit/circuitpython/releases/)からArduino Zero用のバイナリをダウンロードします。今回は2.1.0を使うことにしたので、adafruit-circuitpython-arduino_zero-2.1.0.binになります。

次にインストールツールであるBOSSAを[リリースサイト](https://github.com/shumatech/BOSSA/releases)よりダウンロードします。今回はMac OS X用1.8.0に含まれるbossacコマンドを使いました。

Aruduino M0 ProをUSBケーブルでホストコンピュータと繋いでシリアルポートを探します。Macの場合は ```/dev/tty.usb*``` あたりを調べます。今回は ```/dev/tty.usbmodemFA1441``` でした。

Arduino M0 ProのRESETボタンを二度押しするとファームの書き換えモードになるので、この状態にしたら以下でCircuitPythonをインストールします。

```bash
$ bossac -e -w -v -R -p /dev/tty.usbmodemFA1441 adafruit-circuitpython-arduino_zero-2.1.0.bin
```

以下のようにメッセージが出て、Verify successfulが出ればOKです。

```
Erase flash

Done in 0.863 seconds
Write 184276 bytes to flash (2880 pages)
[==============================] 100% (2880/2880 pages)
Done in 1.102 seconds
Verify 184276 bytes of flash
[==============================] 100% (2880/2880 pages)
Verify successful
Done in 10.457 seconds
```

# プログラミング

CircuitPython の標準モジュール構成はオリジナルのMicroPythonからかなり改変してしまっています。デジタル入出力には ```digitalio```、アナログ入出力には ```analogio```、ボードのピンの指定には ```board``` モジュールを import する必要があります。時間制御用に ```time``` もインストールしておきましょう。

```python3
import digitalio
import analogio
import board
import time
```

LEDは27個もあるので、まともに繋げたのではArduinoのデジタルピンが足りません。そのため、ピカ・タワーではLEDのアノードに9ピン、カソードに3ピンを割り当て、アノード側は各段のLEDの位置、カソード側が段を示すようにして処理します。よくあるLチカではカソード側はGNDに接続し、アノード側のON/OFFだけで点滅させますが、ピカ・タワーではアノード/カソード両方の値設定が必要です。

たとえば、一段目の２番LEDでLチカをやるには以下のようにします。

```python3
anode = digitalio.DigitalInOut(board.D4)  # D4ピンをデジタルI/Oに設定
anode.direction = digitalio.Direction.OUTPUT  # D4ピンをデジタル出力に切り替え
cathode = digitalio.DigitalInOut(board.D11)  # D11ピンをデジタルI/Oに設定
cathode.direction = digitalio.Direction.OUTPUT # D11ピンをデジタル出力に切り替え

while True:
    # 点灯
    anode.value = True
    cathode.value = False
　　　　　　　　time.sleep(0.5)
    # 消灯
    anode.value = False
    cathode.value = True
　　　　　　　　time.sleep(0.5)
```

LED部に載っているCDSの値を得るにはArduinoのA0ピンを使います。A0からアナログ入力してみて、環境光の明暗で値がどう変わるかを見てみます。

```python3
cds = analogio.AnalogIn(board.A0)  # A0 をアナログ入力に指定

while True:
    print(cds.value)  # A0 の値
    time.sleep(1.0)
```

上記を実行してみて、REPL上で値を確認すると以下のようになっていました。CDSを何かで覆うと値が65520になりました。65000の境界で明暗の判別をすればよさそうです。

```
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
main.py output:
47728
47918
48040
47987
65520
65520
65520
65520
65520
```

以上の検証結果をふまえて作成してみたCircuitPythonプログラムです。

```python3
import digitalio
import analogio
import board
import time

cds = analogio.AnalogIn(board.A0)

anodes = [
    digitalio.DigitalInOut(board.D4),
    digitalio.DigitalInOut(board.D3),
    digitalio.DigitalInOut(board.D2),
    digitalio.DigitalInOut(board.D5),
    digitalio.DigitalInOut(board.D6),
    digitalio.DigitalInOut(board.D7),
    digitalio.DigitalInOut(board.D8),
    digitalio.DigitalInOut(board.D9),
    digitalio.DigitalInOut(board.D10)]

for anode in anodes:
    anode.direction = digitalio.Direction.OUTPUT
    anode.value = False

cathodes = [
   digitalio.DigitalInOut(board.D11),
   digitalio.DigitalInOut(board.D12),
   digitalio.DigitalInOut(board.D13)]

for cathode in cathodes:
    cathode.direction = digitalio.Direction.OUTPUT
    cathode.value = True

def pattern0():
    for anode in anodes:
        anode.value = False
    for cathod in cathodes:
        cathod.value = True

def pattern1():
    for anode in anodes:
        anode.value = True
    for cathode in cathodes:
        cathode.value = False
    time.sleep(0.5)
    for cathode in cathodes:
        cathode.value = True
    time.sleep(0.5)

while True:
    pattern0()
    if cds.value < 65000:
        pattern0()
    else:
        pattern1()
```

動かしたところです。部屋を暗くすると点滅します。

![IMG_4277.MOV.gif](https://qiita-image-store.s3.amazonaws.com/0/106817/60edbb3c-9d12-9a4e-200a-73fb064d7b73.gif)