MAiX Qube 奮闘記10 I2C通信でTOF距離センサーを制御

今回は秋月のレーザー測距センサモジュール（ＴｏＦ）に挑戦です。
このモジュールには　STマイクロエレクトロニクス社の　VL53L0X
(Time-of-Flight ranging sensor)が使われています。
こんな小さなチップで光が1mm進むレベルの時間が測れるなんて;;
ほんと凄い時代です。
商品はこれ

https://akizukidenshi.com/catalog/g/gM-12590
# 端子接続
レーザー測距センサモジュールの端子配置
![センサ端子配置.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/2443f455-b13d-bf31-0225-6911632c15d7.png)


端子接続(Qube 正面コネクタ)
| Sensor | QubeIO |QubeIO | Sensor |
|:-:|:-:|:-:|:-:|
|3:SDA|   IO 7 SDA|  3V3 | 1:+V  |
|  -|   IO15|  IO21 |   -|
|  -|   IO20|  IO 8 |   -|
|2:GND|   GND|   IO 6　SCL|4:SCL|

:::note warn
センサの　5:xshut、6:gpio1　は接続しませんでした。
奮闘記08 の液晶モジュールも同じI2Cバス上にいるのでこのプルアップ抵抗も生きています。
:::

![IMG_0037.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/81d6a25a-4c69-234b-1078-2556eb68500a.jpeg)

![IMG_0036.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/906a21d1-b83e-b232-fff4-0cc7b14e30b9.jpeg)

![IMG_0040.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/1bf2f229-8b4d-e9cd-ddfe-4f11cfd1e46c.jpeg)



# コード
VL53L0Xの制御コードを一から作るスキルはないので。
micropython向けに書かれたこのモジュールを使わせて頂きました。

https://github.com/uceeatz/VL53L0X/blob/975d212a33f67b4f41ae64a2bc3b65f62845e852/VL53L0X.py

上記VL53L0X.pyをMaixPy IDEのツール→ transfer file to boad を使ってQUBEへ予め転送しておきます。
そして本体画面と液晶の両方に距離を表示させるバージョンがこれ。
```python:sample1_VL53L0X.py
from machine import I2C
import utime,lcd,image,sensor
from VL53L0X import VL53L0X
def putstr(string):
    BUFF = bytearray([0x40])    #Co=0,RS=1 Data
    for char in string:
        BUFF += char
    print(BUFF)
    i2c.writeto(DEFAULT_I2C_ADDR,BUFF)
def putcmd(command):
        BUFF = bytearray([0x00,command])    #Co=0,RS=0 Control byte
        print(BUFF)
        i2c.writeto(DEFAULT_I2C_ADDR,BUFF)
def custom_char(location,charmap):
    #"""Write a character to one of the 8 CGRAM locations, available
    #as chr(0) through chr(7).
    location &= 0x07
    BUFF = bytearray([0x00,(0x40|(location << 3))])
    i2c.writeto(DEFAULT_I2C_ADDR,BUFF)
    utime.sleep_ms(50)
    BUFF = chr(0x40)  #Co=0,RS=1 Data

    for i in range(8):
        BUFF += chr(charmap[i])
    i2c.writeto(DEFAULT_I2C_ADDR,BUFF)

DEFAULT_I2C_ADDR = 0x3E
print(DEFAULT_I2C_ADDR)
i2c = I2C(I2C.I2C3, freq=300*1000, sda=7, scl=6) # cube
putcmd(0x38)#ファンクションリセット
utime.sleep_ms(5)
putcmd(0x39)#ファンクションセット
utime.sleep_ms(5)
putcmd(0x14)#発信周波数
utime.sleep_ms(5)
#液晶のコントラスト
putcmd(0x70|0x03)#コントラスト下位4ビット　デフォルト0x73
utime.sleep_ms(5)
putcmd(0x54|0x02)#コントラスト上位2ビット　デフォルト0x02
utime.sleep_ms(1)
putcmd(0x6C)
utime.sleep_ms(300)
putcmd(0x38)#ファンクションリセット
utime.sleep_ms(5)
putcmd(0x01)
utime.sleep_ms(1)
putcmd(0x0C)
utime.sleep_ms(1)
#オリジナルキャラクタの定義
happy = bytearray([0x00,0x0A,0x00,0x04,0x00,0x11,0x0E,0x00])
bell = bytearray([0x04,0x0e,0x0e,0x0e,0x1f,0x00,0x04,0x00])
custom_char(0x0,happy)
custom_char(0x1,bell)

sensor.reset(freq=22000000, dual_buff=False)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA) # 320x240
img = sensor.snapshot()
lcd.init(type=2, invert=True) # cube ips
lcd.rotation(2)
lcd.clear(36, 36, 100)
#color: The color initialized by LCD, which can be a 16-bit RGB565 color value, such as 0xFFFF
#or a tuple of RGB888, such as (236, 36, 36)
vl=VL53L0X(i2c)
vl.init()
while(True):
    Lengh = vl.read()
    print(Lengh)
    putcmd(0x80|0x40)
    putstr(str('{:2d}'.format(Lengh))+' mm   ')
    img = sensor.snapshot()
    img.clear()
    img.draw_string(65,100,(str('{:2d}'.format(Lengh))+' mm'),scale=5)
    #lcd.clear(36, 36, 100)
    #lcd.draw_string(60, 100,(str('{:2d}'.format(Lengh))+' mm'),(100,100,100),3,lcd.RED,lcd.BLACK)
    #image.draw_string(x, y, text[, color[, scale=1[, x_spacing=0[, y_spacing=0[, mono_space=True]]]]])
    lcd.display(img)
    utime.sleep_ms(200)
i2c.deinit()
```
そして本体画面のみに表示させるバージョンがこれ。(キャラクタＬＣＤ表示無し)
```python:sample2_VL53L0X.py
from machine import I2C
import utime,lcd,image,sensor
from VL53L0X import VL53L0X

sensor.reset(freq=22000000, dual_buff=False)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA) # 320x240
img = sensor.snapshot()
lcd.init(type=2, invert=True) # cube ips
lcd.rotation(2)
lcd.clear(36, 36, 100)
#color: The color initialized by LCD, which can be a 16-bit RGB565 color value, such as 0xFFFF
#or a tuple of RGB888, such as (236, 36, 36)
i2c = I2C(I2C.I2C3,mode=I2C.MODE_MASTER, freq=100000, scl=6, sda=7)
vl=VL53L0X(i2c)
vl.init()
while(True):
    Lengh = vl.read()
    print(Lengh)
    img = sensor.snapshot()
    img.clear()
    img.draw_string(65,100,(str('{:2d}'.format(Lengh))+' mm'),scale=5)
    #lcd.clear(36, 36, 100)
    #lcd.draw_string(60, 100,(str('{:2d}'.format(Lengh))+' mm'),(100,100,100),3,lcd.RED,lcd.BLACK)
    #image.draw_string(x, y, text[, color[, scale=1[, x_spacing=0[, y_spacing=0[, mono_space=True]]]]])
    lcd.display(img)
    utime.sleep_ms(200)
i2c.deinit()
```