Skip to content

Commit 3863073

Browse files
authored
Merge branch 'master' into master
2 parents 9a0ea23 + 7669d0f commit 3863073

File tree

6 files changed

+433
-53
lines changed

6 files changed

+433
-53
lines changed

CPX_Walking_Stick/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
## The Musical Walking Stick tutorial on the Adafruit Learning System
2+
3+
The code in this repo accompanies the Adafruit tutorial
4+
Musical Walking Stick
5+
https://learn.adafruit.com/musical-cane/
6+
7+
The *appropriate code file file should be copied onto the **CIRCUITPY** flash drive as **code.py** that appears
8+
when you plug the CircuitPlayground Express into your computer via a known good USB cable.
9+
10+
If the only drive name you get is named **CPLAYBOOT**, CircuitPython may not be loaded
11+
on the board. You can load CircuitPython [per this guide](https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-quickstart). Then you should be able to see the **CIRCUITPY** drive when connected via USB.
12+
13+
CircuitPython resources may be found at https://CircuitPython.Org/
14+
15+
Learning Guide by Dano Wall
16+
Code written by Dano Wall and Anne Barela for Adafruit Industries, November 2019
17+
18+
MIT License, include all this text in any redistribution
19+
20+
Support Open Source development by buying your materials at [Adafruit.com](https://www.adafruit.com/).

CPX_Walking_Stick/code.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Talking Cane
2+
# for Adafruit Circuit Playground Express with CircuitPython
3+
from adafruit_circuitplayground.express import cpx
4+
5+
# Change this number to adjust touch sensitivity threshold
6+
cpx.adjust_touch_threshold(600)
7+
# Set the tap type: 1=single, 2=double
8+
cpx.detect_taps = 1
9+
10+
# NeoPixel settings
11+
RED = (90, 0, 0)
12+
BLACK = (0, 0, 0)
13+
step_col = [RED]
14+
15+
cpx.pixels.brightness = 0.1 # set brightness value
16+
17+
# The audio file assigned to the touchpad
18+
audio_file = ["imperial_march.wav"]
19+
20+
def play_it(index):
21+
cpx.pixels.fill(step_col[index]) # Light neopixels
22+
cpx.play_file(audio_file[index]) # play audio clip
23+
print("playing file " + audio_file[index])
24+
cpx.pixels.fill(BLACK) # unlight lights
25+
26+
while True:
27+
# playback mode. Use the slide switch to change between
28+
# trigger via touch or via single tap
29+
if cpx.switch:
30+
if cpx.touch_A1:
31+
play_it(0)
32+
else:
33+
if cpx.tapped:
34+
play_it(0)

Disco_Tie/code.py

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
"""
2+
LED Disco Tie with Bluetooth
3+
=========================================================
4+
Give your suit an sound-reactive upgrade with Circuit
5+
Playground Bluefruit & Neopixels. Set color and animation
6+
mode using the Bluefruit LE Connect app.
7+
8+
Author: Collin Cunningham for Adafruit Industries, 2019
9+
"""
10+
# pylint: disable=global-statement
11+
12+
import time
13+
import array
14+
import math
15+
import audiobusio
16+
import board
17+
import neopixel
18+
from adafruit_ble.uart_server import UARTServer
19+
from adafruit_bluefruit_connect.packet import Packet
20+
from adafruit_bluefruit_connect.color_packet import ColorPacket
21+
from adafruit_bluefruit_connect.button_packet import ButtonPacket
22+
23+
uart_server = UARTServer()
24+
25+
# User input vars
26+
mode = 0 # 0=audio, 1=rainbow, 2=larsen_scanner, 3=solid
27+
user_color= (127,0,0)
28+
29+
# Audio meter vars
30+
PEAK_COLOR = (100, 0, 255)
31+
NUM_PIXELS = 10
32+
CURVE = 2
33+
SCALE_EXPONENT = math.pow(10, CURVE * -0.1)
34+
NUM_SAMPLES = 160
35+
36+
# Restrict value to be between floor and ceiling.
37+
def constrain(value, floor, ceiling):
38+
return max(floor, min(value, ceiling))
39+
40+
# Scale input_value between output_min and output_max, exponentially.
41+
def log_scale(input_value, input_min, input_max, output_min, output_max):
42+
normalized_input_value = (input_value - input_min) / \
43+
(input_max - input_min)
44+
return output_min + \
45+
math.pow(normalized_input_value, SCALE_EXPONENT) \
46+
* (output_max - output_min)
47+
48+
# Remove DC bias before computing RMS.
49+
def normalized_rms(values):
50+
minbuf = int(mean(values))
51+
samples_sum = sum(
52+
float(sample - minbuf) * (sample - minbuf)
53+
for sample in values
54+
)
55+
56+
return math.sqrt(samples_sum / len(values))
57+
58+
def mean(values):
59+
return sum(values) / len(values)
60+
61+
def volume_color(volume):
62+
return 200, volume * (255 // NUM_PIXELS), 0
63+
64+
# Set up NeoPixels and turn them all off.
65+
pixels = neopixel.NeoPixel(board.A1, NUM_PIXELS, brightness=0.1, auto_write=False)
66+
pixels.fill(0)
67+
pixels.show()
68+
69+
mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA,
70+
sample_rate=16000, bit_depth=16)
71+
72+
# Record an initial sample to calibrate. Assume it's quiet when we start.
73+
samples = array.array('H', [0] * NUM_SAMPLES)
74+
mic.record(samples, len(samples))
75+
# Set lowest level to expect, plus a little.
76+
input_floor = normalized_rms(samples) + 10
77+
# Corresponds to sensitivity: lower means more pixels light up with lower sound
78+
input_ceiling = input_floor + 500
79+
peak = 0
80+
81+
def wheel(wheel_pos):
82+
# Input a value 0 to 255 to get a color value.
83+
# The colours are a transition r - g - b - back to r.
84+
if wheel_pos < 0 or wheel_pos > 255:
85+
r = g = b = 0
86+
elif wheel_pos < 85:
87+
r = int(wheel_pos * 3)
88+
g = int(255 - wheel_pos*3)
89+
b = 0
90+
elif wheel_pos < 170:
91+
wheel_pos -= 85
92+
r = int(255 - wheel_pos*3)
93+
g = 0
94+
b = int(wheel_pos*3)
95+
else:
96+
wheel_pos -= 170
97+
r = 0
98+
g = int(wheel_pos*3)
99+
b = int(255 - wheel_pos*3)
100+
return (r, g, b)
101+
102+
def rainbow_cycle(delay):
103+
for j in range(255):
104+
for i in range(NUM_PIXELS):
105+
pixel_index = (i * 256 // NUM_PIXELS) + j
106+
pixels[i] = wheel(pixel_index & 255)
107+
pixels.show()
108+
time.sleep(delay)
109+
110+
def audio_meter(new_peak):
111+
mic.record(samples, len(samples))
112+
magnitude = normalized_rms(samples)
113+
114+
# Compute scaled logarithmic reading in the range 0 to NUM_PIXELS
115+
c = log_scale(constrain(magnitude, input_floor, input_ceiling),
116+
input_floor, input_ceiling, 0, NUM_PIXELS)
117+
118+
# Light up pixels that are below the scaled and interpolated magnitude.
119+
pixels.fill(0)
120+
for i in range(NUM_PIXELS):
121+
if i < c:
122+
pixels[i] = volume_color(i)
123+
# Light up the peak pixel and animate it slowly dropping.
124+
if c >= new_peak:
125+
new_peak = min(c, NUM_PIXELS - 1)
126+
elif new_peak > 0:
127+
new_peak = new_peak - 1
128+
if new_peak > 0:
129+
pixels[int(new_peak)] = PEAK_COLOR
130+
pixels.show()
131+
return new_peak
132+
133+
pos = 0 # position
134+
direction = 1 # direction of "eye"
135+
136+
def larsen_set(index, color):
137+
if index < 0:
138+
return
139+
else:
140+
pixels[index] = color
141+
142+
def larsen(delay):
143+
global pos
144+
global direction
145+
color_dark = (int(user_color[0]/8), int(user_color[1]/8),
146+
int(user_color[2]/8))
147+
color_med = (int(user_color[0]/2), int(user_color[1]/2),
148+
int(user_color[2]/2))
149+
150+
larsen_set(pos - 2, color_dark)
151+
larsen_set(pos - 1, color_med)
152+
larsen_set(pos, user_color)
153+
larsen_set(pos + 1, color_med)
154+
155+
if (pos + 2) < NUM_PIXELS:
156+
# Dark red, do not exceed number of pixels
157+
larsen_set(pos + 2, color_dark)
158+
159+
pixels.write()
160+
time.sleep(delay)
161+
162+
# Erase all and draw a new one next time
163+
for j in range(-2, 2):
164+
larsen_set(pos + j, (0, 0, 0))
165+
if (pos + 2) < NUM_PIXELS:
166+
larsen_set(pos + 2, (0, 0, 0))
167+
168+
# Bounce off ends of strip
169+
pos += direction
170+
if pos < 0:
171+
pos = 1
172+
direction = -direction
173+
elif pos >= (NUM_PIXELS - 1):
174+
pos = NUM_PIXELS - 2
175+
direction = -direction
176+
177+
def solid(new_color):
178+
pixels.fill(new_color)
179+
pixels.show()
180+
181+
def map_value(value, in_min, in_max, out_min, out_max):
182+
out_range = out_max - out_min
183+
in_range = in_max - in_min
184+
return out_min + out_range * ((value - in_min) / in_range)
185+
186+
speed = 6.0
187+
wait = 0.097
188+
189+
def change_speed(mod, old_speed):
190+
new_speed = constrain(old_speed + mod, 1.0, 10.0)
191+
return(new_speed, map_value(new_speed, 10.0, 0.0, 0.01, 0.3))
192+
193+
while True:
194+
# While BLE is *not* connected
195+
if not uart_server.connected:
196+
# OK to call again even if already advertising
197+
uart_server.start_advertising()
198+
199+
# While BLE is connected
200+
else:
201+
if uart_server.in_waiting:
202+
packet = Packet.from_stream(uart_server)
203+
204+
# Received ColorPacket
205+
if isinstance(packet, ColorPacket):
206+
user_color = packet.color
207+
208+
# Received ButtonPacket
209+
elif isinstance(packet, ButtonPacket):
210+
if packet.pressed:
211+
if packet.button == ButtonPacket.UP:
212+
speed, wait = change_speed(1, speed)
213+
elif packet.button == ButtonPacket.DOWN:
214+
speed, wait = change_speed(-1, speed)
215+
elif packet.button == ButtonPacket.BUTTON_1:
216+
mode = 0
217+
elif packet.button == ButtonPacket.BUTTON_2:
218+
mode = 1
219+
elif packet.button == ButtonPacket.BUTTON_3:
220+
mode = 2
221+
elif packet.button == ButtonPacket.BUTTON_4:
222+
mode = 3
223+
224+
# Determine animation based on mode
225+
if mode == 0:
226+
peak = audio_meter(peak)
227+
elif mode == 1:
228+
rainbow_cycle(0.001)
229+
elif mode == 2:
230+
larsen(wait)
231+
elif mode == 3:
232+
solid(user_color)

TFT_Gizmo_Snowglobe/snowglobe_fancy.py

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import board
33
import busio
44
import displayio
5-
from adafruit_st7789 import ST7789
5+
from adafruit_gizmo import tft_gizmo
66
import adafruit_imageload
77
import adafruit_lis3dh
88

@@ -24,20 +24,8 @@
2424
accelo_i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
2525
accelo = adafruit_lis3dh.LIS3DH_I2C(accelo_i2c, address=0x19)
2626

27-
# Display setup
28-
WIDTH = 240
29-
HEIGHT = 240
30-
displayio.release_displays()
31-
32-
spi = busio.SPI(board.SCL, MOSI=board.SDA)
33-
tft_cs = board.RX
34-
tft_dc = board.TX
35-
tft_backlight = board.A3
36-
37-
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs)
38-
39-
display = ST7789(display_bus, width=WIDTH, height=HEIGHT, rowstart=80,
40-
backlight_pin=tft_backlight, rotation=180)
27+
# Create the TFT Gizmo display
28+
display = tft_gizmo.TFT_Gizmo()
4129

4230
# Load background image
4331
try:
@@ -47,7 +35,7 @@
4735
# Or just use solid color
4836
except (OSError, TypeError):
4937
BACKGROUND = BACKGROUND if isinstance(BACKGROUND, int) else 0x000000
50-
bg_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
38+
bg_bitmap = displayio.Bitmap(display.width, display.height, 1)
5139
bg_palette = displayio.Palette(1)
5240
bg_palette[0] = BACKGROUND
5341
background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette)
@@ -71,16 +59,16 @@
7159
height = 1,
7260
tile_width = FLAKE_WIDTH,
7361
tile_height = FLAKE_HEIGHT,
74-
x = randrange(0, WIDTH),
62+
x = randrange(0, display.width),
7563
default_tile=randrange(0, NUM_SPRITES)))
7664

7765
# Snowfield setup
78-
snow_depth = [HEIGHT] * WIDTH
66+
snow_depth = [display.height] * display.width
7967
snow_palette = displayio.Palette(2)
8068
snow_palette[0] = 0xADAF00 # transparent color
8169
snow_palette[1] = SNOW_COLOR # snow color
8270
snow_palette.make_transparent(0)
83-
snow_bitmap = displayio.Bitmap(WIDTH, HEIGHT, len(snow_palette))
71+
snow_bitmap = displayio.Bitmap(display.width, display.height, len(snow_palette))
8472
snow = displayio.TileGrid(snow_bitmap, pixel_shader=snow_palette)
8573

8674
# Add everything to display
@@ -98,13 +86,13 @@ def clear_the_snow():
9886
# set to a random sprite
9987
flake[0] = randrange(0, NUM_SPRITES)
10088
# set to a random x location
101-
flake.x = randrange(0, WIDTH)
89+
flake.x = randrange(0, display.width)
10290
# set random y locations, off screen to start
103-
flake_pos = [-1.0*randrange(0, HEIGHT) for _ in range(NUM_FLAKES)]
91+
flake_pos = [-1.0*randrange(0, display.height) for _ in range(NUM_FLAKES)]
10492
# reset snow level
105-
snow_depth = [HEIGHT] * WIDTH
93+
snow_depth = [display.height] * display.width
10694
# and snow bitmap
107-
for i in range(WIDTH*HEIGHT):
95+
for i in range(display.width*display.height):
10896
snow_bitmap[i] = 0
10997
display.auto_refresh = True
11098

@@ -117,11 +105,11 @@ def add_snow(index, amount, steepness=2):
117105
# check depth to right
118106
if snow_depth[x+1] - snow_depth[x] < steepness:
119107
add = True
120-
elif x == WIDTH - 1:
108+
elif x == display.width - 1:
121109
# check depth to left
122110
if snow_depth[x-1] - snow_depth[x] < steepness:
123111
add = True
124-
elif 0 < x < WIDTH - 1:
112+
elif 0 < x < display.width - 1:
125113
# check depth to left AND right
126114
if snow_depth[x-1] - snow_depth[x] < steepness and \
127115
snow_depth[x+1] - snow_depth[x] < steepness:
@@ -138,7 +126,7 @@ def add_snow(index, amount, steepness=2):
138126
while True:
139127
clear_the_snow()
140128
# loop until globe is full of snow
141-
while snow_depth.count(0) < WIDTH:
129+
while snow_depth.count(0) < display.width:
142130
# check for shake
143131
if accelo.shake(SHAKE_THRESHOLD, 5, 0):
144132
break
@@ -153,6 +141,6 @@ def add_snow(index, amount, steepness=2):
153141
# reset flake to top
154142
flake_pos[i] = 0
155143
# at a new x location
156-
flake.x = randrange(0, WIDTH)
144+
flake.x = randrange(0, display.width)
157145
flake.y = int(flake_pos[i])
158146
display.refresh()

0 commit comments

Comments
 (0)