MicroPython(ESP32)でLS027B4DH01にMPU9250のデータを表示する

Share on:

以前作った、LCDに表示するプログラムセンサの値を取得するプログラムを使って、LCDにセンサのデータを表示するプログラムを作成してみました。

センサの値を取得

mpu9250.pyを使用してセンサの値を取得します。値はfloatで返ってきます。

1accel = mpu9250.read_accel()
2gyro = mpu9250.read_gyro()
3mag = mpu9250.read_magnet()

値をLCDに表示

値は下記の手順で表示しました。

  • 表示データをリセット
  • フォントサイズを24にセット
  • 文字列(MPU9250 data)をセット
  • フォントサイズを16にセット
  • センサの値を0.00の桁数で表示
  • 線を描画
  • LCDの表示を更新
1lcd.data_reset()
2lcd.font_size(24)
3lcd.string(5, 5, 'MPU9250 data')
4lcd.font_size(16)
5lcd.string(5, 100, 'x:'+'{:.2f}'.format(accel['x']) )
6lcd.line(0, 58, 400, 58)
7lcd.update_all_line()

動作の様子

ソースコード

フォントデータはfont_24.pyとfont_16.pyというファイル名で、PCで作成したフォントデータが書き込まれているものを使用しました。

main.py

 1import utime
 2from machine import Pin, SPI, I2C
 3from LS027B4DH01 import LS027B4DH01
 4from mpu9250 import MPU9250
 5
 6def main():
 7    
 8    # LCD
 9    lcd = LS027B4DH01()
10    lcd.spi = SPI(
11        2, #vspi = id = 2
12        baudrate=10_000_000, #1MHz
13        polarity=0, phase=0, bits=8, firstbit=SPI.LSB,
14        sck=Pin(18), mosi=Pin(23), miso=Pin(19)
15    )
16    lcd.scs      = Pin(32, Pin.OUT)
17    lcd.extcomin = Pin(33, Pin.OUT)
18    lcd.disp     = Pin(25, Pin.OUT)
19    lcd.initialize()
20    lcd.disp.on()
21    lcd.font_size(16)
22
23    # Sensor
24    i2c = I2C(scl=Pin(21), sda=Pin(22), freq=100000)
25    mpu9250 = MPU9250(i2c)
26    mpu9250.setting(mpu9250.GFS_1000, mpu9250.AFS_16G)
27
28    lcd.string(50, 50, 'hello')
29    lcd.update_all_line()
30    utime.sleep(3)
31
32    print('initialized')
33
34    while True:
35        
36        # get sensor value
37        accel = mpu9250.read_accel()
38        gyro = mpu9250.read_gyro()
39        mag = mpu9250.read_magnet()
40
41        # display reset
42        lcd.data_reset()
43
44        # display title
45        lcd.font_size(24)
46        lcd.string(5, 5, 'MPU9250 data')
47
48        # display sensor
49        lcd.font_size(16)
50        lcd.string(  5,  60, 'Accel')
51        lcd.string(  5, 100, 'x:'+'{:.2f}'.format(accel['x']) )
52        lcd.string(  5, 140, 'y:'+'{:.2f}'.format(accel['y']) )
53        lcd.string(  5, 180, 'z:'+'{:.2f}'.format(accel['z']) )
54        
55        lcd.string(140,  60, 'GYRO')
56        lcd.string(140, 100, 'x:'+'{:.2f}'.format(gyro['x']) )
57        lcd.string(140, 140, 'y:'+'{:.2f}'.format(gyro['y']) )
58        lcd.string(140, 180, 'z:'+'{:.2f}'.format(gyro['z']) )
59        
60        lcd.string(260,  60, 'MAG')
61        lcd.string(260, 100, 'x:'+'{:.2f}'.format(mag['x']) )
62        lcd.string(260, 140, 'y:'+'{:.2f}'.format(mag['y']) )
63        lcd.string(260, 180, 'z:'+'{:.2f}'.format(mag['z']) )
64        
65        # display line
66        lcd.line(  0,  58, 400,  58)
67        lcd.line(130,  58, 130, 240)
68        lcd.line(250,  58, 250, 240)
69
70        # display update
71        lcd.update_all_line()
72
73if __name__ == "__main__":
74    main()

LS027B4DH01.py

  1import utime
  2from font_24 import font_24
  3from font_16 import font_16
  4
  5class LS027B4DH01():
  6    def __init__(self):
  7        self.scs = None
  8        self.extcomin = None
  9        self.disp = None
 10        self.spi = None
 11        self.data = bytearray( (1+1+50) * 241 + 2 )
 12        self.font_24 = font_24
 13        self.font_16 = font_16
 14        self.font = self.font_24
 15        self.byte_length = 3
 16
 17        self.data_reset()
 18
 19    def set_one_byte(self, x, y, byte):
 20        self.data[2 + x + y * 52] = byte
 21
 22    def font_size(self, font_size):
 23        if font_size == 24:
 24            self.font = self.font_24
 25            self.byte_length = 3
 26        if font_size == 16:
 27            self.font = self.font_16
 28            self.byte_length = 2
 29
 30    def update_one_line(self, line, data_array):
 31        self.scs.on()
 32        # send mode
 33        self.spi.write(b'\x01')
 34        # send gate line address
 35        self.spi.write( bytearray([line]) )
 36        # send data
 37        self.spi.write(data_array)
 38        # dummy data
 39        self.spi.write(b'\x00\x00')
 40        self.scs.off()
 41
 42    def data_reset(self):
 43        for i in range(len(self.data)):
 44            self.data[i] = 0xFF
 45        self.data[0] = 0x01
 46        self.data[1] = 0x01
 47        for i in range(2, 241):
 48            self.data[i * 52 + 1] = i
 49        
 50    def update_all_line(self):
 51        self.scs.on()
 52        utime.sleep_us(4)
 53        self.spi.write(self.data)
 54        utime.sleep_us(4)
 55        self.scs.off()
 56        utime.sleep_us(4)
 57
 58    def character(self, x, y, character):
 59        font_bytearray = self.font[character]
 60
 61        for index, byte in enumerate(font_bytearray):
 62            byte_number = index % self.byte_length
 63            line_number = int(index / self.byte_length)
 64            x2 = int(x / 8) + byte_number
 65            y2 = (y + line_number) * 52
 66            data_index = 2 + y2 + x2
 67            self.data[data_index] = byte
 68
 69    def string(self, x, y, string):
 70        for x2, character in enumerate(string):
 71            self.character(x + x2 * self.byte_length * 8, y, character)
 72
 73    def line(self, x1, y1, x2, y2):
 74        delta_x = abs(x2 - x1)
 75        delta_y = abs(y2 - y1)
 76
 77        if delta_x == 0:
 78            for y in range(delta_y):
 79                self.dot(x1, y + y1)
 80            return
 81        
 82        a = (y2 - y1) / (x2 - x1)
 83
 84        if delta_x > delta_y:
 85            x_array = [ i for i in range(x1, x2)]
 86            y_array = [ int(a * x + y1) for x in x_array ]
 87        else:
 88            y_array = [ i for i in range(y1, y2)]
 89            x_array = [ int( (y - y1) / a ) for y in y_array ]
 90
 91        for x, y in zip(x_array, y_array):
 92            self.dot(x, y)
 93
 94    def dot(self, x, y):
 95        index = 2 + int(x / 8) + y * 52
 96        byte = ~self.data[index] | (1 << (x % 8))
 97        byte = ~byte
 98        self.data[index] = byte
 99
100    def clear_all(self):
101        self.disp.off()
102        self.scs.on()
103        utime.sleep_us(3)
104        self.spi.write(b'\x04\x00')
105        utime.sleep_us(3)
106        self.scs.off()
107        utime.sleep_us(5)
108        self.disp.on()
109
110    def initialize(self):
111        self.disp.off()
112        utime.sleep_us(500)
113        self.scs.off()
114        self.clear_all()
115        utime.sleep_ms(5)
116        self.disp.on()

mpu9250.py

  1from micropython import const
  2import utime
  3
  4class MPU9250():
  5    MPU9250_ADDRESS = const(0x68)
  6    DEVICE_ID       = const(0x71)
  7
  8    SMPLRT_DIV     = const(0x19)
  9    CONFIG         = const(0x1A)
 10    GYRO_CONFIG    = const(0x1B)
 11    ACCEL_CONFIG   = const(0x1C)
 12    ACCEL_CONFIG_2 = const(0x1D)
 13    LP_ACCEL_ODR   = const(0x1E)
 14    WOM_THR        = const(0x1F)
 15    FIFO_EN        = const(0x23)
 16    I2C_MST_CTRL   = const(0x24)
 17    I2C_MST_STATUS = const(0x36)
 18    INT_PIN_CFG    = const(0x37)
 19    INT_ENABLE     = const(0x38)
 20    INT_STATUS     = const(0x3A)
 21    ACCEL_OUT      = const(0x3B)
 22    TEMP_OUT       = const(0x41)
 23    GYRO_OUT       = const(0x43)
 24
 25    I2C_MST_DELAY_CTRL = const(0x67)
 26    SIGNAL_PATH_RESET  = const(0x68)
 27    MOT_DETECT_CTRL    = const(0x69)
 28    USER_CTRL          = const(0x6A)
 29    PWR_MGMT_1         = const(0x6B)
 30    PWR_MGMT_2         = const(0x6C)
 31    FIFO_R_W           = const(0x74)
 32    WHO_AM_I           = const(0x75)
 33
 34    GFS_250  = const(0x00)
 35    GFS_500  = const(0x01)
 36    GFS_1000 = const(0x02)
 37    GFS_2000 = const(0x03)
 38    AFS_2G   = const(0x00)
 39    AFS_4G   = const(0x01)
 40    AFS_8G   = const(0x02)
 41    AFS_16G  = const(0x03)
 42
 43    def __init__(self, i2c, address = MPU9250_ADDRESS):
 44        self.i2c = i2c
 45        self.address = address
 46        self.setting(self.GFS_250, self.AFS_2G)
 47        self.ak8963 = AK8963(self.i2c)
 48
 49    def searchDevice(self):
 50        who_am_i = self.i2c.readfrom(self.address, self.WHO_AM_I)
 51        if(who_am_i == self.DEVICE_ID):
 52            return True
 53        else:
 54            return False
 55
 56    def setting(self, gfs, afs):
 57        if gfs == self.GFS_250:
 58            self.gres = 250.0/32768.0
 59        elif gfs == self.GFS_500:
 60            self.gres = 500.0/32768.0
 61        elif gfs == self.GFS_1000:
 62            self.gres = 1000.0/32768.0
 63        else:  # gfs == GFS_2000
 64            self.gres = 2000.0/32768.0
 65
 66        if afs == self.AFS_2G:
 67            self.ares = 2.0/32768.0
 68        elif afs == self.AFS_4G:
 69            self.ares = 4.0/32768.0
 70        elif afs == self.AFS_8G:
 71            self.ares = 8.0/32768.0
 72        else: # afs == AFS_16G:
 73            self.ares = 16.0/32768.0
 74
 75        buffer = bytearray(1)
 76        self.i2c.writeto_mem(self.address, self.PWR_MGMT_1, b'\x00') # sleep off
 77        utime.sleep_ms(100)
 78        self.i2c.writeto_mem(self.address, self.PWR_MGMT_1, b'\x01') # auto select clock source
 79        utime.sleep_ms(100)
 80        self.i2c.writeto_mem(self.address, self.CONFIG, b'\x03') # DLPF_CFG
 81        self.i2c.writeto_mem(self.address, self.SMPLRT_DIV, b'\x04') # sample rate divider
 82        buffer[0] = gfs << 3
 83        self.i2c.writeto_mem(self.address, self.GYRO_CONFIG, buffer) # gyro full scale select
 84        buffer[0] = afs << 3
 85        self.i2c.writeto_mem(self.address, self.ACCEL_CONFIG, buffer) # accel full scale select
 86        self.i2c.writeto_mem(self.address, self.ACCEL_CONFIG_2, b'\x03') # A_DLPFCFG
 87        self.i2c.writeto_mem(self.address, self.INT_PIN_CFG, b'\x02') # BYPASS_EN
 88        utime.sleep_ms(100)
 89
 90    def check_data_ready(self):
 91        drdy = self.i2c.readfrom(self.address, self.INT_STATUS)
 92        if drdy & 0x01:
 93            return True
 94        else:
 95            return False
 96            
 97    def read_accel(self):
 98        data = self.i2c.readfrom_mem(self.address, self.ACCEL_OUT, 6)
 99        x = self.data_convert(data[1], data[0])
100        y = self.data_convert(data[3], data[2])
101        z = self.data_convert(data[5], data[4])
102
103        x = round(x*self.ares, 3)
104        y = round(y*self.ares, 3)
105        z = round(z*self.ares, 3)
106
107        return {"x":x, "y":y, "z":z}
108
109    def read_gyro(self):
110        data = self.i2c.readfrom_mem(self.address, self.GYRO_OUT, 6)
111
112        x = self.data_convert(data[1], data[0])
113        y = self.data_convert(data[3], data[2])
114        z = self.data_convert(data[5], data[4])
115
116        x = round(x*self.gres, 3)
117        y = round(y*self.gres, 3)
118        z = round(z*self.gres, 3)
119
120        return {"x":x, "y":y, "z":z}
121
122    def read_magnet(self):
123        return self.ak8963.read_magnet()
124
125    def data_convert(self, data1, data2):
126        value = data1 | (data2 << 8)
127        if(value & (1 << 16 - 1)):
128            value -= (1<<16)
129        return value
130
131class AK8963():
132    AK8963_SLAVE_ADDRESS = const(0x0C)
133    AK8963_ST1           = const(0x02)
134    AK8963_MAGNET_OUT    = const(0x03)
135    AK8963_CNTL1         = const(0x0A)
136    AK8963_CNTL2         = const(0x0B)
137    AK8963_ASAX          = const(0x10)
138    AK8963_MODE_DOWN     = const(0x00)
139    AK8963_MODE_ONE      = const(0x01)
140    AK8963_MODE_C8HZ     = const(0x02)
141    AK8963_MODE_C100HZ   = const(0x06)
142    AK8963_BIT_14        = const(0x00)
143    AK8963_BIT_16        = const(0x01)
144
145    def __init__(self, i2c, address=0x76):
146        self.i2c = i2c
147        self.address = address
148        self.setting(self.AK8963_MODE_C8HZ, self.AK8963_BIT_16)
149
150    def setting(self, mode, mfs):
151        if mfs == self.AK8963_BIT_14:
152            self.mres = 4912.0/8190.0
153        else: #  mfs == AK8963_BIT_16:
154            self.mres = 4912.0/32760.0
155
156        self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, b'\x00')
157        utime.sleep_ms(10)
158        self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, b'\x0F') # set read FuseROM mode
159        utime.sleep_ms(10)
160        data = self.i2c.readfrom_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_ASAX, 3) # read coef data
161
162        self.magXcoef = (data[0] - 128) / 256.0 + 1.0
163        self.magYcoef = (data[1] - 128) / 256.0 + 1.0
164        self.magZcoef = (data[2] - 128) / 256.0 + 1.0
165
166        self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, b'\x00') # set power down mode
167        utime.sleep_ms(10)
168        buffer = bytearray(1)
169        buffer[0] = (mfs << 4 | mode)
170        self.i2c.writeto_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_CNTL1, buffer) # set scale&continous mode
171        utime.sleep_ms(10)
172
173    def read_magnet(self):
174        x, y, z=0, 0, 0
175        
176        data = self.i2c.readfrom_mem(self.AK8963_SLAVE_ADDRESS, self.AK8963_MAGNET_OUT, 7)
177
178        # check overflow
179        if (data[6] & 0x08)!=0x08:
180            x = self.data_convert(data[0], data[1])
181            y = self.data_convert(data[2], data[3])
182            z = self.data_convert(data[4], data[5])
183
184            x = round(x * self.mres * self.magXcoef, 3)
185            y = round(y * self.mres * self.magYcoef, 3)
186            z = round(z * self.mres * self.magZcoef, 3)
187
188        return {"x":x, "y":y, "z":z}
189
190    def data_convert(self, data1, data2):
191        value = data1 | (data2 << 8)
192        if(value & (1 << 16 - 1)):
193            value -= (1<<16)
194        return value

関連記事