MicroPython(ESP32)でLS027B4DH01にMPU9250のデータを表示する
2020/08/16 categories:ESP32| tags:ESP32|MicroPython|LS027B4DH01|MPU9250|
以前作った、LCDに表示するプログラムとセンサの値を取得するプログラムを使って、LCDにセンサのデータを表示するプログラムを作成してみました。
センサの値を取得
mpu9250.pyを使用してセンサの値を取得します。値はfloatで返ってきます。
accel = mpu9250.read_accel()
gyro = mpu9250.read_gyro()
mag = mpu9250.read_magnet()
値をLCDに表示
値は下記の手順で表示しました。
- 表示データをリセット
- フォントサイズを24にセット
- 文字列(MPU9250 data)をセット
- フォントサイズを16にセット
- センサの値を0.00の桁数で表示
- 線を描画
- LCDの表示を更新
lcd.data_reset()
lcd.font_size(24)
lcd.string(5, 5, 'MPU9250 data')
lcd.font_size(16)
lcd.string(5, 100, 'x:'+'{:.2f}'.format(accel['x']) )
lcd.line(0, 58, 400, 58)
lcd.update_all_line()
動作の様子
ソースコード
フォントデータはfont_24.pyとfont_16.pyというファイル名で、PCで作成したフォントデータが書き込まれているものを使用しました。
main.py
import utime
from machine import Pin, SPI, I2C
from LS027B4DH01 import LS027B4DH01
from mpu9250 import MPU9250
def main():
# LCD
lcd = LS027B4DH01()
lcd.spi = SPI(
2, #vspi = id = 2
baudrate=10_000_000, #1MHz
polarity=0, phase=0, bits=8, firstbit=SPI.LSB,
sck=Pin(18), mosi=Pin(23), miso=Pin(19)
)
lcd.scs = Pin(32, Pin.OUT)
lcd.extcomin = Pin(33, Pin.OUT)
lcd.disp = Pin(25, Pin.OUT)
lcd.initialize()
lcd.disp.on()
lcd.font_size(16)
# Sensor
i2c = I2C(scl=Pin(21), sda=Pin(22), freq=100000)
mpu9250 = MPU9250(i2c)
mpu9250.setting(mpu9250.GFS_1000, mpu9250.AFS_16G)
lcd.string(50, 50, 'hello')
lcd.update_all_line()
utime.sleep(3)
print('initialized')
while True:
# get sensor value
accel = mpu9250.read_accel()
gyro = mpu9250.read_gyro()
mag = mpu9250.read_magnet()
# display reset
lcd.data_reset()
# display title
lcd.font_size(24)
lcd.string(5, 5, 'MPU9250 data')
# display sensor
lcd.font_size(16)
lcd.string( 5, 60, 'Accel')
lcd.string( 5, 100, 'x:'+'{:.2f}'.format(accel['x']) )
lcd.string( 5, 140, 'y:'+'{:.2f}'.format(accel['y']) )
lcd.string( 5, 180, 'z:'+'{:.2f}'.format(accel['z']) )
lcd.string(140, 60, 'GYRO')
lcd.string(140, 100, 'x:'+'{:.2f}'.format(gyro['x']) )
lcd.string(140, 140, 'y:'+'{:.2f}'.format(gyro['y']) )
lcd.string(140, 180, 'z:'+'{:.2f}'.format(gyro['z']) )
lcd.string(260, 60, 'MAG')
lcd.string(260, 100, 'x:'+'{:.2f}'.format(mag['x']) )
lcd.string(260, 140, 'y:'+'{:.2f}'.format(mag['y']) )
lcd.string(260, 180, 'z:'+'{:.2f}'.format(mag['z']) )
# display line
lcd.line( 0, 58, 400, 58)
lcd.line(130, 58, 130, 240)
lcd.line(250, 58, 250, 240)
# display update
lcd.update_all_line()
if __name__ == "__main__":
main()
LS027B4DH01.py
import utime
from font_24 import font_24
from font_16 import font_16
class LS027B4DH01():
def __init__(self):
self.scs = None
self.extcomin = None
self.disp = None
self.spi = None
self.data = bytearray( (1+1+50) * 241 + 2 )
self.font_24 = font_24
self.font_16 = font_16
self.font = self.font_24
self.byte_length = 3
self.data_reset()
def set_one_byte(self, x, y, byte):
self.data[2 + x + y * 52] = byte
def font_size(self, font_size):
if font_size == 24:
self.font = self.font_24
self.byte_length = 3
if font_size == 16:
self.font = self.font_16
self.byte_length = 2
def update_one_line(self, line, data_array):
self.scs.on()
# send mode
self.spi.write(b'\x01')
# send gate line address
self.spi.write( bytearray([line]) )
# send data
self.spi.write(data_array)
# dummy data
self.spi.write(b'\x00\x00')
self.scs.off()
def data_reset(self):
for i in range(len(self.data)):
self.data[i] = 0xFF
self.data[0] = 0x01
self.data[1] = 0x01
for i in range(2, 241):
self.data[i * 52 + 1] = i
def update_all_line(self):
self.scs.on()
utime.sleep_us(4)
self.spi.write(self.data)
utime.sleep_us(4)
self.scs.off()
utime.sleep_us(4)
def character(self, x, y, character):
font_bytearray = self.font[character]
for index, byte in enumerate(font_bytearray):
byte_number = index % self.byte_length
line_number = int(index / self.byte_length)
x2 = int(x / 8) + byte_number
y2 = (y + line_number) * 52
data_index = 2 + y2 + x2
self.data[data_index] = byte
def string(self, x, y, string):
for x2, character in enumerate(string):
self.character(x + x2 * self.byte_length * 8, y, character)
def line(self, x1, y1, x2, y2):
delta_x = abs(x2 - x1)
delta_y = abs(y2 - y1)
if delta_x == 0:
for y in range(delta_y):
self.dot(x1, y + y1)
return
a = (y2 - y1) / (x2 - x1)
if delta_x > delta_y:
x_array = [ i for i in range(x1, x2)]
y_array = [ int(a * x + y1) for x in x_array ]
else:
y_array = [ i for i in range(y1, y2)]
x_array = [ int( (y - y1) / a ) for y in y_array ]
for x, y in zip(x_array, y_array):
self.dot(x, y)
def dot(self, x, y):
index = 2 + int(x / 8) + y * 52
byte = ~self.data[index] | (1 << (x % 8))
byte = ~byte
self.data[index] = byte
def clear_all(self):
self.disp.off()
self.scs.on()
utime.sleep_us(3)
self.spi.write(b'\x04\x00')
utime.sleep_us(3)
self.scs.off()
utime.sleep_us(5)
self.disp.on()
def initialize(self):
self.disp.off()
utime.sleep_us(500)
self.scs.off()
self.clear_all()
utime.sleep_ms(5)
self.disp.on()
mpu9250.py
from micropython import const
import utime
class MPU9250():
MPU9250_ADDRESS = const(0x68)
DEVICE_ID = const(0x71)
SMPLRT_DIV = const(0x19)
CONFIG = const(0x1A)
GYRO_CONFIG = const(0x1B)
ACCEL_CONFIG = const(0x1C)
ACCEL_CONFIG_2 = const(0x1D)
LP_ACCEL_ODR = const(0x1E)
WOM_THR = const(0x1F)
FIFO_EN = const(0x23)
I2C_MST_CTRL = const(0x24)
I2C_MST_STATUS = const(0x36)
INT_PIN_CFG = const(0x37)
INT_ENABLE = const(0x38)
INT_STATUS = const(0x3A)
ACCEL_OUT = const(0x3B)
TEMP_OUT = const(0x41)
GYRO_OUT = const(0x43)
I2C_MST_DELAY_CTRL = const(0x67)
SIGNAL_PATH_RESET = const(0x68)
MOT_DETECT_CTRL = const(0x69)
USER_CTRL = const(0x6A)
PWR_MGMT_1 = const(0x6B)
PWR_MGMT_2 = const(0x6C)
FIFO_R_W = const(0x74)
WHO_AM_I = const(0x75)
GFS_250 = const(0x00)
GFS_500 = const(0x01)
GFS_1000 = const(0x02)
GFS_2000 = const(0x03)
AFS_2G = const(0x00)
AFS_4G = const(0x01)
AFS_8G = const(0x02)
AFS_16G = const(0x03)
def __init__(self, i2c, address = MPU9250_ADDRESS):
self.i2c = i2c
self.address = address
self.setting(self.GFS_250, self.AFS_2G)
self.ak8963 = AK8963(self.i2c)
def searchDevice(self):
who_am_i = self.i2c.readfrom(self.address, self.WHO_AM_I)
if(who_am_i == self.DEVICE_ID):
return True
else:
return False
def setting(self, gfs, afs):
if gfs == self.GFS_250:
self.gres = 250.0/32768.0
elif gfs == self.GFS_500:
self.gres = 500.0/32768.0
elif gfs == self.GFS_1000:
self.gres = 1000.0/32768.0
else: # gfs == GFS_2000
self.gres = 2000.0/32768.0
if afs == self.AFS_2G:
self.ares = 2.0/32768.0
elif afs == self.AFS_4G:
self.ares = 4.0/32768.0
elif afs == self.AFS_8G:
self.ares = 8.0/32768.0
else: # afs == AFS_16G:
self.ares = 16.0/32768.0
buffer = bytearray(1)
self.i2c.writeto_mem(self.address, self.PWR_MGMT_1, b'\x00') # sleep off
utime.sleep_ms(100)
self.i2c.writeto_mem(self.address, self.PWR_MGMT_1, b'\x01') # auto select clock source
utime.sleep_ms(100)
self.i2c.writeto_mem(self.address, self.CONFIG, b'\x03') # DLPF_CFG
self.i2c.writeto_mem(self.address, self.SMPLRT_DIV, b'\x04') # sample rate divider
buffer[0] = gfs << 3
self.i2c.writeto_mem(self.address, self.GYRO_CONFIG, buffer) # gyro full scale select
buffer[0] = afs << 3
self.i2c.writeto_mem(self.address, self.ACCEL_CONFIG, buffer) # accel full scale select
self.i2c.writeto_mem(self.address, self.ACCEL_CONFIG_2, b'\x03') # A_DLPFCFG
self.i2c.writeto_mem(self.address, self.INT_PIN_CFG, b'\x02') # BYPASS_EN
utime.sleep_ms(100)
def check_data_ready(self):
drdy = self.i2c.readfrom(self.address, self.INT_STATUS)
if drdy & 0x01:
return True
else:
return False
def read_accel(self):
data = self.i2c.readfrom_mem(self.address, self.ACCEL_OUT, 6)
x = self.data_convert(data[1], data[0])
y = self.data_convert(data[3], data[2])
z = self.data_convert(data[5], data[4])
x = round(x*self.ares, 3)
y = round(y*self.ares, 3)
z = round(z*self.ares, 3)
return {"x":x, "y":y, "z":z}
def read_gyro(self):
data = self.i2c.readfrom_mem(self.address, self.GYRO_OUT, 6)
x = self.data_convert(data[1], data[0])
y = self.data_convert(data[3], data[2])
z = self.data_convert(data[5], data[4])
x = round(x*self.gres, 3)
y = round(y*self.gres, 3)
z = round(z*self.gres, 3)
return {"x":x, "y":y, "z":z}
def read_magnet(self):
return self.ak8963.read_magnet()
def data_convert(self, data1, data2):
value = data1 | (data2 << 8)
if(value & (1 << 16 - 1)):
value -= (1<<16)
return value
class AK8963():
AK8963_SLAVE_ADDRESS = const(0x0C)
AK8963_ST1 = const(0x02)
AK8963_MAGNET_OUT = const(0x03)
AK8963_CNTL1 = const(0x0A)
AK8963_CNTL2 = const(0x0B)
AK8963_ASAX = const(0x10)
AK8963_MODE_DOWN = const(0x00)
AK8963_MODE_ONE = const(0x01)
AK8963_MODE_C8HZ = const(0x02)
AK8963_MODE_C100HZ = const(0x06)
AK8963_BIT_14 = const(0x00)
AK8963_BIT_16 = const(0x01)
def __init__(self, i2c, address=0x76):
self.i2c = i2c
self.address = address
self.setting(self.AK8963_MODE_C8HZ, self.AK8963_BIT_16)
def setting(self, mode, mfs):
if mfs == self.AK8963_BIT_14:
self.mres = 4912.0/8190.0
else: # mfs == AK8963_BIT_16:
self.mres = 4912.0/32760.0
self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, b'\x00')
utime.sleep_ms(10)
self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, b'\x0F') # set read FuseROM mode
utime.sleep_ms(10)
data = self.i2c.readfrom_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_ASAX, 3) # read coef data
self.magXcoef = (data[0] - 128) / 256.0 + 1.0
self.magYcoef = (data[1] - 128) / 256.0 + 1.0
self.magZcoef = (data[2] - 128) / 256.0 + 1.0
self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, b'\x00') # set power down mode
utime.sleep_ms(10)
buffer = bytearray(1)
buffer[0] = (mfs << 4 | mode)
self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, buffer) # set scale&continous mode
utime.sleep_ms(10)
def read_magnet(self):
x, y, z=0, 0, 0
data = self.i2c.readfrom_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_MAGNET_OUT, 7)
# check overflow
if (data[6] & 0x08)!=0x08:
x = self.data_convert(data[0], data[1])
y = self.data_convert(data[2], data[3])
z = self.data_convert(data[4], data[5])
x = round(x * self.mres * self.magXcoef, 3)
y = round(y * self.mres * self.magYcoef, 3)
z = round(z * self.mres * self.magZcoef, 3)
return {"x":x, "y":y, "z":z}
def data_convert(self, data1, data2):
value = data1 | (data2 << 8)
if(value & (1 << 16 - 1)):
value -= (1<<16)
return value