PicoBoy - Treiber für - ACC Sensor

technische Daten wie beim RPi Pico
MC RP2040 mit OLED-Display 128x64 Pixel

Anleitung für die Firmware CircuitPython 9.x.x



Hardware

- PicoBoy
- USB-A zu USB-C Kabel

Software

- ACC-library my_stk8ba58.py

Der Beschleunigungssensor beim PicoBoy ist laut Hersteller ein 3-Achsen ACC-Sensor STK8BA58. Leider konnte ich dafür unter CircuitPython keinen Treiber finden und musste mir also, genau wie beim runden LCD-Display von Waveshare, etwas einfallen lassen. Was heißt das? Erste Erkenntnis der Chip ist über I2C mit SDA - GPIO 20 und SCL - GPIO 21 angebunden. Wenn man den Bus scannt, bekommt man die Ausgabe, dass der i2c-Bus auf Addresse 0x18 liegt. Ein Blick in die class PicoBoy(SH1106) in der Micropython-Datei 'picoboy.py' zeigt mir die dort verwendeten Variablenamen, die ich für meinen Treiber übernehme, der damit so aussieht:

  
  

1  # SPDX-FileCopyrightText: 2024 Detlef Gebhardt, written for CircuitPython
2  # SPDX-FileCopyrightText: Copyright (c) 2024 Detlef Gebhardt
3  # SPDX-FileCopyrightText: based on a PicoBoy template in Micropython
4  #
5  # SPDX-License-Identifier: GEBMEDIA
6  import board
7  import busio
8  import time
9  from adafruit_bus_device.i2c_device import I2CDevice
10
11 class STK8BA58:
12     def __init__(self):
13         global device, DEV_ADDR, sda, scl, XOUT1, YOUT1, ZOUT1
14         DEV_ADDR = 0x18    # STK8BA58
15         sda=board.GP20
16         scl=board.GP21
17         XOUT1  = 0x02
18         YOUT1  = 0x04
19         ZOUT1  = 0x06
20         i2c = busio.I2C(scl=scl, sda=sda, frequency = 400000)
21         device = I2CDevice(i2c, DEV_ADDR)
22         while not i2c.try_lock():
23             pass
24
25     def xAcc(self):
26         device.write(bytes([XOUT1]))
27         data = bytearray(2)
28         device.readinto(data)
29         value = int(data[0] / 16) + data[1] * 16
30         if value >= 2048:
31             value = value-4096
32         return value/1024
33
34     def yAcc(self):
35         device.write(bytes([YOUT1]))
36         data = bytearray(2)
37         device.readinto(data)
38         value = int(data[0] / 16) + data[1] * 16
39         if value >= 2048:
40             value = value-4096
41         return value/1024
42
43     def zAcc(self):
44         device.write(bytes([ZOUT1]))
45         data = bytearray(2)
46         device.readinto(data)
47         value = int(data[0] / 16) + data[1] * 16
48         if value >= 2048:
49             value = value-4096
50         return value/1024
51
52 if __name__=='__main__':
53     #do nothing
54     pass
  

Kopieren Sie den Quellcode in Ihre Thonny-IDE und speichern ihn im 'lib-Ordner' unter dem Namen my_stk8ba58.py ab, damit er bei der späteren Programmausführung benutzt werden kann.

Los gehts

Es kann jetzt ein erster Test mit dem Beschleunigungssensor erfolgen. Zunächst wird das Display initialisiert und eine Textausgabe definiert. Für die Funktion des Sensors wird in Zeile 10 'my_stk8ba58' importiert. Der Sensor selbst wird in Zeile 36 mit sensor=my_stk8ba58.STK8BA58() definiert. Das kann so in jedem Programm, welches den ACC-Sensor beim PicoBoy nutzen soll, geschehen.

  
  

1  import time
2  import board
3  import busio
4  import displayio
5  import digitalio
6  import terminalio
7  import fourwire
8  from adafruit_display_text import label
9  import adafruit_displayio_sh1106
10 import my_stk8ba58
11
12 # Compatibility with both CircuitPython 8.x.x and 9.x.x.
13 # Remove after 8.x.x is no longer a supported release.
14 try:
15     from fourwire import FourWire
16 except ImportError:
17     from displayio import FourWire
18
19 # built-in a display
20 displayio.release_displays()
21 # Make the displayio SPI bus and the sh1106 display
22 spi = busio.SPI(board.GP18, board.GP19)
23 #
24 # Circuit 8.x.x
25 #display_bus = displayio.FourWire(spi, command=board.GP8, chip_select=board.GP10, reset=board.GP9, baudrate=1000000)
26 #display =adafruit_displayio_sh1106.SH1106(display_bus, width=132, height=64, rotation=0, brightness = 1)
27 #
28 # Circuit 9.x.x
29 display_bus = FourWire(spi, command=board.GP8, chip_select=board.GP10, reset=board.GP9, baudrate=1000000)
30 display =adafruit_displayio_sh1106.SH1106(display_bus, width=132, height=64, rotation=0, brightness = 1)
31 # Make the display context
32 splash = displayio.Group()
33 display.root_group = splash
34
35 # ACC-Sensor initialisieren
36 sensor=my_stk8ba58.STK8BA58()
37
38 # create the label
39 updating_label = label.Label(font=terminalio.FONT, text="Systemstart", scale=2, color=0xffffff, line_spacing=0.9)
40 updating_label.anchor_point = (0, 0)
41 updating_label.anchored_position = (1, 1)
42 splash.append(updating_label)
43
44 while True:
45     #read STK8BA58
46     val_1=sensor.xAcc()
47     val_2=sensor.yAcc()
48     val_3=sensor.zAcc()
49     wert_x = int(val_1 * 100)/10
50     wert_y = int(val_2 * 100)/10
51     wert_z = int(val_3 * 100)/10
52     updating_label.text = "x_acc="+str(wert_x)+"\ny_acc="+str(wert_y)+"\nz_acc="+str(wert_z)
53     time.sleep(0.5)
54
  

Geholt werden die Werte für xAcc, yAcc und zAcc ab Zeile 45 in der 'while-Schleife'. Sie werden in gerundeter Form den Variablen wert_x, wert_y und wert_z zugewiesen und alle 0.5 Sekunden auf dem Display ausgegeben. Bewegt man nun das Display in verschiedenen Richtungen, sieht man, wie sich die Werte ändern. 'It works !!'

Zum Abschluss noch eine kleine Zugabe, welche eine kleine Kugel auf dem Bildschirm hin- und herbewegt und in ein Loch versenkt werden muss. Mehr wird an dieser Stelle mal noch nicht verraten. Probieren Sie es einfach aus, indem Sie den Quellcode in die Thonny-IDE kopieren und als code.py speichern. So kann das kleine Beispiel auch ohne den Rechner mit externer Spannungsquelle oder bei eingelegter Knopfzelle durch Betätigen des Schalters 'gespielt' werden.

  
  

1  import time
2  import board
3  import busio
4  import displayio
5  import digitalio
6  import terminalio
7  import fourwire
8  from adafruit_display_text import label
9  from adafruit_display_shapes.circle import Circle
10 import adafruit_displayio_sh1106
11 import my_stk8ba58
12 import random
13 import pwmio
14
15 # Compatibility with both CircuitPython 8.x.x and 9.x.x.
16 # Remove after 8.x.x is no longer a supported release.
17 try:
18     from fourwire import FourWire
19 except ImportError:
20     from displayio import FourWire
21
22 # built-in a display
23 displayio.release_displays()
24 # Make the displayio SPI bus and the sh1106 display
25 spi = busio.SPI(board.GP18, board.GP19)
26 #
27 # Circuit 8.x.x
28 #display_bus = displayio.FourWire(spi, command=board.GP8, chip_select=board.GP10, reset=board.GP9, baudrate=1000000)
29 #display =adafruit_displayio_sh1106.SH1106(display_bus, width=132, height=64, rotation=0, brightness = 1)
30 #
31 # Circuit 9.x.x
32 display_bus = FourWire(spi, command=board.GP8, chip_select=board.GP10, reset=board.GP9, baudrate=1000000)
33 display =adafruit_displayio_sh1106.SH1106(display_bus, width=132, height=64, rotation=0, brightness = 1)
34 # Make the display context
35 splash = displayio.Group()
36 display.root_group = splash
37
38 # ACC-Sensor initialisieren
39 sensor=my_stk8ba58.STK8BA58()
40
41 led_red = pwmio.PWMOut(board.GP7)
42 points=0
43 # create the label
44 updating_label = label.Label(font=terminalio.FONT, text="Punkte: " + str(points), scale=1, color=0xffffff, line_spacing=0.9)
45 updating_label.anchor_point = (0, 0)
46 updating_label.anchored_position = (35, 1)
47 splash.append(updating_label)
48
49 def pos_hole(x_hole,y_hole):
50     global hole
51     x_hole = random.randint(5,122)
52     y_hole = random.randint(5,58)
53     hole=[x_hole, y_hole]
54     circle_hole.x = x_hole
55     circle_hole.y = y_hole
56
57
58 xpos = 66
59 ypos = 32
60 x_hole = 0
61 y_hole = 0
62 circle_hole = Circle(x_hole, y_hole, 3,fill=0x000000, outline=0xffffff)
63 splash.append(circle_hole)
64 circle = Circle(xpos, ypos, 2,fill=0xffffff, outline=0x000000)
65 splash.append(circle)
66
67 hole=[0,0]
68 pos_hole(x_hole,y_hole)
69 print(hole)
70
71 while True:
72     #read STK8BA58
73     val_1=sensor.xAcc()
74     val_2=sensor.yAcc()
75     #val_3=sensor.zAcc()
76     wert_x = int(val_1 * 100)/10
77     wert_y = int(val_2 * 100)/10
78     if wert_y > 1 and xpos>=4:
79         xpos -= 3
80     if wert_y < -1 and xpos<=122:
81         xpos += 3
82     if wert_x > 1 and ypos<=56:
83         ypos +=2
84     if wert_x <-1 and ypos>=2:
85         ypos -=2
86     circle.x = xpos
87     circle.y = ypos
88     if abs(xpos-hole[0])<3 and abs(ypos - hole[1])<3:
89         #print(abs(xpos-hole[0]),", ",abs(ypos - hole[1]))
90         circle_hole.fill=0xffffff
91         points+=5
92         updating_label.text = "Punkte: " + str(points)
93         for i in range(3):
94             for cycle in range(0, 65535, +2):  # Cycles through the full PWM range from 0 to 65535
95                 led_red.duty_cycle = cycle  # Cycles the LED pin duty cycle through the range of values
96             for cycle in range(65534, 0, -2):  # Cycles through the PWM range backwards from 65534 to 0
97                 led_red.duty_cycle = cycle  # Cycles the LED pin duty cycle through the range of values
98         circle_hole.fill=0x000000
99         pos_hole(x_hole,y_hole)
100    time.sleep(0.1)
  



Viel Spass und Erfolg beim Ausprobieren.