Compare commits

..

2 commits

Author SHA1 Message Date
Phillip Burgess
d5bf35da48 Update pylint settings, remove unused import time 2021-07-06 10:20:28 -07:00
Phillip Burgess
827423399b Update to use CPy7 keypad module, put "no macros" error on display rather than print 2021-07-06 10:09:41 -07:00
6314 changed files with 76860 additions and 1121007 deletions

View file

@ -1,134 +0,0 @@
name: Arduino Library CI
on:
workflow_dispatch:
pull_request:
push:
jobs:
check-if-needed:
runs-on: ubuntu-latest
outputs:
answer: ${{ steps.is-needed.outputs.answer }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check if run by adabot
id: check-cron
run: |
iscron=false
[[ "${{ github.event_name }}" == "push" && "${{ github.actor }}" == "adafruit-adabot" ]] && iscron=true
echo "status=$iscron" >> "$GITHUB_OUTPUT"
- name: Check if dispatched
id: check-dispatch
run: |
isdispatch=false
[[ "${{ github.event_name }}" == "workflow_dispatch" ]] && isdispatch=true
echo "status=$isdispatch" >> "$GITHUB_OUTPUT"
- name: Check for Arduino file updates
id: check-updated
if: ${{ steps.check-cron.outputs.status }} == false && ${{ steps.check-dispatch.outputs.status }} == false
run: |
changedfiles=$(git diff --name-only -r HEAD^1 HEAD)
ischanged=false
for changedfile in ${changedfiles[*]}; do
echo $changedfile
if [[ $changedfile == *.c ]] ||
[[ $changedfile == *.cpp ]] ||
[[ $changedfile == *.h ]] ||
[[ $changedfile == *.hpp ]] ||
[[ $changedfile == *.ino ]] ||
[[ $changedfile == *.yml ]]; then
ischanged=true
break
fi
done
echo "status=$ischanged" >> "$GITHUB_OUTPUT"
- name: Output Arduino needed
id: is-needed
run: |
isneeded=false
if [[ ${{ steps.check-cron.outputs.status }} == true ]] ||
[[ ${{ steps.check-dispatch.outputs.status }} == true ]] ||
[[ ${{ steps.check-updated.outputs.status }} == true ]]; then
isneeded=true
fi
echo "answer=$isneeded" >> "$GITHUB_OUTPUT"
arduino:
strategy:
fail-fast: false
matrix:
arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_esp32c6", "feather_m0_express", "feather_m4_express", "feather_rp2040", "feather_rp2040_adalogger", "feather_rp2350", "flora", "fruit_jam_tinyusb", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "ledglasses_nrf52840", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "metro_rp2350", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "pixeltrinkey_m0", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pycamera_s3", "pygamer", "pyportal", "qualia_s3_rgb666", "qt2040_trinkey", "qtpy_m0", "qtpy_esp32s2", "rotarytrinkey_m0", "sht4xtrinkey_m0", "slidetrinkey_m0", "trinket_5v", "trinket_m0", "uno"]
runs-on: ubuntu-latest
if: needs.check-if-needed.outputs.answer == 'true'
needs: check-if-needed
steps:
- uses: actions/setup-python@v5
with:
python-version: "3.x"
# Checkout the learn repo itself
- uses: actions/checkout@v4
# Checkout the CI scripts
- uses: actions/checkout@v4
with:
repository: adafruit/ci-arduino
path: ci
- name: pre-install
run: bash ci/actions_install.sh
# manually install some libraries
- name: extra libraries
run: |
git clone --quiet https://github.com/adafruit/Cryptosuite.git /home/runner/Arduino/libraries/Cryptosuite
git clone --quiet https://github.com/adafruit/WiFiNINA.git /home/runner/Arduino/libraries/WiFiNINA
git clone --quiet https://github.com/adafruit/Adafruit_LSM303.git /home/runner/Arduino/libraries/Adafruit_LSM303
git clone --quiet https://github.com/moderndevice/CapSense.git /home/runner/Arduino/libraries/CapSense
git clone --quiet https://github.com/PaintYourDragon/ffft.git /home/runner/Arduino/libraries/ffft
git clone --quiet https://github.com/adafruit/RadioHead.git /home/runner/Arduino/libraries/RadioHead
git clone --quiet https://github.com/me-no-dev/ESPAsyncTCP /home/runner/Arduino/libraries/ESPAsyncTCP
git clone --quiet https://github.com/adafruit/Talkie /home/runner/Arduino/libraries/Talkie
git clone --quiet https://github.com/Infineon/arduino-optiga-trust-m /home/runner/Arduino/libraries/arduinoOptigaTrustM
git clone --quiet https://github.com/adafruit/HID /home/runner/Arduino/libraries/HID_Project
rm -rf /home/runner/Arduino/libraries/ArduinoHttpClient
git clone --quiet https://github.com/arduino-libraries/ArduinoHttpClient.git /home/runner/Arduino/libraries/ArduinoHttpClient
git clone --quiet https://github.com/pschatzmann/ESP32-A2DP /home/runner/Arduino/libraries/ESP32-A2DP
git clone --quiet https://github.com/pschatzmann/arduino-audio-tools /home/runner/Arduino/libraries/arduino-audio-tools
- name: test platforms
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.repository.name }}.${{ github.sha }}
path: |
build/*.hex
build/*.bin
build/*.uf2
- name: Zip release files
if: startsWith(github.ref, 'refs/tags/')
run: |
if [ -d build ]; then
(
echo "Built from Adafruit Learning System Guides `git describe --tags` for ${{ matrix.arduino-platform }}"
echo "Source code: https://github.com/adafruit/"
echo "Adafruit Learning System: https://learn.adafruit.com/"
) > build/README.txt
cd build && zip -9 -o ${{ matrix.arduino-platform }}.zip *.hex *.bin *.uf2 *.txt
fi
- name: Create release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: build/${{ matrix.arduino-platform }}.zip
fail_on_unmatched_files: false
body: "Select the zip file corresponding to your board from the list below."

View file

@ -1,35 +1,60 @@
name: SPDX and Pylint
name: Arduino Library CI
on: [pull_request, push, repository_dispatch]
jobs:
spdx:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Checkout Current Repo
uses: actions/checkout@v4
arduino:
strategy:
fail-fast: false
matrix:
arduino-platform: ["uno", "nrf52832", "cpx_ada", "pyportal", "protrinket_3v", "protrinket_5v", "metro_m0", "esp8266", "esp32", "trinket_3v", "trinket_5v", "gemma", "flora", "feather32u4", "feather_m0_express", "gemma_m0", "trinket_m0", "hallowing_m0", "monster_m4sk", "hallowing_m4", "hallowing_m4_tinyusb", "neotrellis_m4", "pybadge", "cpb", "cpc", "funhouse", "magtag"]
runs-on: ubuntu-18.04
steps:
- uses: actions/setup-python@v2
with:
python-version: '3.8'
- uses: actions/checkout@v2
- uses: actions/checkout@v2
with:
repository: adafruit/ci-arduino
path: ci
- name: pre-install
run: bash ci/actions_install.sh
# manually install some libraries
- name: extra libraries
run: |
git clone --quiet https://github.com/adafruit/Cryptosuite.git /home/runner/Arduino/libraries/Cryptosuite
git clone --quiet https://github.com/adafruit/WiFiNINA.git /home/runner/Arduino/libraries/WiFiNINA
git clone --quiet https://github.com/adafruit/Adafruit_LSM303.git /home/runner/Arduino/libraries/Adafruit_LSM303
git clone --quiet https://github.com/moderndevice/CapSense.git /home/runner/Arduino/libraries/CapSense
git clone --quiet https://github.com/PaintYourDragon/ffft.git /home/runner/Arduino/libraries/ffft
git clone --quiet https://github.com/adafruit/RadioHead.git /home/runner/Arduino/libraries/RadioHead
git clone --quiet https://github.com/me-no-dev/ESPAsyncTCP /home/runner/Arduino/libraries/ESPAsyncTCP
git clone --quiet https://github.com/adafruit/Talkie /home/runner/Arduino/libraries/Talkie
- name: test platforms
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
- name: check SPDX licensing
run: python ./SPDX.py
pylint:
runs-on: ubuntu-latest
steps:
- name: Set up Python 3.10
uses: actions/setup-python@v5
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: "3.10"
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Pip install pylint
- name: Pip install pylint, black, & Sphinx
run: |
pip install --force-reinstall pylint==2.7.1
pip install --force-reinstall pylint==1.9.2
- name: Checkout Current Repo
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: lint
run: ./pylint_check.sh

View file

@ -8,25 +8,24 @@ on:
branches: [main]
concurrency:
group: folder-images-concurrency # https://github.com/adafruit/Adafruit_Learning_System_Guides/issues/2327
group: folder-images
cancel-in-progress: true
jobs:
update-images:
if: github.repository_owner == 'adafruit'
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v4
- uses: actions/checkout@v2.2.0
- name: Set up Python 3.x
uses: actions/setup-python@v5
- name: Set up Python 3.9
uses: actions/setup-python@v1
with:
python-version: "3.x"
python-version: 3.9
- name: Checkout screenshot maker
run: git clone --depth=1 https://github.com/circuitpython/CircuitPython_Library_Screenshot_Maker
@ -50,3 +49,4 @@ jobs:
git add *.png index.html
git remote add origin https://${GITHUB_ACTOR}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
if git commit -m"update images"; then git push -f origin HEAD:folder-images; fi

1
.gitignore vendored
View file

@ -5,4 +5,3 @@ Hue_Controller/secrets.h
CircuitPython_Logger/secrets\.py
.python-version
__pycache__
*.swp

View file

@ -1 +0,0 @@
Anne Barela <mydigitalhome@gmail.com>

View file

@ -52,7 +52,7 @@ confidence=
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=too-many-instance-attributes,len-as-condition,too-few-public-methods,anomalous-backslash-in-string,no-else-return,simplifiable-if-statement,too-many-arguments,duplicate-code,no-name-in-module,no-member,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,missing-docstring,invalid-name,bad-whitespace,consider-using-enumerate,unexpected-keyword-arg,consider-using-f-string,unspecified-encoding
disable=too-many-instance-attributes,len-as-condition,too-few-public-methods,anomalous-backslash-in-string,no-else-return,simplifiable-if-statement,too-many-arguments,duplicate-code,no-name-in-module,no-member,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,missing-docstring,invalid-name,bad-whitespace,consider-using-enumerate,unexpected-keyword-arg
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
@ -72,7 +72,7 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
msg-template='{path}:{line}: {msg} ({symbol})'
msg-template='{path} {line}: {msg} ({symbol})'
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg

View file

@ -1,622 +0,0 @@
// SPDX-FileCopyrightText: 2023 Phil B. for Adafruit Industries
// SPDX-License-Identifier: MIT
// Basic full-color PicoDVI test. Provides a 16-bit color video framebuffer to
// which Adafruit_GFX calls can be made. It's based on the EYESPI_Test.ino sketch.
#include <PicoDVI.h> // Core display & graphics library
#include <Fonts/FreeSansBold18pt7b.h> // A custom font
// Here's how a 320x240 16-bit color framebuffer is declared. Double-buffering
// is not an option in 16-bit color mode, just not enough RAM; all drawing
// operations are shown as they occur. Second argument is a hardware
// configuration -- examples are written for Adafruit Feather RP2040 DVI, but
// that's easily switched out for boards like the Pimoroni Pico DV (use
// 'pimoroni_demo_hdmi_cfg') or Pico DVI Sock ('pico_sock_cfg').
DVIGFX16 display(DVI_RES_320x240p60, adafruit_dvibell_cfg);
// A 400x240 mode is possible but pushes overclocking even higher than
// 320x240 mode. SOME BOARDS MIGHT SIMPLY NOT BE COMPATIBLE WITH THIS.
// May require selecting QSPI div4 clock (Tools menu) to slow down flash
// accesses, may require further over-volting the CPU to 1.25 or 1.3 V.
//DVIGFX16 display(DVI_RES_400x240p60, adafruit_feather_dvi_cfg);
void setup() { // Runs once on startup
if (!display.begin()) { // Blink LED if insufficient RAM
pinMode(LED_BUILTIN, OUTPUT);
for (;;) digitalWrite(LED_BUILTIN, (millis() / 500) & 1);
}
}
#define PAUSE 2000 // Delay (milliseconds) between examples
uint8_t rotate = 0; // Current screen orientation (0-3)
#define CORNER_RADIUS 0
void loop() {
// Each of these functions demonstrates a different Adafruit_GFX concept:
show_shapes();
show_charts();
show_basic_text();
show_char_map();
show_custom_text();
show_bitmap();
show_canvas();
if (++rotate > 3) rotate = 0; // Cycle through screen rotations 0-3
display.setRotation(rotate); // Takes effect on next drawing command
}
// BASIC SHAPES EXAMPLE ----------------------------------------------------
void show_shapes() {
// Draw outlined and filled shapes. This demonstrates:
// - Enclosed shapes supported by GFX (points & lines are shown later).
// - Adapting to different-sized displays, and to rounded corners.
const int16_t cx = display.width() / 2; // Center of screen =
const int16_t cy = display.height() / 2; // half of width, height
int16_t minor = min(cx, cy); // Lesser of half width or height
// Shapes will be drawn in a square region centered on the screen. But one
// particular screen -- rounded 240x280 ST7789 -- has VERY rounded corners
// that would clip a couple of shapes if drawn full size. If using that
// screen type, reduce area by a few pixels to avoid drawing in corners.
if (CORNER_RADIUS > 40) minor -= 4;
const uint8_t pad = 5; // Space between shapes is 2X this
const int16_t size = minor - pad; // Shapes are this width & height
const int16_t half = size / 2; // 1/2 of shape size
display.fillScreen(0); // Start by clearing the screen; color 0 = black
// Draw outline version of basic shapes: rectangle, triangle, circle and
// rounded rectangle in different colors. Rather than hardcoded numbers
// for position and size, some arithmetic helps adapt to screen dimensions.
display.drawRect(cx - minor, cy - minor, size, size, 0xF800);
display.drawTriangle(cx + pad, cy - pad, cx + pad + half, cy - minor,
cx + minor - 1, cy - pad, 0x07E0);
display.drawCircle(cx - pad - half, cy + pad + half, half, 0x001F);
display.drawRoundRect(cx + pad, cy + pad, size, size, size / 5, 0xFFE0);
delay(PAUSE);
// Draw same shapes, same positions, but filled this time.
display.fillRect(cx - minor, cy - minor, size, size, 0xF800);
display.fillTriangle(cx + pad, cy - pad, cx + pad + half, cy - minor,
cx + minor - 1, cy - pad, 0x07E0);
display.fillCircle(cx - pad - half, cy + pad + half, half, 0x001F);
display.fillRoundRect(cx + pad, cy + pad, size, size, size / 5, 0xFFE0);
delay(PAUSE);
} // END SHAPE EXAMPLE
// CHART EXAMPLES ----------------------------------------------------------
void show_charts() {
// Draw some graphs and charts. GFX library doesn't handle these as native
// object types, but it only takes a little code to build them from simple
// shapes. This demonstrates:
// - Drawing points and horizontal, vertical and arbitrary lines.
// - Adapting to different-sized displays.
// - Graphics being clipped off edge.
// - Use of negative values to draw shapes "backward" from an anchor point.
// - C technique for finding array size at runtime (vs hardcoding).
display.fillScreen(0); // Clear screen
const int16_t cx = display.width() / 2; // Center of screen =
const int16_t cy = display.height() / 2; // half of width, height
const int16_t minor = min(cx, cy); // Lesser of half width or height
const int16_t major = max(cx, cy); // Greater of half width or height
// Let's start with a relatively simple sine wave graph with axes.
// Draw graph axes centered on screen. drawFastHLine() and drawFastVLine()
// need fewer arguments than normal 2-point line drawing shown later.
display.drawFastHLine(0, cy, display.width(), 0x0210); // Dark blue
display.drawFastVLine(cx, 0, display.height(), 0x0210);
// Then draw some tick marks along the axes. To keep this code simple,
// these aren't to any particular scale, but a real program may want that.
// The loop here draws them from the center outward and pays no mind
// whether the screen is rectangular; any ticks that go off-screen will
// be clipped by the library.
for (uint8_t i=1; i<=10; i++) {
// The Arduino map() function scales an input value (e.g. "i") from an
// input range (0-10 here) to an output range (0 to major-1 here).
// Very handy for making graphics adjust to different screens!
int16_t n = map(i, 0, 10, 0, major - 1); // Tick offset relative to center point
display.drawFastVLine(cx - n, cy - 5, 11, 0x210);
display.drawFastVLine(cx + n, cy - 5, 11, 0x210);
display.drawFastHLine(cx - 5, cy - n, 11, 0x210);
display.drawFastHLine(cx - 5, cy + n, 11, 0x210);
}
// Then draw sine wave over this using GFX drawPixel() function.
for (int16_t x=0; x<display.width(); x++) { // Each column of screen...
// Note the inverted Y axis here (cy-value rather than cy+value)
// because GFX, like most graphics libraries, has +Y heading down,
// vs. classic Cartesian coords which have +Y heading up.
int16_t y = cy - (int16_t)(sin((x - cx) * 0.05) * (float)minor * 0.5);
display.drawPixel(x, y, 0xFFFF);
}
delay(PAUSE);
// Next, let's draw some charts...
// NOTE: some other examples in this code take extra steps to avoid placing
// anything off in the rounded corners of certain displays. The charts do
// not. It's *possible* but would introduce a lot of complexity into code
// that's trying to show the basics. We'll leave the clipped charts here as
// a teachable moment: not all content suits all displays.
// A list of data to plot. These are Y values only; X assumed equidistant.
const uint8_t data[] = { 31, 42, 36, 58, 67, 88 }; // Percentages, 0-100
const uint8_t num_points = sizeof data / sizeof data[0]; // Length of data[] list
display.fillScreen(0); // Clear screen
display.setFont(); // Use default (built-in) font
display.setTextSize(2); // and 2X size for chart label
// Chart label is centered manually; 144 is the width in pixels of
// "Widget Sales" at 2X scale (12 chars * 6 px * 2 = 144). A later example
// shows automated centering based on string.
display.setCursor((display.width() - 144) / 2, 0);
display.print(F("Widget Sales")); // F("string") is in program memory, not RAM
// The chart-drawing code is then written to skip the top 20 rows where
// this label is located.
// First, a line chart, connecting the values point-to-point:
// Draw a grid of lines to provide scale & an interesting background.
for (uint8_t i=0; i<11; i++) {
int16_t x = map(i, 0, 10, 0, display.width() - 1); // Scale grid X to screen
display.drawFastVLine(x, 20, display.height(), 0x001F);
int16_t y = map(i, 0, 10, 20, display.height() - 1); // Scale grid Y to screen
display.drawFastHLine(0, y, display.width(), 0x001F);
}
// And then draw lines connecting data points. Load up the first point...
int16_t prev_x = 0;
int16_t prev_y = map(data[0], 0, 100, display.height() - 1, 20);
// Then connect lines to each subsequent point...
for (uint8_t i=1; i<num_points; i++) {
int16_t new_x = map(i, 0, num_points - 1, 0, display.width() - 1);
int16_t new_y = map(data[i], 0, 100, display.height() - 1, 20);
display.drawLine(prev_x, prev_y, new_x, new_y, 0x07FF);
prev_x = new_x;
prev_y = new_y;
}
// For visual interest, let's add a circle around each data point. This is
// done in a second pass so the circles are always drawn "on top" of lines.
for (uint8_t i=0; i<num_points; i++) {
int16_t x = map(i, 0, num_points - 1, 0, display.width() - 1);
int16_t y = map(data[i], 0, 100, display.height() - 1, 20);
display.drawCircle(x, y, 5, 0xFFFF);
}
delay(PAUSE);
// Then a bar chart of the same data...
// Erase the old chart but keep the label at top.
display.fillRect(0, 20, display.width(), display.height() - 20, 0);
// Just draw the Y axis lines; bar chart doesn't really need X lines.
for (uint8_t i=0; i<11; i++) {
int16_t y = map(i, 0, 10, 20, display.height() - 1);
display.drawFastHLine(0, y, display.width(), 0x001F);
}
int bar_width = display.width() / num_points - 4; // 2px pad to either side
for (uint8_t i=0; i<num_points; i++) {
int16_t x = map(i, 0, num_points, 0, display.width()) + 2; // Left edge of bar
int16_t height = map(data[i], 0, 100, 0, display.height() - 20);
// Some GFX functions (rects, H/V lines and similar) can accept negative
// width/height values. What this does is anchor the shape at the right or
// bottom coordinate (rather than the usual left/top) and draw back from
// there, hence the -height here (bar is anchored at bottom of screen):
display.fillRect(x, display.height() - 1, bar_width, -height, 0xFFE0);
}
delay(PAUSE);
} // END CHART EXAMPLES
// TEXT ALIGN FUNCTIONS ----------------------------------------------------
// Adafruit_GFX only handles left-aligned text. This is normal and by design;
// it's a rare need that would further strain AVR by incurring a ton of extra
// code to properly handle, and some details would confuse. If needed, these
// functions give a fair approximation, with the "gotchas" that multi-line
// input won't work, and this operates only as a println(), not print()
// (though, unlike println(), cursor X does not reset to column 0, instead
// returning to initial column and downward by font's line spacing). If you
// can work with those constraints, it's a modest amount of code to copy
// into a project. Or, if your project only needs one or two aligned strings,
// simply use getTextBounds() for a bounding box and work from there.
// DO NOT ATTEMPT TO MAKE THIS A GFX-NATIVE FEATURE, EVERYTHING WILL BREAK.
typedef enum { // Alignment options passed to functions below
GFX_ALIGN_LEFT,
GFX_ALIGN_CENTER,
GFX_ALIGN_RIGHT
} GFXalign;
// Draw text aligned relative to current cursor position. Arguments:
// gfx : An Adafruit_GFX-derived type (e.g. display or canvas object).
// str : String to print (as a char *).
// align : One of the GFXalign values declared above.
// GFX_ALIGN_LEFT is normal left-aligned println() behavior.
// GFX_ALIGN_CENTER prints centered on cursor pos.
// GFX_ALIGN_RIGHT prints right-aligned to cursor pos.
// Cursor advances down one line a la println(). Column is unchanged.
void print_aligned(Adafruit_GFX &gfx, const char *str,
GFXalign align = GFX_ALIGN_LEFT) {
uint16_t w, h;
int16_t x, y, cursor_x, cursor_x_save;
cursor_x = cursor_x_save = gfx.getCursorX();
gfx.getTextBounds(str, 0, gfx.getCursorY(), &x, &y, &w, &h);
if (align == GFX_ALIGN_RIGHT) cursor_x -= w;
else if (align == GFX_ALIGN_CENTER) cursor_x -= w / 2;
//gfx.drawRect(cursor_x, y, w, h, 0xF800); // Debug rect
gfx.setCursor(cursor_x - x, gfx.getCursorY()); // Center/right align
gfx.println(str);
gfx.setCursor(cursor_x_save, gfx.getCursorY()); // Restore cursor X
}
// Equivalent function for strings in flash memory (e.g. F("Foo")). Body
// appears identical to above function, but with C++ overloading it it works
// from flash instead of RAM. Any changes should be made in both places.
void print_aligned(Adafruit_GFX &gfx, const __FlashStringHelper *str,
GFXalign align = GFX_ALIGN_LEFT) {
uint16_t w, h;
int16_t x, y, cursor_x, cursor_x_save;
cursor_x = cursor_x_save = gfx.getCursorX();
gfx.getTextBounds(str, 0, gfx.getCursorY(), &x, &y, &w, &h);
if (align == GFX_ALIGN_RIGHT) cursor_x -= w;
else if (align == GFX_ALIGN_CENTER) cursor_x -= w / 2;
//gfx.drawRect(cursor_x, y, w, h, 0xF800); // Debug rect
gfx.setCursor(cursor_x - x, gfx.getCursorY()); // Center/right align
gfx.println(str);
gfx.setCursor(cursor_x_save, gfx.getCursorY()); // Restore cursor X
}
// Equivalent function for Arduino Strings; converts to C string (char *)
// and calls corresponding print_aligned() implementation.
void print_aligned(Adafruit_GFX &gfx, const String &str,
GFXalign align = GFX_ALIGN_LEFT) {
print_aligned(gfx, const_cast<char *>(str.c_str()));
}
// TEXT EXAMPLES -----------------------------------------------------------
// This section demonstrates:
// - Using the default 5x7 built-in font, including scaling in each axis.
// - How to access all characters of this font, including symbols.
// - Using a custom font, including alignment techniques that aren't a normal
// part of the GFX library (uses functions above).
void show_basic_text() {
// Show text scaling with built-in font.
display.fillScreen(0);
display.setFont(); // Use default font
display.setCursor(0, CORNER_RADIUS); // Initial cursor position
display.setTextSize(1); // Default size
display.println(F("Standard built-in font"));
display.setTextSize(2);
display.println(F("BIG TEXT"));
display.setTextSize(3);
// "BIGGER TEXT" won't fit on narrow screens, so abbreviate there.
display.println((display.width() >= 200) ? F("BIGGER TEXT") : F("BIGGER"));
display.setTextSize(2, 4);
display.println(F("TALL and"));
display.setTextSize(4, 2);
display.println(F("WIDE"));
delay(PAUSE);
} // END BASIC TEXT EXAMPLE
void show_char_map() {
// "Code Page 437" is a name given to the original IBM PC character set.
// Despite age and limited language support, still seen in small embedded
// settings as it has some useful symbols and accented characters. The
// default 5x7 pixel font of Adafruit_GFX is modeled after CP437. This
// function draws a table of all the characters & explains some issues.
// There are 256 characters in all. Draw table as 16 rows of 16 columns,
// plus hexadecimal row & column labels. How big can each cell be drawn?
const int cell_size = min(display.width(), display.height()) / 17;
if (cell_size < 8) return; // Screen is too small for table, skip example.
const int total_size = cell_size * 17; // 16 cells + 1 row or column label
// Set up for default 5x7 font at 1:1 scale. Custom fonts are NOT used
// here as most are only 128 characters to save space (the "7b" at the
// end of many GFX font names means "7 bits," i.e. 128 characters).
display.setFont();
display.setTextSize(1);
// Early Adafruit_GFX was missing one symbol, throwing off some indices!
// But fixing the library would break MANY existing sketches that relied
// on the degrees symbol and others. The default behavior is thus "broken"
// to keep older code working. New code can access the CORRECT full CP437
// table by calling this function like so:
display.cp437(true);
display.fillScreen(0);
const int16_t x = (display.width() - total_size) / 2; // Upper left corner of
int16_t y = (display.height() - total_size) / 2; // table centered on screen
if (y >= 4) { // If there's a little extra space above & below, scoot table
y += 4; // down a few pixels and show a message centered at top.
display.setCursor((display.width() - 114) / 2, 0); // 114 = pixel width
display.print(F("CP437 Character Map")); // of this message
}
const int16_t inset_x = (cell_size - 5) / 2; // To center each character within cell,
const int16_t inset_y = (cell_size - 8) / 2; // compute X & Y offset from corner.
for (uint8_t row=0; row<16; row++) { // 16 down...
// Draw row and columm headings as hexadecimal single digits. To get the
// hex value for a specific character, combine the left & top labels,
// e.g. Pi symbol is row E, column 3, thus: display.print((char)0xE3);
display.setCursor(x + (row + 1) * cell_size + inset_x, y + inset_y);
display.print(row, HEX); // This actually draws column labels
display.setCursor(x + inset_x, y + (row + 1) * cell_size + inset_y);
display.print(row, HEX); // and THIS is the row labels
for (uint8_t col=0; col<16; col++) { // 16 across...
if ((row + col) & 1) { // Fill alternating cells w/gray
display.fillRect(x + (col + 1) * cell_size, y + (row + 1) * cell_size,
cell_size, cell_size, 0x630C);
}
// drawChar() bypasses usual cursor positioning to go direct to an X/Y
// location. If foreground & background match, it's drawn transparent.
display.drawChar(x + (col + 1) * cell_size + inset_x,
y + (row + 1) * cell_size + inset_y, row * 16 + col,
0xFFFF, 0xFFFF, 1);
}
}
delay(PAUSE * 2);
} // END CHAR MAP EXAMPLE
void show_custom_text() {
// Show use of custom fonts, plus how to do center or right alignment
// using some additional functions provided earlier.
display.fillScreen(0);
display.setFont(&FreeSansBold18pt7b);
display.setTextSize(1);
display.setTextWrap(false); // Allow text off edges
// Get "M height" of custom font and move initial base line there:
uint16_t w, h;
int16_t x, y;
display.getTextBounds("M", 0, 0, &x, &y, &w, &h);
// On rounded 240x280 display in tall orientation, "Custom Font" gets
// clipped by top corners. Scoot text down a few pixels in that one case.
if (CORNER_RADIUS && (display.height() == 280)) h += 20;
display.setCursor(display.width() / 2, h);
if (display.width() >= 200) {
print_aligned(display, F("Custom Font"), GFX_ALIGN_CENTER);
display.setCursor(0, display.getCursorY() + 10);
print_aligned(display, F("Align Left"), GFX_ALIGN_LEFT);
display.setCursor(display.width() / 2, display.getCursorY());
print_aligned(display, F("Centered"), GFX_ALIGN_CENTER);
// Small rounded screen, when oriented the wide way, "Right" gets
// clipped by bottom right corner. Scoot left to compensate.
int16_t x_offset = (CORNER_RADIUS && (display.height() < 200)) ? 15 : 0;
display.setCursor(display.width() - x_offset, display.getCursorY());
print_aligned(display, F("Align Right"), GFX_ALIGN_RIGHT);
} else {
// On narrow screens, use abbreviated messages
print_aligned(display, F("Font &"), GFX_ALIGN_CENTER);
print_aligned(display, F("Align"), GFX_ALIGN_CENTER);
display.setCursor(0, display.getCursorY() + 10);
print_aligned(display, F("Left"), GFX_ALIGN_LEFT);
display.setCursor(display.width() / 2, display.getCursorY());
print_aligned(display, F("Center"), GFX_ALIGN_CENTER);
display.setCursor(display.width(), display.getCursorY());
print_aligned(display, F("Right"), GFX_ALIGN_RIGHT);
}
delay(PAUSE);
} // END CUSTOM FONT EXAMPLE
// BITMAP EXAMPLE ----------------------------------------------------------
// This section demonstrates:
// - Embedding a small bitmap in the code (flash memory).
// - Drawing that bitmap in various colors, and transparently (only '1' bits
// are drawn; '0' bits are skipped, leaving screen contents in place).
// - Use of the color565() function to decimate 24-bit RGB to 16 bits.
#define HEX_WIDTH 16 // Bitmap width in pixels
#define HEX_HEIGHT 16 // Bitmap height in pixels
// Bitmap data. PROGMEM ensures it's in flash memory (not RAM). And while
// it would be valid to leave the brackets empty here (i.e. hex_bitmap[]),
// having dimensions with a little math makes the compiler verify the
// correct number of bytes are present in the list.
PROGMEM const uint8_t hex_bitmap[(HEX_WIDTH + 7) / 8 * HEX_HEIGHT] = {
0b00000001, 0b10000000,
0b00000111, 0b11100000,
0b00011111, 0b11111000,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b00011111, 0b11111000,
0b00000111, 0b11100000,
0b00000001, 0b10000000,
};
#define Y_SPACING (HEX_HEIGHT - 2) // Used by code below for positioning
void show_bitmap() {
display.fillScreen(0);
// Not screen center, but UL coordinates of center hexagon bitmap
const int16_t center_x = (display.width() - HEX_WIDTH) / 2;
const int16_t center_y = (display.height() - HEX_HEIGHT) / 2;
const uint8_t steps = min((display.height() - HEX_HEIGHT) / Y_SPACING,
display.width() / HEX_WIDTH - 1) / 2;
display.drawBitmap(center_x, center_y, hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
0xFFFF); // Draw center hexagon in white
// Tile the hexagon bitmap repeatedly in a range of hues. Don't mind the
// bit of repetition in the math, the optimizer easily picks this up.
// Also, if math looks odd, keep in mind "PEMDAS" operator precedence;
// multiplication and division occur before addition and subtraction.
for (uint8_t a=0; a<=steps; a++) {
for (uint8_t b=1; b<=steps; b++) {
display.drawBitmap( // Right section centered red: a = green, b = blue
center_x + (a + b) * HEX_WIDTH / 2,
center_y + (a - b) * Y_SPACING,
hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
display.color565(255, 255 - 255 * a / steps, 255 - 255 * b / steps));
display.drawBitmap( // UL section centered green: a = blue, b = red
center_x - b * HEX_WIDTH + a * HEX_WIDTH / 2,
center_y - a * Y_SPACING,
hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
display.color565(255 - 255 * b / steps, 255, 255 - 255 * a / steps));
display.drawBitmap( // LL section centered blue: a = red, b = green
center_x - a * HEX_WIDTH + b * HEX_WIDTH / 2,
center_y + b * Y_SPACING,
hex_bitmap, HEX_WIDTH, HEX_HEIGHT,
display.color565(255 - 255 * a / steps, 255 - 255 * b / steps, 255));
}
}
delay(PAUSE);
} // END BITMAP EXAMPLE
// CANVAS EXAMPLE ----------------------------------------------------------
// This section demonstrates:
// - How to refresh changing values onscreen without erase/redraw flicker.
// - Using an offscreen canvas. It's similar to a bitmap above, but rather
// than a fixed pattern in flash memory, it's drawable like the screen.
// - More tips on text alignment, and adapting to different screen sizes.
#define PADDING 6 // Pixels between axis label and value
void show_canvas() {
// For this example, let's suppose we want to display live readings from a
// sensor such as a three-axis accelerometer, something like:
// X: (number)
// Y: (number)
// Z: (number)
// To look extra classy, we want a custom font, and the labels for each
// axis are right-aligned so the ':' characters line up...
display.setFont(&FreeSansBold18pt7b); // Use a custom font
display.setTextSize(1); // and reset to 1:1 scale
char *label[] = { "X:", "Y:", "Z:" }; // Labels for each axis
const uint16_t color[] = { 0xF800, 0x07E0, 0x001F }; // Colors for each value
// To get the labels right-aligned, one option would be simple trial and
// error to find a column that looks good and doesn't clip anything off.
// Let's do this dynamically though, so it adapts to any font or labels!
// Start by finding the widest of the label strings:
uint16_t w, h, max_w = 0;
int16_t x, y;
for (uint8_t i=0; i<3; i++) { // For each label...
display.getTextBounds(label[i], 0, 0, &x, &y, &w, &h);
if (w > max_w) max_w = w; // Keep track of widest label
}
// Rounded corners throwing us a curve again. If needed, scoot everything
// to the right a bit on wide displays, down a bit on tall ones.
int16_t y_offset = 0;
if (display.width() > display.height()) max_w += CORNER_RADIUS;
else y_offset = CORNER_RADIUS;
// Now we have max_w for right-aligning the labels. Before we draw them
// though...in order to perform flicker-free updates, the numbers we show
// will be rendered in either a GFXcanvas1 or GFXcanvas16 object; a 1-bit
// or 16-bit offscreen bitmap, RAM permitting. The correct size for this
// canvas could also be trial-and-errored, but again let's make this adapt
// automatically. The width of the canvas will span from max_w (plus a few
// pixels for padding) to the right edge. But the height? Looking at an
// uppercase 'M' can work in many situations, but some fonts have ascenders
// and descenders on digits, and in some locales a comma (extending below
// the baseline) is the decimal separator. Feed ALL the numeric chars into
// getTextBounds() for a cumulative height:
display.setTextWrap(false); // Keep on one line
display.getTextBounds(F("0123456789.,-"), 0, 0, &x, &y, &w, &h);
// Now declare a GFXcanvas16 object based on the computed width & height:
GFXcanvas16 canvas16(display.width() - max_w - PADDING, h);
// Small devices (e.g. ATmega328p) will almost certainly lack enough RAM
// for the canvas. Check if canvas buffer exists. If not, fall back on
// using a 1-bit (rather than 16-bit) canvas. Much more RAM friendly, but
// not as fast to draw. If a project doesn't require super interactive
// updates, consider just going straight for the more compact Canvas1.
if (canvas16.getBuffer()) {
// If here, 16-bit canvas allocated successfully! Point of interest,
// only one canvas is needed for this example, we can reuse it for all
// three numbers because the regions are the same size.
// display and canvas are independent drawable objects; must explicitly
// set the same custom font to use on the canvas now:
canvas16.setFont(&FreeSansBold18pt7b);
// Clear display and print labels. Once drawn, these remain untouched.
display.fillScreen(0);
display.setCursor(max_w, -y + y_offset); // Set baseline for first row
for (uint8_t i=0; i<3; i++) print_aligned(display, label[i], GFX_ALIGN_RIGHT);
// Last part now is to print numbers on the canvas and copy the canvas to
// the display, repeating for several seconds...
uint32_t elapsed, startTime = millis();
while ((elapsed = (millis() - startTime)) <= PAUSE * 2) {
for (uint8_t i=0; i<3; i++) { // For each label...
canvas16.fillScreen(0); // fillScreen() in this case clears canvas
canvas16.setCursor(0, -y); // Reset baseline for custom font
canvas16.setTextColor(color[i]);
// These aren't real accelerometer readings, just cool-looking numbers.
// Notice we print to the canvas, NOT the display:
canvas16.print(sin(elapsed / 200.0 + (float)i * M_PI * 2.0 / 3.0), 5);
// And HERE is the secret sauce to flicker-free updates. Canvas details
// can be passed to the drawRGBBitmap() function, which fully overwrites
// prior screen contents in that area. yAdvance is font line spacing.
display.drawRGBBitmap(max_w + PADDING, i * FreeSansBold18pt7b.yAdvance +
y_offset, canvas16.getBuffer(), canvas16.width(),
canvas16.height());
}
}
} else {
// Insufficient RAM for Canvas16. Try declaring a 1-bit canvas instead...
GFXcanvas1 canvas1(display.width() - max_w - PADDING, h);
// If even this smaller object fails, can't proceed, cancel this example.
if (!canvas1.getBuffer()) return;
// Remainder here is nearly identical to the code above, simply using a
// different canvas type. It's stripped of most comments for brevity.
canvas1.setFont(&FreeSansBold18pt7b);
display.fillScreen(0);
display.setCursor(max_w, -y + y_offset);
for (uint8_t i=0; i<3; i++) print_aligned(display, label[i], GFX_ALIGN_RIGHT);
uint32_t elapsed, startTime = millis();
while ((elapsed = (millis() - startTime)) <= PAUSE * 2) {
for (uint8_t i=0; i<3; i++) {
canvas1.fillScreen(0);
canvas1.setCursor(0, -y);
canvas1.print(sin(elapsed / 200.0 + (float)i * M_PI * 2.0 / 3.0), 5);
// Here's the secret sauce to flicker-free updates with GFXcanvas1.
// Canvas details can be passed to the drawBitmap() function, and by
// specifying both a foreground AND BACKGROUND color (0), this will fully
// overwrite/erase prior screen contents in that area (vs transparent).
display.drawBitmap(max_w + PADDING, i * FreeSansBold18pt7b.yAdvance +
y_offset, canvas1.getBuffer(), canvas1.width(),
canvas1.height(), color[i], 0);
}
}
}
// Because canvas object was declared locally to this function, it's freed
// automatically when the function returns; no explicit delete needed.
} // END CANVAS EXAMPLE

View file

@ -1,7 +1,5 @@
// SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#define BITMAP_WIDTH 64
#define BITMAP_HEIGHT 32
const uint8_t PROGMEM bitmap_2020[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View file

@ -1,24 +1,10 @@
// SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <Adafruit_LIS3DH.h> // For accelerometer
#include <Adafruit_PixelDust.h> // For simulation
#include <Adafruit_Protomatter.h> // For LED matrix
#include "2020.h" // 2020 bitmap data
#include "2021.h" // 2021 bitmap data
#include "2022.h" // etc.
#include "2023.h"
#include "2024.h"
#include "2025.h"
#include "2026.h"
#define BITMAP_WIDTH 64 // All the year bitmaps are a fixed size
#define BITMAP_HEIGHT 32
#define THIS_YEAR_BITMAP bitmap_2021 // Name of current/next year bitmap
#define NEXT_YEAR_BITMAP bitmap_2022 // arrays in header files
bool show_new_year = true;
bool show_2021 = true;
#define SHAKE_ACCEL_G 2.9 // Force (in Gs) to trigger shake
#define SHAKE_ACCEL_MS2 (SHAKE_ACCEL_G * 9.8) // Convert to m/s^2
@ -27,19 +13,11 @@ bool show_new_year = true;
#define SHAKE_PERIOD 2000 // Period (in ms) when SHAKE_EVENTS must happen
#define SAND_TIME 6000 // Time (in ms) to run simulation before restarting
#if defined(_VARIANT_MATRIXPORTAL_M4_) // MatrixPortal M4
uint8_t rgbPins[] = {7, 8, 9, 10, 11, 12};
uint8_t addrPins[] = {17, 18, 19, 20, 21};
uint8_t addrPins[] = {17, 18, 19, 20};
uint8_t clockPin = 14;
uint8_t latchPin = 15;
uint8_t oePin = 16;
#else // MatrixPortal ESP32-S3
uint8_t rgbPins[] = {42, 41, 40, 38, 39, 37};
uint8_t addrPins[] = {35, 36, 48, 45, 21};
uint8_t clockPin = 2;
uint8_t latchPin = 47;
uint8_t oePin = 14;
#endif
// 64x32 pixel matrix, 6-bit depth
Adafruit_Protomatter matrix(
@ -72,10 +50,10 @@ void setup(void) {
ProtomatterStatus status = matrix.begin();
Serial.printf("Protomatter begin() status: %d\n", status);
// Count number of 'on' pixels (sand grains) in THIS_YEAR_BITMAP
for (int i=0; i<sizeof(THIS_YEAR_BITMAP); i++) {
// Count number of 'on' pixels (sand grains) in bitmap_2020
for (int i=0; i<sizeof(bitmap_2020); i++) {
for (int b=0; b<8; b++) {
if (THIS_YEAR_BITMAP[i] & (1 << b)) {
if (bitmap_2020[i] & (1 << b)) {
n_grains++;
}
}
@ -99,15 +77,15 @@ void setup(void) {
void loop() {
Serial.print("Tick");
uint16_t sandColor = show_new_year ? 0xF800 : 0xFFFF; // Red or white
uint16_t sandColor = show_2021 ? 0xF800 : 0xFFFF; // Red or white
// Set initial sand pixel positions and draw initial matrix state
sand->clear();
matrix.fillScreen(0);
int grain = 0, pixel = 0; // Sand grain and pixel indices
for (int i=0; i<sizeof(THIS_YEAR_BITMAP); i++) {
for (int i=0; i<sizeof(bitmap_2020); i++) {
for (int b=0; b<8; b++, pixel++) {
if (THIS_YEAR_BITMAP[i] & (1 << (7-b))) {
if (bitmap_2020[i] & (1 << (7-b))) {
int x = pixel % BITMAP_WIDTH;
int y = pixel / BITMAP_WIDTH;
//Serial.printf("Set pixel %d @ (%d, %d)\n", grain, x, y);
@ -165,7 +143,7 @@ void loop() {
scale = pow(scale, 2.6);
uint16_t rb = (int)(31.0 * scale + 0.5);
uint16_t g = (int)(63.0 * scale + 0.5);
if (show_new_year)
if (show_2021)
sandColor = (rb * 0b100000000000); // Just show red
else
sandColor = (rb * 0b100000000001) + (g << 5);
@ -181,16 +159,16 @@ void loop() {
matrix.show();
}
// If the show_new_year flag is set, don't return to shake detect,
// instead switch to sparkly display forever (reset to start over)
if (show_new_year) {
uint16_t frame = 0;
// If the show_2021 flag is set, don't return to 2020 shake detect,
// instead switch to sparkly '2021' display forever (reset to start over)
if (show_2021) {
uint16_t frame = 0;
matrix.fillScreen(0);
for(;;) {
int pixel = 0;
for (int i=0; i<sizeof(NEXT_YEAR_BITMAP); i++) {
for (int i=0; i<sizeof(bitmap_2021); i++) {
for (int b=0; b<8; b++, pixel++) {
if (NEXT_YEAR_BITMAP[i] & (1 << (7-b))) {
if (bitmap_2021[i] & (1 << (7-b))) {
int x = pixel % BITMAP_WIDTH;
int y = pixel / BITMAP_WIDTH;
matrix.drawPixel(x, y, (random() & 1) ? ((((x - y + frame) / 8) & 1) ? 0xFFFF : 0x001F) : 0);

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
const uint8_t PROGMEM bitmap_2021[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View file

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: 2021 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
const uint8_t PROGMEM bitmap_2022[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x1f, 0xf8, 0x1f, 0xf0,
0x1f, 0xf8, 0x1f, 0xf8, 0x3f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc,
0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7c, 0x7e, 0x7c, 0x7c,
0x7c, 0x7e, 0x7c, 0x7e, 0xf8, 0x3e, 0x7c, 0x3c, 0xf8, 0x3e, 0xf8, 0x3e,
0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e,
0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e,
0x00, 0x3e, 0xf8, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x7c, 0xf8, 0x3e,
0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0xf8, 0x3e, 0x00, 0x7c, 0x00, 0x7c,
0x01, 0xf8, 0xf8, 0x3e, 0x01, 0xf8, 0x01, 0xf8, 0x03, 0xf0, 0xf8, 0x3e,
0x03, 0xf0, 0x03, 0xf0, 0x07, 0xe0, 0xf8, 0x3e, 0x07, 0xe0, 0x07, 0xe0,
0x0f, 0xc0, 0xf8, 0x3e, 0x0f, 0xc0, 0x0f, 0xc0, 0x1f, 0x80, 0xf8, 0x3e,
0x1f, 0x80, 0x1f, 0x80, 0x1f, 0x00, 0xf8, 0x3e, 0x1f, 0x00, 0x1f, 0x00,
0x3e, 0x00, 0xf8, 0x3e, 0x3e, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0x78, 0x7c,
0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x7c, 0x7c, 0x00, 0x7c, 0x00,
0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x3f, 0xf8,
0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x3f, 0xf0, 0xff, 0xfe, 0xff, 0xfe,
0xff, 0xfe, 0x0f, 0xe0, 0xff, 0xfe, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };

View file

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: 2021 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
const uint8_t PROGMEM bitmap_2023[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xc0, 0x1f, 0xf8, 0x1f, 0xf0,
0x1f, 0xf8, 0x3f, 0xf0, 0x3f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfc, 0x3f, 0xf8,
0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7c, 0x7e, 0x7c, 0x7c,
0x7c, 0x7e, 0x7c, 0xfc, 0xf8, 0x3e, 0x7c, 0x3c, 0xf8, 0x3e, 0xf8, 0x7c,
0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x7c, 0xf8, 0x3e, 0xf8, 0x3e,
0xf8, 0x3e, 0xf8, 0x7c, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0x00, 0x7c,
0x00, 0x3e, 0xf8, 0x3e, 0x00, 0x3e, 0x00, 0xf8, 0x00, 0x7c, 0xf8, 0x3e,
0x00, 0x7c, 0x0f, 0xf8, 0x00, 0x7c, 0xf8, 0x3e, 0x00, 0x7c, 0x0f, 0xe0,
0x01, 0xf8, 0xf8, 0x3e, 0x01, 0xf8, 0x0f, 0xf8, 0x03, 0xf0, 0xf8, 0x3e,
0x03, 0xf0, 0x0f, 0xfc, 0x07, 0xe0, 0xf8, 0x3e, 0x07, 0xe0, 0x00, 0xfc,
0x0f, 0xc0, 0xf8, 0x3e, 0x0f, 0xc0, 0x00, 0x7e, 0x1f, 0x80, 0xf8, 0x3e,
0x1f, 0x80, 0x00, 0x3e, 0x1f, 0x00, 0xf8, 0x3e, 0x1f, 0x00, 0xf8, 0x3e,
0x3e, 0x00, 0xf8, 0x3e, 0x3e, 0x00, 0xf8, 0x3e, 0x7c, 0x00, 0x78, 0x7c,
0x7c, 0x00, 0xf8, 0x3e, 0x7c, 0x00, 0x7c, 0x7c, 0x7c, 0x00, 0x7c, 0x7e,
0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0x3f, 0xf8,
0xff, 0xfe, 0x3f, 0xfc, 0xff, 0xfe, 0x3f, 0xf0, 0xff, 0xfe, 0x1f, 0xf8,
0xff, 0xfe, 0x0f, 0xe0, 0xff, 0xfe, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };

View file

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: 2021 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
const uint8_t PROGMEM bitmap_2024[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x01, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0,
0x1f, 0xf8, 0x01, 0xf8, 0x3f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfc, 0x03, 0xf8,
0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x03, 0xf8, 0x7c, 0x7e, 0x7c, 0x7c,
0x7c, 0x7e, 0x07, 0xf8, 0xf8, 0x3e, 0x7c, 0x3c, 0xf8, 0x3e, 0x07, 0xf8,
0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0x0f, 0xf8, 0xf8, 0x3e, 0xf8, 0x3e,
0xf8, 0x3e, 0x1e, 0xf8, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0x1e, 0xf8,
0x00, 0x3e, 0xf8, 0x3e, 0x00, 0x3e, 0x3c, 0xf8, 0x00, 0x7c, 0xf8, 0x3e,
0x00, 0x7c, 0x3c, 0xf8, 0x00, 0x7c, 0xf8, 0x3e, 0x00, 0x7c, 0x78, 0xf8,
0x01, 0xf8, 0xf8, 0x3e, 0x01, 0xf8, 0x78, 0xf8, 0x03, 0xf0, 0xf8, 0x3e,
0x03, 0xf0, 0xf0, 0xf8, 0x07, 0xe0, 0xf8, 0x3e, 0x07, 0xe0, 0xf0, 0xf8,
0x0f, 0xc0, 0xf8, 0x3e, 0x0f, 0xc1, 0xe0, 0xf8, 0x1f, 0x80, 0xf8, 0x3e,
0x1f, 0x81, 0xff, 0xfe, 0x1f, 0x00, 0xf8, 0x3e, 0x1f, 0x01, 0xff, 0xfe,
0x3e, 0x00, 0xf8, 0x3e, 0x3e, 0x01, 0xff, 0xfe, 0x7c, 0x00, 0x78, 0x7c,
0x7c, 0x01, 0xff, 0xfe, 0x7c, 0x00, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0xf8,
0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0x00, 0xf8, 0xff, 0xfe, 0x3f, 0xf8,
0xff, 0xfe, 0x00, 0xf8, 0xff, 0xfe, 0x3f, 0xf0, 0xff, 0xfe, 0x00, 0xf8,
0xff, 0xfe, 0x0f, 0xe0, 0xff, 0xfe, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };

View file

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: 2021 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
const uint8_t PROGMEM bitmap_2025[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf8, 0x1f, 0xf0,
0x1f, 0xf8, 0x7f, 0xfc, 0x3f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfc,
0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7c, 0x7e, 0x7c, 0x7c,
0x7c, 0x7e, 0x7f, 0xfc, 0xf8, 0x3e, 0x7c, 0x3c, 0xf8, 0x3e, 0x78, 0x00,
0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0x78, 0x00, 0xf8, 0x3e, 0xf8, 0x3e,
0xf8, 0x3e, 0x78, 0x00, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0x79, 0xf0,
0x00, 0x3e, 0xf8, 0x3e, 0x00, 0x3e, 0x7f, 0xf8, 0x00, 0x7c, 0xf8, 0x3e,
0x00, 0x7c, 0x7f, 0xfc, 0x00, 0x7c, 0xf8, 0x3e, 0x00, 0x7c, 0x7f, 0xfc,
0x01, 0xf8, 0xf8, 0x3e, 0x01, 0xf8, 0x7c, 0x7e, 0x03, 0xf0, 0xf8, 0x3e,
0x03, 0xf0, 0x78, 0x3e, 0x07, 0xe0, 0xf8, 0x3e, 0x07, 0xe0, 0x00, 0x3e,
0x0f, 0xc0, 0xf8, 0x3e, 0x0f, 0xc0, 0x00, 0x3e, 0x1f, 0x80, 0xf8, 0x3e,
0x1f, 0x80, 0x00, 0x3e, 0x1f, 0x00, 0xf8, 0x3e, 0x1f, 0x00, 0xf8, 0x3e,
0x3e, 0x00, 0xf8, 0x3e, 0x3e, 0x00, 0xf8, 0x3e, 0x7c, 0x00, 0x78, 0x7c,
0x7c, 0x00, 0xf8, 0x3e, 0x7c, 0x00, 0x7c, 0x7c, 0x7c, 0x00, 0xfc, 0x7c,
0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0x3f, 0xf8,
0xff, 0xfe, 0x7f, 0xf8, 0xff, 0xfe, 0x3f, 0xf0, 0xff, 0xfe, 0x3f, 0xf8,
0xff, 0xfe, 0x0f, 0xe0, 0xff, 0xfe, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };

View file

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: 2021 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
const uint8_t PROGMEM bitmap_2026[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xe0, 0x0f, 0xe0, 0x0f, 0xe0, 0x07, 0xe0, 0x1f, 0xf8, 0x1f, 0xf0,
0x1f, 0xf8, 0x1f, 0xf8, 0x3f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc,
0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfe, 0x7c, 0x7e, 0x7c, 0x7c,
0x7c, 0x7e, 0x7c, 0x3e, 0xf8, 0x3e, 0x7c, 0x3c, 0xf8, 0x3e, 0x7c, 0x3e,
0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x00, 0xf8, 0x3e, 0xf8, 0x3e,
0xf8, 0x3e, 0xf8, 0x00, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x3e, 0xf8, 0x00,
0x00, 0x3e, 0xf8, 0x3e, 0x00, 0x3e, 0xf9, 0xf0, 0x00, 0x7c, 0xf8, 0x3e,
0x00, 0x7c, 0xfb, 0xf8, 0x00, 0x7c, 0xf8, 0x3e, 0x00, 0x7c, 0xff, 0xfc,
0x01, 0xf8, 0xf8, 0x3e, 0x01, 0xf8, 0xff, 0xfc, 0x03, 0xf0, 0xf8, 0x3e,
0x03, 0xf0, 0xfc, 0x7e, 0x07, 0xe0, 0xf8, 0x3e, 0x07, 0xe0, 0xf8, 0x3e,
0x0f, 0xc0, 0xf8, 0x3e, 0x0f, 0xc0, 0xf8, 0x3e, 0x1f, 0x80, 0xf8, 0x3e,
0x1f, 0x80, 0xf8, 0x3e, 0x1f, 0x00, 0xf8, 0x3e, 0x1f, 0x00, 0xf8, 0x3e,
0x3e, 0x00, 0xf8, 0x3e, 0x3e, 0x00, 0xf8, 0x3e, 0x7c, 0x00, 0x78, 0x7c,
0x7c, 0x00, 0x78, 0x3e, 0x7c, 0x00, 0x7c, 0x7c, 0x7c, 0x00, 0x7c, 0x7c,
0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0x7f, 0xfc, 0xff, 0xfe, 0x3f, 0xf8,
0xff, 0xfe, 0x3f, 0xf8, 0xff, 0xfe, 0x3f, 0xf0, 0xff, 0xfe, 0x1f, 0xf8,
0xff, 0xfe, 0x0f, 0xe0, 0xff, 0xfe, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: 2018 Bill Earl and Mikey Sklar for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*******************************************************************
Bionic Eye sketch for Adafruit Trinket.

View file

@ -0,0 +1,50 @@
# Bionic Eye sketch for Adafruit Trinket.
#
# written by Bill Earl for Arduino
# ported to CircuitPython by Mikey Sklar
# for Adafruit Industries
#
# Required library is the Adafruit_SoftServo library
# available at https://github.com/adafruit/Adafruit_SoftServo
# The standard Arduino IDE servo library will not work with 8 bit
# AVR microcontrollers like Trinket and Gemma due to differences
# in available timer hardware and programming. We simply refresh
# by piggy-backing on the timer0 millis() counter
#
# Trinket: Bat+ Gnd Pin #0 Pin #2
# Connection: Servo+ Servo- Tilt Rotate
# (Red) (Black) Servo Servo
# (Orange)(Orange)
import time
import random
import board
import pwmio
from adafruit_motor import servo
# we are intentionally avoiding Trinket Pin #1 (board.A0)
# as it does not have PWM capability
tilt_servo_pin = board.A2 # servo control line (orange) Trinket Pin #0
rotate_servo_pin = board.A1 # servo control line (orange) Trinket Pin #2
# servo object setup for the M0 boards:
tilt_pwm = pwmio.PWMOut(tilt_servo_pin, duty_cycle=2 ** 15, frequency=50)
rotate_pwm = pwmio.PWMOut(rotate_servo_pin, duty_cycle=2 ** 15, frequency=50)
tilt_servo = servo.Servo(tilt_pwm)
rotate_servo = servo.Servo(rotate_pwm)
# servo timing and angle range
tilt_min = 120 # lower limit to tilt rotation range
max_rotate = 180 # rotation range limited to half circle
while True:
# servo tilt - on average move every 500ms
if random.randint(0,100) > 80:
tilt_servo.angle = random.randint(tilt_min, max_rotate)
time.sleep(.25)
# servo rotate - on average move every 500ms
if random.randint(0,100) > 90:
rotate_servo.angle = random.randint(0, max_rotate)
time.sleep(.25)

View file

@ -1,54 +0,0 @@
# SPDX-FileCopyrightText: 2018 Bill Earl and Mikey Sklar for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
# Bionic Eye sketch for Adafruit Trinket.
#
# written by Bill Earl for Arduino
# ported to CircuitPython by Mikey Sklar
# for Adafruit Industries
#
# Required library is the Adafruit_SoftServo library
# available at https://github.com/adafruit/Adafruit_SoftServo
# The standard Arduino IDE servo library will not work with 8 bit
# AVR microcontrollers like Trinket and Gemma due to differences
# in available timer hardware and programming. We simply refresh
# by piggy-backing on the timer0 millis() counter
#
# Trinket: Bat+ Gnd Pin #0 Pin #2
# Connection: Servo+ Servo- Tilt Rotate
# (Red) (Black) Servo Servo
# (Orange)(Orange)
import time
import random
import board
import pwmio
from adafruit_motor import servo
# we are intentionally avoiding Trinket Pin #1 (board.A0)
# as it does not have PWM capability
tilt_servo_pin = board.A2 # servo control line (orange) Trinket Pin #0
rotate_servo_pin = board.A1 # servo control line (orange) Trinket Pin #2
# servo object setup for the M0 boards:
tilt_pwm = pwmio.PWMOut(tilt_servo_pin, duty_cycle=2 ** 15, frequency=50)
rotate_pwm = pwmio.PWMOut(rotate_servo_pin, duty_cycle=2 ** 15, frequency=50)
tilt_servo = servo.Servo(tilt_pwm)
rotate_servo = servo.Servo(rotate_pwm)
# servo timing and angle range
tilt_min = 120 # lower limit to tilt rotation range
max_rotate = 180 # rotation range limited to half circle
while True:
# servo tilt - on average move every 500ms
if random.randint(0,100) > 80:
tilt_servo.angle = random.randint(tilt_min, max_rotate)
time.sleep(.25)
# servo rotate - on average move every 500ms
if random.randint(0,100) > 90:
rotate_servo.angle = random.randint(0, max_rotate)
time.sleep(.25)

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
// Fiery demon horns (rawr!) for Adafruit Trinket/Gemma.
// Adafruit invests time and resources providing this open source code,
// please support Adafruit and open-source hardware by purchasing
@ -30,7 +26,7 @@ struct {
long fade; // Decreases brightness as wave moves
// Gamma correction improves appearance of midrange colors
const uint8_t gamma[] PROGMEM = {
uint8_t gamma[] PROGMEM = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,

View file

@ -0,0 +1,147 @@
# Fiery demon horns (rawr!) for Adafruit Trinket/Gemma.
# Adafruit invests time and resources providing this open source code,
# please support Adafruit and open-source hardware by purchasing
# products from Adafruit!
import board
import neopixel
from analogio import AnalogIn
# pylint: disable=global-statement
try:
import urandom as random
except ImportError:
import random
# /\ -> Fire-like effect is the sum_total of multiple triangle
# ____/ \____ waves in motion, with a 'warm' color map applied.
n_horns = 1 # number of horns
led_pin = board.D0 # which pin your pixels are connected to
n_leds = 30 # number of LEDs per horn
frames_per_second = 50 # animation frames per second
brightness = 0 # current wave height
fade = 0 # Decreases brightness as wave moves
pixels = neopixel.NeoPixel(led_pin, n_leds, brightness=1, auto_write=False)
offset = 0
# Coordinate space for waves is 16x the pixel spacing,
# allowing fixed-point math to be used instead of floats.
lower = 0 # lower bound of wave
upper = 1 # upper bound of wave
mid = 2 # midpoint (peak) ((lower+upper)/2)
vlower = 3 # velocity of lower bound
vupper = 4 # velocity of upper bound
intensity = 5 # brightness at peak
y = 0
brightness = 0
count = 0
# initialize 3D list
wave = [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6
# Number of simultaneous waves (per horn)
n_waves = len(wave)
# Gamma-correction table
gamma = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110,
112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133,
135, 137, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186,
189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218,
220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252,
255
]
def random_wave(he, wi):
wave[he][wi][upper] = -1 # Always start below head of strip
wave[he][wi][lower] = -16 * (3 + random.randint(0,4)) # Lower end starts ~3-7 pixels back
wave[he][wi][mid] = (wave[he][wi][lower]+ wave[he][wi][upper]) / 2
wave[he][wi][vlower] = 3 + random.randint(0,4) # Lower end moves at ~1/8 to 1/pixels
wave[he][wi][vupper] = wave[he][wi][vlower]+ random.randint(0,4) # Upper end moves a bit faster
wave[he][wi][intensity] = 300 + random.randint(0,600)
def setup():
global fade
# Random number generator is seeded from an unused 'floating'
# analog input - this helps ensure the random color choices
# aren't always the same order.
pin = AnalogIn(board.A0)
random.seed(pin.value)
pin.deinit()
for he in range(n_horns):
for wi in range(n_waves):
random_wave(he, wi)
fade = 233 + n_leds / 2
if fade > 233:
fade = 233
setup()
while True:
h = w = i = r = g = b = 0
x = 0
for h in range(n_horns): # For each horn...
x = 7
sum_total = 0
for i in range(n_leds): # For each LED along horn...
x += 16
for w in range(n_waves): # For each wave of horn...
if (x < wave[h][w][lower]) or (x > wave[h][w][upper]):
continue # Out of range
if x <= wave[h][w][mid]: # Lower half of wave (ramping up peak brightness)
sum_top = wave[h][w][intensity] * (x - wave[h][w][lower])
sum_bottom = (wave[h][w][mid] - wave[h][w][lower])
sum_total += sum_top / sum_bottom
else: # Upper half of wave (ramping down from peak)
sum_top = wave[h][w][intensity] * (wave[h][w][upper] - x)
sum_bottom = (wave[h][w][upper] - wave[h][w][mid])
sum_total += sum_top / sum_bottom
sum_total = int(sum_total) # convert from decimal to whole number
# Now the magnitude (sum_total) is remapped to color for the LEDs.
# A blackbody palette is used - fades white-yellow-red-black.
if sum_total < 255: # 0-254 = black to red-1
r = gamma[sum_total]
g = b = 0
elif sum_total < 510: # 255-509 = red to yellow-1
r = 255
g = gamma[sum_total - 255]
b = 0
elif sum_total < 765: # 510-764 = yellow to white-1
r = g = 255
b = gamma[sum_total - 510]
else: # 765+ = white
r = g = b = 255
pixels[i] = (r, g, b)
for w in range(n_waves): # Update wave positions for each horn
wave[h][w][lower] += wave[h][w][vlower] # Advance lower position
if wave[h][w][lower] >= (n_leds * 16): # Off end of strip?
random_wave(h, w) # Yes, 'reboot' wave
else: # No, adjust other values...
wave[h][w][upper] += wave[h][w][vupper]
wave[h][w][mid] = (wave[h][w][lower] + wave[h][w][upper]) / 2
wave[h][w][intensity] = (wave[h][w][intensity] * fade) / 256 # Dimmer
pixels.show()

View file

@ -1,151 +0,0 @@
# SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Fiery demon horns (rawr!) for Adafruit Trinket/Gemma.
# Adafruit invests time and resources providing this open source code,
# please support Adafruit and open-source hardware by purchasing
# products from Adafruit!
import board
import neopixel
from analogio import AnalogIn
# pylint: disable=global-statement
try:
import urandom as random
except ImportError:
import random
# /\ -> Fire-like effect is the sum_total of multiple triangle
# ____/ \____ waves in motion, with a 'warm' color map applied.
n_horns = 1 # number of horns
led_pin = board.D0 # which pin your pixels are connected to
n_leds = 30 # number of LEDs per horn
frames_per_second = 50 # animation frames per second
brightness = 0 # current wave height
fade = 0 # Decreases brightness as wave moves
pixels = neopixel.NeoPixel(led_pin, n_leds, brightness=1, auto_write=False)
offset = 0
# Coordinate space for waves is 16x the pixel spacing,
# allowing fixed-point math to be used instead of floats.
lower = 0 # lower bound of wave
upper = 1 # upper bound of wave
mid = 2 # midpoint (peak) ((lower+upper)/2)
vlower = 3 # velocity of lower bound
vupper = 4 # velocity of upper bound
intensity = 5 # brightness at peak
y = 0
brightness = 0
count = 0
# initialize 3D list
wave = [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6
# Number of simultaneous waves (per horn)
n_waves = len(wave)
# Gamma-correction table
gamma = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110,
112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133,
135, 137, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186,
189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218,
220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252,
255
]
def random_wave(he, wi):
wave[he][wi][upper] = -1 # Always start below head of strip
wave[he][wi][lower] = -16 * (3 + random.randint(0,4)) # Lower end starts ~3-7 pixels back
wave[he][wi][mid] = (wave[he][wi][lower]+ wave[he][wi][upper]) / 2
wave[he][wi][vlower] = 3 + random.randint(0,4) # Lower end moves at ~1/8 to 1/pixels
wave[he][wi][vupper] = wave[he][wi][vlower]+ random.randint(0,4) # Upper end moves a bit faster
wave[he][wi][intensity] = 300 + random.randint(0,600)
def setup():
global fade
# Random number generator is seeded from an unused 'floating'
# analog input - this helps ensure the random color choices
# aren't always the same order.
pin = AnalogIn(board.A0)
random.seed(pin.value)
pin.deinit()
for he in range(n_horns):
for wi in range(n_waves):
random_wave(he, wi)
fade = 233 + n_leds / 2
if fade > 233:
fade = 233
setup()
while True:
h = w = i = r = g = b = 0
x = 0
for h in range(n_horns): # For each horn...
x = 7
sum_total = 0
for i in range(n_leds): # For each LED along horn...
x += 16
for w in range(n_waves): # For each wave of horn...
if (x < wave[h][w][lower]) or (x > wave[h][w][upper]):
continue # Out of range
if x <= wave[h][w][mid]: # Lower half of wave (ramping up peak brightness)
sum_top = wave[h][w][intensity] * (x - wave[h][w][lower])
sum_bottom = (wave[h][w][mid] - wave[h][w][lower])
sum_total += sum_top / sum_bottom
else: # Upper half of wave (ramping down from peak)
sum_top = wave[h][w][intensity] * (wave[h][w][upper] - x)
sum_bottom = (wave[h][w][upper] - wave[h][w][mid])
sum_total += sum_top / sum_bottom
sum_total = int(sum_total) # convert from decimal to whole number
# Now the magnitude (sum_total) is remapped to color for the LEDs.
# A blackbody palette is used - fades white-yellow-red-black.
if sum_total < 255: # 0-254 = black to red-1
r = gamma[sum_total]
g = b = 0
elif sum_total < 510: # 255-509 = red to yellow-1
r = 255
g = gamma[sum_total - 255]
b = 0
elif sum_total < 765: # 510-764 = yellow to white-1
r = g = 255
b = gamma[sum_total - 510]
else: # 765+ = white
r = g = b = 255
pixels[i] = (r, g, b)
for w in range(n_waves): # Update wave positions for each horn
wave[h][w][lower] += wave[h][w][vlower] # Advance lower position
if wave[h][w][lower] >= (n_leds * 16): # Off end of strip?
random_wave(h, w) # Yes, 'reboot' wave
else: # No, adjust other values...
wave[h][w][upper] += wave[h][w][vupper]
wave[h][w][mid] = (wave[h][w][lower] + wave[h][w][upper]) / 2
wave[h][w][intensity] = (wave[h][w][intensity] * fade) / 256 # Dimmer
pixels.show()

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
// Adafruit Trinket+NeoPixel animation for Daft Punk-inspired helmet.
// Contains some ATtiny85-specific stuff; won't run as-is on Uno, etc.

View file

@ -0,0 +1,189 @@
# Adafruit Trinket+NeoPixel animation for Daft Punk-inspired helmet.
# Contains some ATtiny85-specific stuff; won't run as-is on Uno, etc.
# Operates in HSV (hue, saturation, value) colorspace rather than RGB.
# Animation is an interference pattern between two waves; one controls
# saturation, the other controls value (brightness). The wavelength,
# direction, speed and type (square vs triangle wave) for each is randomly
# selected every few seconds. Hue is always linear, but other parameters
# are similarly randomized.
import random
import board
import neopixel
from analogio import AnalogIn
n_leds = 29 # number of LEDs per horn
led_pin = board.D0 # which pin your pixels are connected to
# initialize neopixel strip
pixels = neopixel.NeoPixel(led_pin, n_leds, brightness=1, auto_write=False)
count = 1 # countdown to next animation change
# Gamma-correction table
gamma = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110,
112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133,
135, 137, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186,
189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218,
220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252,
255
]
# initialize 3D list
wave = [0] * 5, [0] * 5, [0] * 5
wave_type = 0 # 0 = square wave, 1 = triangle wave
value_frame = 1 # start-of-frame value
value_pixel = 2 # pixel-to-pixel value
inc_frame = 3 # frame-to-frame increment
inc_pixel = 4 # pixel-to-pixel inc
wave_h = 0 # hue
wave_s = 1 # saturation
wave_v = 2 # brightness
# Random number generator is seeded from an unused 'floating'
# analog input - this helps ensure the random color choices
# aren't always the same order.
pin = AnalogIn(board.A0)
random.seed(pin.value)
pin.deinit()
# generate a non-zero random number for frame and pixel increments
def nz_random():
random_number = 0
while random_number <= 0:
random_number = random.randint(0,15) - 7
return random_number
while True:
w = i = n = s = v = r = g = b = v1 = s1 = 0
if count <= 0: # time for new animation
count = 250 + random.randint(0,250) # effect run for 5-10 sec.
for w in range(3): # three waves (H,S,V)
wave[w][wave_type] = random.randint(0,2)# square vs triangle
wave[w][inc_frame] = nz_random() # frame increment
wave[w][inc_pixel] = nz_random() # pixel increment
wave[w][value_pixel] = wave[w][value_frame]
wave[wave_s][inc_pixel] *= 16 # make saturation & value
wave[wave_v][inc_pixel] *= 16 # blinkier along strip
else: # continue animation
count -= 1
for w in range(3):
wave[w][value_frame] += wave[w][inc_frame]
wave[w][value_pixel] = wave[w][value_frame]
# Render current animation frame. COGNITIVE HAZARD: fixed point math.
for i in range(n_leds): # for each LED along strip...
# Coarse (8-bit) HSV-to-RGB conversion, hue first:
n = (wave[wave_h][value_pixel] % 43) * 6 # angle within sextant
sextant = wave[wave_h][value_pixel] / 43 # sextant number 0-5
# R to Y
if sextant == 0:
r = 255
g = n
b = 0
# Y to G
elif sextant == 1:
r = 254 - n
g = 255
b = 0
# G to C
elif sextant == 2:
r = 0
g = 255
b = n
# C to B
elif sextant == 3:
r = 0
g = 254 - n
b = 255
# B to M
elif sextant == 4:
r = n
g = 0
b = 255
# M to R
else:
r = 255
g = 0
b = 254 - n
# Saturation = 1-256 to allow >>8 instead of /255
s = wave[wave_s][value_pixel]
if wave[wave_s][wave_type]: # triangle wave?
if s & 0x80: # downslope
s = (s & 0x7F) << 1
s1 = 256 - s
else: # upslope
s = s<<1
s1 = 1 + s
s = 255 - s
else:
if s & 0x80: # square wave
s1 = 256 # 100% saturation
s = 0
else: # 0% saturation
s1 = 1
s = 255
# Value (brightness) = 1-256 for similar reasons
v = wave[wave_v][value_pixel]
# value (brightness) = 1-256 for similar reasons
if wave[wave_v][wave_type]: # triangle wave?
if v & 0x80: # downslope
v1 = 64 - ((v & 0x7F) << 1)
else: # upslope
v1 = 1 + (v << 1)
else:
if v & 0x80: # square wave; on/off
v1 = 256
else:
v1 = 1
# gamma rgb values
gr = ((((r * s1) >> 8) + s) * v1) >> 8
gg = ((((g * s1) >> 8) + s) * v1) >> 8
gb = ((((b * s1) >> 8) + s) * v1) >> 8
# gamma rgb indices range check
if -256 < gr < 256:
r = gamma[gr]
if -256 < gg < 256:
g = gamma[gg]
if -256 < gb < 256:
b = gamma[gb]
pixels[i] = (r, g, b)
# update wave values along length of strip (values may wrap, is OK!)
for w in range(3):
wave[w][value_pixel] += wave[w][inc_pixel]
pixels.show()

View file

@ -1,193 +0,0 @@
# SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Adafruit Trinket+NeoPixel animation for Daft Punk-inspired helmet.
# Contains some ATtiny85-specific stuff; won't run as-is on Uno, etc.
# Operates in HSV (hue, saturation, value) colorspace rather than RGB.
# Animation is an interference pattern between two waves; one controls
# saturation, the other controls value (brightness). The wavelength,
# direction, speed and type (square vs triangle wave) for each is randomly
# selected every few seconds. Hue is always linear, but other parameters
# are similarly randomized.
import random
import board
import neopixel
from analogio import AnalogIn
n_leds = 29 # number of LEDs per horn
led_pin = board.D0 # which pin your pixels are connected to
# initialize neopixel strip
pixels = neopixel.NeoPixel(led_pin, n_leds, brightness=1, auto_write=False)
count = 1 # countdown to next animation change
# Gamma-correction table
gamma = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110,
112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133,
135, 137, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186,
189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218,
220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252,
255
]
# initialize 3D list
wave = [0] * 5, [0] * 5, [0] * 5
wave_type = 0 # 0 = square wave, 1 = triangle wave
value_frame = 1 # start-of-frame value
value_pixel = 2 # pixel-to-pixel value
inc_frame = 3 # frame-to-frame increment
inc_pixel = 4 # pixel-to-pixel inc
wave_h = 0 # hue
wave_s = 1 # saturation
wave_v = 2 # brightness
# Random number generator is seeded from an unused 'floating'
# analog input - this helps ensure the random color choices
# aren't always the same order.
pin = AnalogIn(board.A0)
random.seed(pin.value)
pin.deinit()
# generate a non-zero random number for frame and pixel increments
def nz_random():
random_number = 0
while random_number <= 0:
random_number = random.randint(0,15) - 7
return random_number
while True:
w = i = n = s = v = r = g = b = v1 = s1 = 0
if count <= 0: # time for new animation
count = 250 + random.randint(0,250) # effect run for 5-10 sec.
for w in range(3): # three waves (H,S,V)
wave[w][wave_type] = random.randint(0,2)# square vs triangle
wave[w][inc_frame] = nz_random() # frame increment
wave[w][inc_pixel] = nz_random() # pixel increment
wave[w][value_pixel] = wave[w][value_frame]
wave[wave_s][inc_pixel] *= 16 # make saturation & value
wave[wave_v][inc_pixel] *= 16 # blinkier along strip
else: # continue animation
count -= 1
for w in range(3):
wave[w][value_frame] += wave[w][inc_frame]
wave[w][value_pixel] = wave[w][value_frame]
# Render current animation frame. COGNITIVE HAZARD: fixed point math.
for i in range(n_leds): # for each LED along strip...
# Coarse (8-bit) HSV-to-RGB conversion, hue first:
n = (wave[wave_h][value_pixel] % 43) * 6 # angle within sextant
sextant = wave[wave_h][value_pixel] / 43 # sextant number 0-5
# R to Y
if sextant == 0:
r = 255
g = n
b = 0
# Y to G
elif sextant == 1:
r = 254 - n
g = 255
b = 0
# G to C
elif sextant == 2:
r = 0
g = 255
b = n
# C to B
elif sextant == 3:
r = 0
g = 254 - n
b = 255
# B to M
elif sextant == 4:
r = n
g = 0
b = 255
# M to R
else:
r = 255
g = 0
b = 254 - n
# Saturation = 1-256 to allow >>8 instead of /255
s = wave[wave_s][value_pixel]
if wave[wave_s][wave_type]: # triangle wave?
if s & 0x80: # downslope
s = (s & 0x7F) << 1
s1 = 256 - s
else: # upslope
s = s<<1
s1 = 1 + s
s = 255 - s
else:
if s & 0x80: # square wave
s1 = 256 # 100% saturation
s = 0
else: # 0% saturation
s1 = 1
s = 255
# Value (brightness) = 1-256 for similar reasons
v = wave[wave_v][value_pixel]
# value (brightness) = 1-256 for similar reasons
if wave[wave_v][wave_type]: # triangle wave?
if v & 0x80: # downslope
v1 = 64 - ((v & 0x7F) << 1)
else: # upslope
v1 = 1 + (v << 1)
else:
if v & 0x80: # square wave; on/off
v1 = 256
else:
v1 = 1
# gamma rgb values
gr = ((((r * s1) >> 8) + s) * v1) >> 8
gg = ((((g * s1) >> 8) + s) * v1) >> 8
gb = ((((b * s1) >> 8) + s) * v1) >> 8
# gamma rgb indices range check
if -256 < gr < 256:
r = gamma[gr]
if -256 < gg < 256:
g = gamma[gg]
if -256 < gb < 256:
b = gamma[gb]
pixels[i] = (r, g, b)
# update wave values along length of strip (values may wrap, is OK!)
for w in range(3):
wave[w][value_pixel] += wave[w][inc_pixel]
pixels.show()

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2018 Mikey Sklar for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>

View file

@ -0,0 +1,50 @@
# 3D_Printed_Guardian_Sword
# https://learn.adafruit.com/breath-of-the-wild-guardian-sword-led-3d-printed
import time
import board
import neopixel
pin = board.D4 # DIGITAL IO pin for NeoPixel OUTPUT from GEMMA
pixel_count = 93 # number of neopixels
delayval = .01 # 10 ms delay
APIXELS = 14 # number of first orange pixels
BPIXELS = 84 # number of blue pixels
CPIXELS = 93 # second orange pixels
# initialize neopixels
pixels = neopixel.NeoPixel(pin, pixel_count, brightness=1, auto_write=False)
while True:
# For the first 14 pixels, make them orange,
# starting from pixel number 0.
for i in range(0, APIXELS):
# Set Pixels to Orange Color
pixels[i] = (255, 50, 0)
# This sends the updated pixel color to the hardware.
pixels.write()
# Delay for a period of time (in milliseconds).
time.sleep(delayval)
# Fill up 84 pixels with blue,
# starting with pixel number 14.
for i in range(APIXELS, BPIXELS):
# Set Pixels to Orange Color
pixels[i] = (0, 250, 200)
# This sends the updated pixel color to the hardware.
pixels.write()
# Delay for a period of time (in milliseconds).
time.sleep(delayval)
# Fill up 9 pixels with orange,
# starting from pixel number 84.
for i in range(BPIXELS, CPIXELS):
# Set Pixels to Orange Color
pixels[i] = (250, 50, 0)
# This sends the updated pixel color to the hardware.
pixels.write()
# Delay for a period of time (in milliseconds).
time.sleep(delayval)

View file

@ -1,54 +0,0 @@
# SPDX-FileCopyrightText: 2018 Mikey Sklar for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# 3D_Printed_Guardian_Sword
# https://learn.adafruit.com/breath-of-the-wild-guardian-sword-led-3d-printed
import time
import board
import neopixel
pin = board.D4 # DIGITAL IO pin for NeoPixel OUTPUT from GEMMA
pixel_count = 93 # number of neopixels
delayval = .01 # 10 ms delay
APIXELS = 14 # number of first orange pixels
BPIXELS = 84 # number of blue pixels
CPIXELS = 93 # second orange pixels
# initialize neopixels
pixels = neopixel.NeoPixel(pin, pixel_count, brightness=1, auto_write=False)
while True:
# For the first 14 pixels, make them orange,
# starting from pixel number 0.
for i in range(0, APIXELS):
# Set Pixels to Orange Color
pixels[i] = (255, 50, 0)
# This sends the updated pixel color to the hardware.
pixels.write()
# Delay for a period of time (in milliseconds).
time.sleep(delayval)
# Fill up 84 pixels with blue,
# starting with pixel number 14.
for i in range(APIXELS, BPIXELS):
# Set Pixels to Orange Color
pixels[i] = (0, 250, 200)
# This sends the updated pixel color to the hardware.
pixels.write()
# Delay for a period of time (in milliseconds).
time.sleep(delayval)
# Fill up 9 pixels with orange,
# starting from pixel number 84.
for i in range(BPIXELS, CPIXELS):
# Set Pixels to Orange Color
pixels[i] = (250, 50, 0)
# This sends the updated pixel color to the hardware.
pixels.write()
# Delay for a period of time (in milliseconds).
time.sleep(delayval)

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
// Trinket/Gemma + LED matrix backpack jewelry. Plays animated
// sequence on LED matrix. Press reset button to display again,
// or add optional momentary button between pin #1 and +V.

View file

@ -0,0 +1,117 @@
# Trinket/Gemma + LED matrix backpack jewelry. Plays animated
# sequence on LED matrix. Press reset button to display again.
import time
import adafruit_ht16k33.matrix
import board
import busio as io
import touchio
touch = touchio.TouchIn(board.D1)
i2c = io.I2C(board.SCL, board.SDA)
matrix = adafruit_ht16k33.matrix.Matrix8x8(i2c)
# pixels initializers
x_pix = y_pix = 8
x = y = 0
matrix.fill(0)
matrix.show()
# seconds to pause between frames
frame_delay = [.25, .25, .25, .25, .25, .25, .25, .25, .25, .25]
# counter for animation frames
frame_count = 0
# repeat entire animation multiple times
reps = 255
rep_count = reps
# animation bitmaps
animation = [
# frame 1
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 0, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 2
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 1, 1, 0, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 3
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 0, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 4
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 1, 1, 0, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 5
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 6
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 7
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[0, 0, 0, 1, 1, 0, 0, 0], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 8
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 9
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[0, 0, 0, 1, 1, 0, 0, 0], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
]
#
# run until we are out of animation frames
# use Gemma's built-in reset button or switch to restart
#
# populate matrix
while True:
if frame_count < len(animation) and rep_count >= 0:
for x in range(x_pix):
for y in range(y_pix):
matrix.pixel(x, y, animation[frame_count][x][y])
# next animation frame
frame_count += 1
# show animation
matrix.show()
# pause for effect
time.sleep(frame_delay[frame_count])
else:
matrix.fill(0)
matrix.show()
time.sleep(.1)
# track repitions
rep_count -= 1
# play it again
frame_count = 0
# A0/D1 pin has been touched
# reset animation
if touch.value:
frame_count = 0
rep_count = reps

View file

@ -1,8 +1,4 @@
// SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
// Animation data for Trinket/Gemma + LED matrix backpack jewelry.
// Animation data for Trinket/Gemma + LED matrix backpack jewelry.
#define REPS 255 // Number of times to repeat the animation loop (1-255)
const uint8_t PROGMEM anim[] = {

View file

@ -1,122 +0,0 @@
# SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
# SPDX-FileCopyrightText: 2018 Phil Burgess for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
# Trinket/Gemma + LED matrix backpack jewelry. Plays animated
# sequence on LED matrix. Press reset button to display again.
import time
import adafruit_ht16k33.matrix
import board
import busio as io
import touchio
touch = touchio.TouchIn(board.D1)
i2c = io.I2C(board.SCL, board.SDA)
matrix = adafruit_ht16k33.matrix.Matrix8x8(i2c)
# pixels initializers
x_pix = y_pix = 8
x = y = 0
matrix.fill(0)
matrix.show()
# seconds to pause between frames
frame_delay = [.25, .25, .25, .25, .25, .25, .25, .25, .25, .25]
# counter for animation frames
frame_count = 0
# repeat entire animation multiple times
reps = 255
rep_count = reps
# animation bitmaps
animation = [
# frame 1
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 0, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 2
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 1, 1, 0, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 3
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 0, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 4
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 1, 1, 1, 0, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 5
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 6
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 7
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[0, 0, 0, 1, 1, 0, 0, 0], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 8
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
# frame 9
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 1, 1, 1, 1, 0, 1],
[0, 0, 0, 1, 1, 0, 0, 0], [1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 0, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]],
]
#
# run until we are out of animation frames
# use Gemma's built-in reset button or switch to restart
#
# populate matrix
while True:
if frame_count < len(animation) and rep_count >= 0:
for x in range(x_pix):
for y in range(y_pix):
matrix.pixel(x, y, animation[frame_count][x][y])
# next animation frame
frame_count += 1
# show animation
matrix.show()
# pause for effect
time.sleep(frame_delay[frame_count])
else:
matrix.fill(0)
matrix.show()
time.sleep(.1)
# track repitions
rep_count -= 1
# play it again
frame_count = 0
# A0/D1 pin has been touched
# reset animation
if touch.value:
frame_count = 0
rep_count = reps

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2017 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
// Fiery demon horns (rawr!) for Adafruit Trinket/Gemma.
// Adafruit invests time and resources providing this open source code,
// please support Adafruit and open-source hardware by purchasing

View file

@ -0,0 +1,147 @@
# Fiery demon horns (rawr!) for Adafruit Trinket/Gemma.
# Adafruit invests time and resources providing this open source code,
# please support Adafruit and open-source hardware by purchasing
# products from Adafruit!
import board
import neopixel
from analogio import AnalogIn
# pylint: disable=global-statement
try:
import urandom as random
except ImportError:
import random
# /\ -> Fire-like effect is the sum_total of multiple triangle
# ____/ \____ waves in motion, with a 'warm' color map applied.
n_horns = 1 # number of horns
led_pin = board.D0 # which pin your pixels are connected to
n_leds = 30 # number of LEDs per horn
frames_per_second = 50 # animation frames per second
brightness = 0 # current wave height
fade = 0 # Decreases brightness as wave moves
pixels = neopixel.NeoPixel(led_pin, n_leds, brightness=1, auto_write=False)
offset = 0
# Coordinate space for waves is 16x the pixel spacing,
# allowing fixed-point math to be used instead of floats.
lower = 0 # lower bound of wave
upper = 1 # upper bound of wave
mid = 2 # midpoint (peak) ((lower+upper)/2)
vlower = 3 # velocity of lower bound
vupper = 4 # velocity of upper bound
intensity = 5 # brightness at peak
y = 0
brightness = 0
count = 0
# initialize 3D list
wave = [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6
# Number of simultaneous waves (per horn)
n_waves = len(wave)
# Gamma-correction table
gamma = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110,
112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133,
135, 137, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186,
189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218,
220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252,
255
]
def random_wave(he, wi):
wave[he][wi][upper] = -1 # Always start below head of strip
wave[he][wi][lower] = -16 * (3 + random.randint(0,4)) # Lower end starts ~3-7 pixels back
wave[he][wi][mid] = (wave[he][wi][lower]+ wave[he][wi][upper]) / 2
wave[he][wi][vlower] = 3 + random.randint(0,4) # Lower end moves at ~1/8 to 1/pixels
wave[he][wi][vupper] = wave[he][wi][vlower]+ random.randint(0,4) # Upper end moves a bit faster
wave[he][wi][intensity] = 300 + random.randint(0,600)
def setup():
global fade
# Random number generator is seeded from an unused 'floating'
# analog input - this helps ensure the random color choices
# aren't always the same order.
pin = AnalogIn(board.A0)
random.seed(pin.value)
pin.deinit()
for he in range(n_horns):
for wi in range(n_waves):
random_wave(he, wi)
fade = 233 + n_leds / 2
if fade > 233:
fade = 233
setup()
while True:
h = w = i = r = g = b = 0
x = 0
for h in range(n_horns): # For each horn...
x = 7
sum_total = 0
for i in range(n_leds): # For each LED along horn...
x += 16
for w in range(n_waves): # For each wave of horn...
if (x < wave[h][w][lower]) or (x > wave[h][w][upper]):
continue # Out of range
if x <= wave[h][w][mid]: # Lower half of wave (ramping up peak brightness)
sum_top = wave[h][w][intensity] * (x - wave[h][w][lower])
sum_bottom = (wave[h][w][mid] - wave[h][w][lower])
sum_total += sum_top / sum_bottom
else: # Upper half of wave (ramping down from peak)
sum_top = wave[h][w][intensity] * (wave[h][w][upper] - x)
sum_bottom = (wave[h][w][upper] - wave[h][w][mid])
sum_total += sum_top / sum_bottom
sum_total = int(sum_total) # convert from decimal to whole number
# Now the magnitude (sum_total) is remapped to color for the LEDs.
# A blackbody palette is used - fades white-yellow-red-black.
if sum_total < 255: # 0-254 = black to red-1
r = gamma[sum_total]
g = b = 0
elif sum_total < 510: # 255-509 = red to yellow-1
r = 255
g = gamma[sum_total - 255]
b = 0
elif sum_total < 765: # 510-764 = yellow to white-1
r = g = 255
b = gamma[sum_total - 510]
else: # 765+ = white
r = g = b = 255
pixels[i] = (r, g, b)
for w in range(n_waves): # Update wave positions for each horn
wave[h][w][lower] += wave[h][w][vlower] # Advance lower position
if wave[h][w][lower] >= (n_leds * 16): # Off end of strip?
random_wave(h, w) # Yes, 'reboot' wave
else: # No, adjust other values...
wave[h][w][upper] += wave[h][w][vupper]
wave[h][w][mid] = (wave[h][w][lower] + wave[h][w][upper]) / 2
wave[h][w][intensity] = (wave[h][w][intensity] * fade) / 256 # Dimmer
pixels.show()

View file

@ -1,151 +0,0 @@
# SPDX-FileCopyrightText: 2018 Phil Burgess and Mikey Sklar for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Fiery demon horns (rawr!) for Adafruit Trinket/Gemma.
# Adafruit invests time and resources providing this open source code,
# please support Adafruit and open-source hardware by purchasing
# products from Adafruit!
import board
import neopixel
from analogio import AnalogIn
# pylint: disable=global-statement
try:
import urandom as random
except ImportError:
import random
# /\ -> Fire-like effect is the sum_total of multiple triangle
# ____/ \____ waves in motion, with a 'warm' color map applied.
n_horns = 1 # number of horns
led_pin = board.D0 # which pin your pixels are connected to
n_leds = 30 # number of LEDs per horn
frames_per_second = 50 # animation frames per second
brightness = 0 # current wave height
fade = 0 # Decreases brightness as wave moves
pixels = neopixel.NeoPixel(led_pin, n_leds, brightness=1, auto_write=False)
offset = 0
# Coordinate space for waves is 16x the pixel spacing,
# allowing fixed-point math to be used instead of floats.
lower = 0 # lower bound of wave
upper = 1 # upper bound of wave
mid = 2 # midpoint (peak) ((lower+upper)/2)
vlower = 3 # velocity of lower bound
vupper = 4 # velocity of upper bound
intensity = 5 # brightness at peak
y = 0
brightness = 0
count = 0
# initialize 3D list
wave = [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6, [[0] * 6] * 6
# Number of simultaneous waves (per horn)
n_waves = len(wave)
# Gamma-correction table
gamma = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110,
112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133,
135, 137, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186,
189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218,
220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252,
255
]
def random_wave(he, wi):
wave[he][wi][upper] = -1 # Always start below head of strip
wave[he][wi][lower] = -16 * (3 + random.randint(0,4)) # Lower end starts ~3-7 pixels back
wave[he][wi][mid] = (wave[he][wi][lower]+ wave[he][wi][upper]) / 2
wave[he][wi][vlower] = 3 + random.randint(0,4) # Lower end moves at ~1/8 to 1/pixels
wave[he][wi][vupper] = wave[he][wi][vlower]+ random.randint(0,4) # Upper end moves a bit faster
wave[he][wi][intensity] = 300 + random.randint(0,600)
def setup():
global fade
# Random number generator is seeded from an unused 'floating'
# analog input - this helps ensure the random color choices
# aren't always the same order.
pin = AnalogIn(board.A0)
random.seed(pin.value)
pin.deinit()
for he in range(n_horns):
for wi in range(n_waves):
random_wave(he, wi)
fade = 233 + n_leds / 2
if fade > 233:
fade = 233
setup()
while True:
h = w = i = r = g = b = 0
x = 0
for h in range(n_horns): # For each horn...
x = 7
sum_total = 0
for i in range(n_leds): # For each LED along horn...
x += 16
for w in range(n_waves): # For each wave of horn...
if (x < wave[h][w][lower]) or (x > wave[h][w][upper]):
continue # Out of range
if x <= wave[h][w][mid]: # Lower half of wave (ramping up peak brightness)
sum_top = wave[h][w][intensity] * (x - wave[h][w][lower])
sum_bottom = (wave[h][w][mid] - wave[h][w][lower])
sum_total += sum_top / sum_bottom
else: # Upper half of wave (ramping down from peak)
sum_top = wave[h][w][intensity] * (wave[h][w][upper] - x)
sum_bottom = (wave[h][w][upper] - wave[h][w][mid])
sum_total += sum_top / sum_bottom
sum_total = int(sum_total) # convert from decimal to whole number
# Now the magnitude (sum_total) is remapped to color for the LEDs.
# A blackbody palette is used - fades white-yellow-red-black.
if sum_total < 255: # 0-254 = black to red-1
r = gamma[sum_total]
g = b = 0
elif sum_total < 510: # 255-509 = red to yellow-1
r = 255
g = gamma[sum_total - 255]
b = 0
elif sum_total < 765: # 510-764 = yellow to white-1
r = g = 255
b = gamma[sum_total - 510]
else: # 765+ = white
r = g = b = 255
pixels[i] = (r, g, b)
for w in range(n_waves): # Update wave positions for each horn
wave[h][w][lower] += wave[h][w][vlower] # Advance lower position
if wave[h][w][lower] >= (n_leds * 16): # Off end of strip?
random_wave(h, w) # Yes, 'reboot' wave
else: # No, adjust other values...
wave[h][w][upper] += wave[h][w][vupper]
wave[h][w][mid] = (wave[h][w][lower] + wave[h][w][upper]) / 2
wave[h][w][intensity] = (wave[h][w][intensity] * fade) / 256 # Dimmer
pixels.show()

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: 2013 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: BSD-3-Clause
/*
LED VU meter for Arduino and Adafruit NeoPixel LEDs.

View file

@ -0,0 +1,195 @@
# LED VU meter for Arduino and Adafruit NeoPixel LEDs.
# Hardware requirements:
# - M0 boards
# - Adafruit Electret Microphone Amplifier (ID: 1063)
# - Adafruit Flora RGB Smart Pixels (ID: 1260)
# OR
# - Adafruit NeoPixel Digital LED strip (ID: 1138)
# - Optional: battery for portable use (else power through USB or adapter)
# Software requirements:
# - Adafruit NeoPixel library
# Connections:
# - 3.3V to mic amp +
# - GND to mic amp -
# - Analog pin to microphone output (configurable below)
# - Digital pin to LED data input (configurable below)
# See notes in setup() regarding 5V vs. 3.3V boards - there may be an
# extra connection to make and one line of code to enable or disable.
# Written by Adafruit Industries. Distributed under the BSD license.
# This paragraph must be included in any redistribution.
# fscale function:
# Floating Point Autoscale Function V0.1
# Written by Paul Badger 2007
# Modified fromhere code by Greg Shakar
# Ported to Circuit Python by Mikey Sklar
import time
import board
import neopixel
from analogio import AnalogIn
n_pixels = 16 # Number of pixels you are using
mic_pin = AnalogIn(board.A1) # Microphone is attached to this analog pin
led_pin = board.D1 # NeoPixel LED strand is connected to this pin
sample_window = .1 # Sample window for average level
peak_hang = 24 # Time of pause before peak dot falls
peak_fall = 4 # Rate of falling peak dot
input_floor = 10 # Lower range of analogRead input
# Max range of analogRead input, the lower the value the more sensitive
# (1023 = max)
input_ceiling = 300
peak = 16 # Peak level of column; used for falling dots
sample = 0
dotcount = 0 # Frame counter for peak dot
dothangcount = 0 # Frame counter for holding peak dot
strip = neopixel.NeoPixel(led_pin, n_pixels, brightness=1, auto_write=False)
def wheel(pos):
# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
if pos < 0 or pos > 255:
return (0, 0, 0)
if pos < 85:
return (int(pos * 3), int(255 - (pos * 3)), 0)
elif pos < 170:
pos -= 85
return (int(255 - pos * 3), 0, int(pos * 3))
else:
pos -= 170
return (0, int(pos * 3), int(255 - pos * 3))
def remapRange(value, leftMin, leftMax, rightMin, rightMax):
# this remaps a value fromhere original (left) range to new (right) range
# Figure out how 'wide' each range is
leftSpan = leftMax - leftMin
rightSpan = rightMax - rightMin
# Convert the left range into a 0-1 range (int)
valueScaled = int(value - leftMin) / int(leftSpan)
# Convert the 0-1 range into a value in the right range.
return int(rightMin + (valueScaled * rightSpan))
def fscale(originalmin, originalmax, newbegin, newend, inputvalue, curve):
invflag = 0
# condition curve parameter
# limit range
if curve > 10:
curve = 10
if curve < -10:
curve = -10
# - invert and scale -
# this seems more intuitive
# postive numbers give more weight to high end on output
curve = (curve * -.1)
# convert linear scale into lograthimic exponent for other pow function
curve = pow(10, curve)
# Check for out of range inputValues
if inputvalue < originalmin:
inputvalue = originalmin
if inputvalue > originalmax:
inputvalue = originalmax
# Zero Refference the values
originalrange = originalmax - originalmin
if newend > newbegin:
newrange = newend - newbegin
else:
newrange = newbegin - newend
invflag = 1
zerorefcurval = inputvalue - originalmin
# normalize to 0 - 1 float
normalizedcurval = zerorefcurval / originalrange
# Check for originalMin > originalMax
# -the math for all other cases
# i.e. negative numbers seems to work out fine
if originalmin > originalmax:
return 0
if invflag == 0:
rangedvalue = (pow(normalizedcurval, curve) * newrange) + newbegin
else: # invert the ranges
rangedvalue = newbegin - (pow(normalizedcurval, curve) * newrange)
return rangedvalue
def drawLine(fromhere, to):
if fromhere > to:
fromheretemp = fromhere
fromhere = to
to = fromheretemp
for index in range(fromhere, to):
strip[index] = (0, 0, 0)
while True:
time_start = time.monotonic() # current time used for sample window
peaktopeak = 0 # peak-to-peak level
signalmax = 0
signalmin = 1023
c = 0
y = 0
# collect data for length of sample window (in seconds)
while (time.monotonic() - time_start) < sample_window:
# convert to arduino 10-bit [1024] fromhere 16-bit [65536]
sample = mic_pin.value / 64
if sample < 1024: # toss out spurious readings
if sample > signalmax:
signalmax = sample # save just the max levels
elif sample < signalmin:
signalmin = sample # save just the min levels
peaktopeak = signalmax - signalmin # max - min = peak-peak amplitude
# Fill the strip with rainbow gradient
for i in range(0, len(strip)):
strip[i] = wheel(remapRange(i, 0, (n_pixels - 1), 30, 150))
# Scale the input logarithmically instead of linearly
c = fscale(input_floor, input_ceiling, (n_pixels - 1), 0, peaktopeak, 2)
if c < peak:
peak = c # keep dot on top
dothangcount = 0 # make the dot hang before falling
if c <= n_pixels: # fill partial column with off pixels
drawLine(n_pixels, n_pixels - int(c))
# Set the peak dot to match the rainbow gradient
y = n_pixels - peak
strip.fill = (y - 1, wheel(remapRange(y, 0, (n_pixels - 1), 30, 150)))
strip.write()
# Frame based peak dot animation
if dothangcount > peak_hang: # Peak pause length
dotcount += 1
if dotcount >= peak_fall: # Fall rate
peak += 1
dotcount = 0
else:
dothangcount += 1

View file

@ -1,184 +0,0 @@
# SPDX-FileCopyrightText: 2013 Phil Burgess for Adafruit Industries
# SPDX-FileCopyrightText: 2017 Mikey Sklar for Adafruit Industries
#
# SPDX-License-Identifier: BSD-3-Clause
# LED VU meter for Arduino and Adafruit NeoPixel LEDs.
# Hardware requirements:
# - M0 boards
# - Adafruit Electret Microphone Amplifier (ID: 1063)
# - Adafruit Flora RGB Smart Pixels (ID: 1260)
# OR
# - Adafruit NeoPixel Digital LED strip (ID: 1138)
# - Optional: battery for portable use (else power through USB or adapter)
# Software requirements:
# - Adafruit NeoPixel library
# Connections:
# - 3.3V to mic amp +
# - GND to mic amp -
# - Analog pin to microphone output (configurable below)
# - Digital pin to LED data input (configurable below)
# See notes in setup() regarding 5V vs. 3.3V boards - there may be an
# extra connection to make and one line of code to enable or disable.
# Written by Adafruit Industries. Distributed under the BSD license.
# This paragraph must be included in any redistribution.
# fscale function:
# Floating Point Autoscale Function V0.1
# Written by Paul Badger 2007
# Modified fromhere code by Greg Shakar
# Ported to Circuit Python by Mikey Sklar
import time
import board
import neopixel
from rainbowio import colorwheel
from analogio import AnalogIn
n_pixels = 16 # Number of pixels you are using
mic_pin = AnalogIn(board.A1) # Microphone is attached to this analog pin
led_pin = board.D1 # NeoPixel LED strand is connected to this pin
sample_window = .1 # Sample window for average level
peak_hang = 24 # Time of pause before peak dot falls
peak_fall = 4 # Rate of falling peak dot
input_floor = 10 # Lower range of analogRead input
# Max range of analogRead input, the lower the value the more sensitive
# (1023 = max)
input_ceiling = 300
peak = 16 # Peak level of column; used for falling dots
sample = 0
dotcount = 0 # Frame counter for peak dot
dothangcount = 0 # Frame counter for holding peak dot
strip = neopixel.NeoPixel(led_pin, n_pixels, brightness=1, auto_write=False)
def remapRange(value, leftMin, leftMax, rightMin, rightMax):
# this remaps a value fromhere original (left) range to new (right) range
# Figure out how 'wide' each range is
leftSpan = leftMax - leftMin
rightSpan = rightMax - rightMin
# Convert the left range into a 0-1 range (int)
valueScaled = int(value - leftMin) / int(leftSpan)
# Convert the 0-1 range into a value in the right range.
return int(rightMin + (valueScaled * rightSpan))
def fscale(originalmin, originalmax, newbegin, newend, inputvalue, curve):
invflag = 0
# condition curve parameter
# limit range
if curve > 10:
curve = 10
if curve < -10:
curve = -10
# - invert and scale -
# this seems more intuitive
# postive numbers give more weight to high end on output
curve = (curve * -.1)
# convert linear scale into lograthimic exponent for other pow function
curve = pow(10, curve)
# Check for out of range inputValues
if inputvalue < originalmin:
inputvalue = originalmin
if inputvalue > originalmax:
inputvalue = originalmax
# Zero Refference the values
originalrange = originalmax - originalmin
if newend > newbegin:
newrange = newend - newbegin
else:
newrange = newbegin - newend
invflag = 1
zerorefcurval = inputvalue - originalmin
# normalize to 0 - 1 float
normalizedcurval = zerorefcurval / originalrange
# Check for originalMin > originalMax
# -the math for all other cases
# i.e. negative numbers seems to work out fine
if originalmin > originalmax:
return 0
if invflag == 0:
rangedvalue = (pow(normalizedcurval, curve) * newrange) + newbegin
else: # invert the ranges
rangedvalue = newbegin - (pow(normalizedcurval, curve) * newrange)
return rangedvalue
def drawLine(fromhere, to):
if fromhere > to:
to, fromhere = fromhere, to
for index in range(fromhere, to):
strip[index] = (0, 0, 0)
while True:
time_start = time.monotonic() # current time used for sample window
peaktopeak = 0 # peak-to-peak level
signalmax = 0
signalmin = 1023
c = 0
y = 0
# collect data for length of sample window (in seconds)
while (time.monotonic() - time_start) < sample_window:
# convert to arduino 10-bit [1024] fromhere 16-bit [65536]
sample = mic_pin.value / 64
if sample < 1024: # toss out spurious readings
if sample > signalmax:
signalmax = sample # save just the max levels
elif sample < signalmin:
signalmin = sample # save just the min levels
peaktopeak = signalmax - signalmin # max - min = peak-peak amplitude
# Fill the strip with rainbow gradient
for i in range(0, len(strip)):
strip[i] = colorwheel(remapRange(i, 0, (n_pixels - 1), 30, 150))
# Scale the input logarithmically instead of linearly
c = fscale(input_floor, input_ceiling, (n_pixels - 1), 0, peaktopeak, 2)
if c < peak:
peak = c # keep dot on top
dothangcount = 0 # make the dot hang before falling
if c <= n_pixels: # fill partial column with off pixels
drawLine(n_pixels, n_pixels - int(c))
# Set the peak dot to match the rainbow gradient
y = n_pixels - peak
strip.fill = (y - 1, colorwheel(remapRange(y, 0, (n_pixels - 1), 30, 150)))
strip.write()
# Frame based peak dot animation
if dothangcount > peak_hang: # Peak pause length
dotcount += 1
if dotcount >= peak_fall: # Fall rate
peak += 1
dotcount = 0
else:
dothangcount += 1

View file

@ -1,8 +1,3 @@
// SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
#include <Adafruit_NeoPixel.h>
#define PIN 0

View file

@ -0,0 +1,58 @@
import time
import board
import neopixel
try:
import urandom as random # for v1.0 API support
except ImportError:
import random
numpix = 24 # Number of NeoPixels
pixpin = board.D0 # Pin where NeoPixels are connected
strip = neopixel.NeoPixel(pixpin, numpix, brightness=0.3)
mode = 0 # Current animation effect
offset = 0 # Position of spinner animation
color = [255, 0, 0] # RGB color - red
prevtime = time.monotonic() # Time of last animation mode switch
while True: # Loop forever...
if mode == 0: # Random sparkles - lights just one LED at a time
i = random.randint(0, numpix - 1) # Choose random pixel
strip[i] = color # Set it to current color
strip.write() # Refresh LED states
# Set same pixel to "off" color now but DON'T refresh...
# it stays on for now...bot this and the next random
# pixel will be refreshed on the next pass.
strip[i] = [0, 0, 0]
time.sleep(0.008) # 8 millisecond delay
elif mode == 1: # Spinny wheels
# A little trick here: pixels are processed in groups of 8
# (with 2 of 8 on at a time), NeoPixel rings are 24 pixels
# (8*3) and 16 pixels (8*2), so we can issue the same data
# to both rings and it appears correct and contiguous
# (also, the pixel order is different between the two ring
# types, so we get the reversed motion on #2 for free).
for i in range(numpix): # For each LED...
if ((offset + i) & 7) < 2: # 2 pixels out of 8...
strip[i] = color # are set to current color
else:
strip[i] = [0, 0, 0] # other pixels are off
strip.write() # Refresh LED states
time.sleep(0.04) # 40 millisecond delay
offset += 1 # Shift animation by 1 pixel on next frame
if offset >= 8:
offset = 0
# Additional animation modes could be added here!
t = time.monotonic() # Current time in seconds
if (t - prevtime) >= 8: # Every 8 seconds...
mode += 1 # Advance to next mode
if mode > 1: # End of modes?
mode = 0 # Start over from beginning
# Rotate color R->G->B
color = [color[2], color[0], color[1]]
strip.fill([0, 0, 0]) # Turn off all pixels
prevtime = t # Record time of last mode change

View file

@ -1,62 +0,0 @@
# SPDX-FileCopyrightText: 2017 Phil Burgess for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
import time
import board
import neopixel
try:
import urandom as random # for v1.0 API support
except ImportError:
import random
numpix = 24 # Number of NeoPixels
pixpin = board.D0 # Pin where NeoPixels are connected
strip = neopixel.NeoPixel(pixpin, numpix, brightness=0.3)
mode = 0 # Current animation effect
offset = 0 # Position of spinner animation
color = [255, 0, 0] # RGB color - red
prevtime = time.monotonic() # Time of last animation mode switch
while True: # Loop forever...
if mode == 0: # Random sparkles - lights just one LED at a time
i = random.randint(0, numpix - 1) # Choose random pixel
strip[i] = color # Set it to current color
strip.write() # Refresh LED states
# Set same pixel to "off" color now but DON'T refresh...
# it stays on for now...bot this and the next random
# pixel will be refreshed on the next pass.
strip[i] = [0, 0, 0]
time.sleep(0.008) # 8 millisecond delay
elif mode == 1: # Spinny wheels
# A little trick here: pixels are processed in groups of 8
# (with 2 of 8 on at a time), NeoPixel rings are 24 pixels
# (8*3) and 16 pixels (8*2), so we can issue the same data
# to both rings and it appears correct and contiguous
# (also, the pixel order is different between the two ring
# types, so we get the reversed motion on #2 for free).
for i in range(numpix): # For each LED...
if ((offset + i) & 7) < 2: # 2 pixels out of 8...
strip[i] = color # are set to current color
else:
strip[i] = [0, 0, 0] # other pixels are off
strip.write() # Refresh LED states
time.sleep(0.04) # 40 millisecond delay
offset += 1 # Shift animation by 1 pixel on next frame
if offset >= 8:
offset = 0
# Additional animation modes could be added here!
t = time.monotonic() # Current time in seconds
if (t - prevtime) >= 8: # Every 8 seconds...
mode += 1 # Advance to next mode
if mode > 1: # End of modes?
mode = 0 # Start over from beginning
# Rotate color R->G->B
color = [color[2], color[0], color[1]]
strip.fill([0, 0, 0]) # Turn off all pixels
prevtime = t # Record time of last mode change

View file

@ -1,7 +1,4 @@
// SPDX-FileCopyrightText: 2014 HerrRausB https://github.com/HerrRausB
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
/******************************************************************************
*
* this file is part of the gemma hoop animator example sketch

View file

@ -0,0 +1,311 @@
#
# 3D_Printed_NeoPixel_Ring_Hair_Dress.py
#
# this was ported to CircuitPython from the 'Gemma Hoop Animator'
#
# https://github.com/HerrRausB/GemmaHoopAnimator
#
# unless you # don't like the preset animations or find a
# major bug, you don't need tochange anything here
#
import time
import board
import neopixel
try:
import urandom as random # for v1.0 API support
except ImportError:
import random
from analogio import AnalogIn
# available actions
ACT_NOP = 0x00 # all leds off, do nothing
ACT_SIMPLE_RING = 0x01 # all leds on
ACT_CYCLING_RING_ACLK = 0x02 # anti clockwise cycling colors
ACT_CYCLING_RING_CLKW = 0x04 # clockwise cycling colors
ACT_WHEEL_ACLK = 0x08 # anti clockwise spinning wheel
ACT_WHEEL_CLKW = 0x10 # clockwise spinning wheel
ACT_SPARKLING_RING = 0x20 # sparkling effect
numpix = 16 # total number of NeoPixels
pixel_output = board.D0 # pin where NeoPixels are connected
analog_input = board.A0 # needed to seed the random generator
strip = neopixel.NeoPixel(pixel_output, numpix,
brightness=.3, auto_write=False)
# available color generation methods
COL_RANDOM = 0x40 # colors will be generated randomly
COL_SPECTRUM = 0x80 # colors will be set as cyclic spectral wipe
# specifiyng the action list
# the action's overall duration in milliseconds (be careful not
action_duration = 0
# to use values > 2^16-1 - roughly one minute :-)
action_and_color_gen = 1 # the color generation method
# the duration of each action step rsp. the delay of the main
action_step_duration = 2
# loop in milliseconds - thus, controls the action speed (be
# careful not to use values > 2^16-1 - roughly one minute :-)
color_granularity = 3 # controls the increment of the R, G, and B
# portions of the rsp. color. 1 means the increment is 0,1,2,3,...,
# 10 means the increment is 0,10,20,... don't use values > 255, and
# note that even values > 127 wouldn't make much sense...
# controls the speed of color changing independently from action
color_interval = 4
# general global variables
color = 0
color_timer = 0
action_timer = 0
action_step_timer = 0
color_idx = 0
curr_color_interval = 0
curr_action_step_duration = 0
curr_action_duration = 0
curr_action = 0
curr_color_gen = COL_RANDOM
idx = 0
offset = 0
number_of_actions = 31
curr_action_idx = 0
curr_color_granularity = 1
spectrum_part = 0
# defining the animation actions by simply initializing the array of actions
# this array variable must be called theactionlist !!!
#
# valid actions are:
# ACT_NOP simply do nothing and switch everything off
# ACT_SIMPLE_RING all leds on
# ACT_CYCLING_RING_ACLK anti clockwise cycling colors
# ACT_CYCLING_RING_CLKW clockwise cycling colors acording
# ACT_WHEEL_ACLK anti clockwise spinning wheel
# ACT_WHEEL_CLKW clockwise spinning wheel
# ACT_SPARKLING_RING sparkling effect
#
# valid color options are:
# COL_RANDOM colors will be selected randomly, which might
# be not very sufficient due to well known
# limitations of the random generation algorithm
# COL_SPECTRUM colors will be set as cyclic spectral wipe
# R -> G -> B -> R -> G -> B -> R -> ...
# action action name & action step color color change
# duration color generation method duration granularity interval
theactionlist = [
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2, ACT_CYCLING_RING_CLKW | COL_RANDOM,
0.02, 1, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2, ACT_CYCLING_RING_ACLK | COL_RANDOM,
0.02, 1, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2.5, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.25, 20, 0.020],
[1, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.50, 1, 0.020],
[.750, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.075, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.100, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.125, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.150, 1, 0.050],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.175, 1, 0.100],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.200, 1, 0.200],
[.750, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.225, 1, 0.250],
[1, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.250, 1, 0.350],
[30, ACT_SIMPLE_RING | COL_SPECTRUM,
0.050, 1, 0.010],
[2.5, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.010, 1, 0.010],
[2.5, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.015, 1, 0.020],
[2, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.025, 1, 0.030],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.050, 1, 0.040],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.075, 1, 0.040],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.100, 1, 0.050],
[.500, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.125, 1, 0.060],
[.500, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.125, 5, 0.050],
[1, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.100, 10, 0.040],
[1.5, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.075, 15, 0.030],
[2, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.050, 20, 0.020],
[2.5, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.025, 25, 0.010],
[3, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.010, 30, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.010, 25, 1],
[5, ACT_NOP, 0, 0, 0]
]
# pylint: disable=global-statement
def nextspectrumcolor():
global spectrum_part, color_idx, curr_color_granularity, color
# spectral wipe from green to red
if spectrum_part == 2:
color = (color_idx, 0, 255-color_idx)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 0
color_idx = 0
# spectral wipe from blue to green
elif spectrum_part == 1:
color = (0, 255 - color_idx, color_idx)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 2
color_idx = 0
# spectral wipe from red to blue
elif spectrum_part == 0:
color = (255 - color_idx, color_idx, 0)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 1
color_idx = 0
def nextrandomcolor():
global color
# granularity = 1 --> [0 .. 255] * 1 --> 0,1,2,3 ... 255
# granularity = 10 --> [0 .. 25] * 10 --> 0,10,20,30 ... 250
# granularity = 100 --> [0 .. 2] * 100 --> 0,100, 200 (boaring...)
random_red = random.randint(0, int(256 / curr_color_granularity))
random_red *= curr_color_granularity
random_green = random.randint(0, int(256 / curr_color_granularity))
random_green *= curr_color_granularity
random_blue = random.randint(0, int(256 / curr_color_granularity))
random_blue *= curr_color_granularity
color = (random_red, random_green, random_blue)
def nextcolor():
# save some RAM for more animation actions
if curr_color_gen & COL_RANDOM:
nextrandomcolor()
else:
nextspectrumcolor()
def setup():
# fingers corssed, the seeding makes sense to really get random colors...
apin = AnalogIn(analog_input)
random.seed(apin.value)
apin.deinit()
# let's go!
nextcolor()
strip.write()
setup()
while True: # Loop forever...
# do we need to load the next action?
if (time.monotonic() - action_timer) > curr_action_duration:
current_action = theactionlist[curr_action_idx]
curr_action_duration = current_action[action_duration]
curr_action = current_action[action_and_color_gen] & 0x3F
curr_action_step_duration = current_action[action_step_duration]
curr_color_gen = current_action[action_and_color_gen] & 0xC0
curr_color_granularity = current_action[color_granularity]
curr_color_interval = current_action[color_interval]
curr_action_idx += 1
# take care to rotate the action list!
curr_action_idx %= number_of_actions
action_timer = time.monotonic()
# do we need to change to the next color?
if (time.monotonic() - color_timer) > curr_color_interval:
nextcolor()
color_timer = time.monotonic()
# do we need to step up the current action?
if (time.monotonic() - action_step_timer) > curr_action_step_duration:
if curr_action:
is_act_cycling = (ACT_CYCLING_RING_ACLK or ACT_CYCLING_RING_CLKW)
if curr_action == ACT_NOP:
# rather trivial even tho this will be repeated as long as the
# NOP continues - i could have prevented it from repeating
# unnecessarily, but that would mean more code and less
# space for more actions within the animation
for i in range(0, numpix):
strip[i] = (0, 0, 0)
elif curr_action == ACT_SIMPLE_RING:
# even more trivial - just set the new color, if there is one
for i in range(0, numpix):
strip[i] = color
elif curr_action == is_act_cycling:
# spin the ring clockwise or anti clockwise
if curr_action == ACT_CYCLING_RING_ACLK:
idx += 1
else:
idx -= 1
# prevent overflows or underflows
idx %= numpix
# set the new color, if there is one
strip[idx] = color
elif curr_action == ACT_WHEEL_ACLK or ACT_WHEEL_CLKW:
# switch on / off the appropriate pixels according to
# the current offset
for idx in range(0, numpix):
if ((offset + idx) & 7) < 2:
strip[idx] = color
else:
strip[idx] = (0, 0, 0)
# advance the offset and thus, spin the wheel
if curr_action == ACT_WHEEL_CLKW:
offset += 1
else:
offset -= 1
# prevent overflows or underflows
offset %= numpix
elif curr_action == ACT_SPARKLING_RING:
# switch current pixel off
strip[idx] = (0, 0, 0)
# pick a new pixel
idx = random.randint(0, numpix)
# set new pixel to the current color
strip[idx] = color
strip.write()
action_step_timer = time.monotonic()

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2014 HerrRausB https://github.com/HerrRausB
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
/******************************************************************************
*
* this file is part of the gemma hoop animator example sketch

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2014 HerrRausB https://github.com/HerrRausB
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
/******************************************************************************
*
* this file is part of the gemma hoop animator example sketch

View file

@ -1,315 +0,0 @@
# SPDX-FileCopyrightText: 2014 HerrRausB https://github.com/HerrRausB
# SPDX-FileCopyrightText: 2017 Mikey Sklar for Adafruit Industries
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
# 3D_Printed_NeoPixel_Ring_Hair_Dress.py
#
# this was ported to CircuitPython from the 'Gemma Hoop Animator'
#
# https://github.com/HerrRausB/GemmaHoopAnimator
#
# unless you # don't like the preset animations or find a
# major bug, you don't need tochange anything here
#
import time
import board
import neopixel
try:
import urandom as random # for v1.0 API support
except ImportError:
import random
from analogio import AnalogIn
# available actions
ACT_NOP = 0x00 # all leds off, do nothing
ACT_SIMPLE_RING = 0x01 # all leds on
ACT_CYCLING_RING_ACLK = 0x02 # anti clockwise cycling colors
ACT_CYCLING_RING_CLKW = 0x04 # clockwise cycling colors
ACT_WHEEL_ACLK = 0x08 # anti clockwise spinning wheel
ACT_WHEEL_CLKW = 0x10 # clockwise spinning wheel
ACT_SPARKLING_RING = 0x20 # sparkling effect
numpix = 16 # total number of NeoPixels
pixel_output = board.D0 # pin where NeoPixels are connected
analog_input = board.A0 # needed to seed the random generator
strip = neopixel.NeoPixel(pixel_output, numpix,
brightness=.3, auto_write=False)
# available color generation methods
COL_RANDOM = 0x40 # colors will be generated randomly
COL_SPECTRUM = 0x80 # colors will be set as cyclic spectral wipe
# specifiyng the action list
# the action's overall duration in milliseconds (be careful not
action_duration = 0
# to use values > 2^16-1 - roughly one minute :-)
action_and_color_gen = 1 # the color generation method
# the duration of each action step rsp. the delay of the main
action_step_duration = 2
# loop in milliseconds - thus, controls the action speed (be
# careful not to use values > 2^16-1 - roughly one minute :-)
color_granularity = 3 # controls the increment of the R, G, and B
# portions of the rsp. color. 1 means the increment is 0,1,2,3,...,
# 10 means the increment is 0,10,20,... don't use values > 255, and
# note that even values > 127 wouldn't make much sense...
# controls the speed of color changing independently from action
color_interval = 4
# general global variables
color = 0
color_timer = 0
action_timer = 0
action_step_timer = 0
color_idx = 0
curr_color_interval = 0
curr_action_step_duration = 0
curr_action_duration = 0
curr_action = 0
curr_color_gen = COL_RANDOM
idx = 0
offset = 0
number_of_actions = 31
curr_action_idx = 0
curr_color_granularity = 1
spectrum_part = 0
# defining the animation actions by simply initializing the array of actions
# this array variable must be called theactionlist !!!
#
# valid actions are:
# ACT_NOP simply do nothing and switch everything off
# ACT_SIMPLE_RING all leds on
# ACT_CYCLING_RING_ACLK anti clockwise cycling colors
# ACT_CYCLING_RING_CLKW clockwise cycling colors acording
# ACT_WHEEL_ACLK anti clockwise spinning wheel
# ACT_WHEEL_CLKW clockwise spinning wheel
# ACT_SPARKLING_RING sparkling effect
#
# valid color options are:
# COL_RANDOM colors will be selected randomly, which might
# be not very sufficient due to well known
# limitations of the random generation algorithm
# COL_SPECTRUM colors will be set as cyclic spectral wipe
# R -> G -> B -> R -> G -> B -> R -> ...
# action action name & action step color color change
# duration color generation method duration granularity interval
theactionlist = [
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2, ACT_CYCLING_RING_CLKW | COL_RANDOM,
0.02, 1, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2, ACT_CYCLING_RING_ACLK | COL_RANDOM,
0.02, 1, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2.5, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.25, 20, 0.020],
[1, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.50, 1, 0.020],
[.750, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.075, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.100, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.125, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.150, 1, 0.050],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.175, 1, 0.100],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.200, 1, 0.200],
[.750, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.225, 1, 0.250],
[1, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.250, 1, 0.350],
[30, ACT_SIMPLE_RING | COL_SPECTRUM,
0.050, 1, 0.010],
[2.5, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.010, 1, 0.010],
[2.5, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.015, 1, 0.020],
[2, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.025, 1, 0.030],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.050, 1, 0.040],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.075, 1, 0.040],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.100, 1, 0.050],
[.500, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.125, 1, 0.060],
[.500, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.125, 5, 0.050],
[1, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.100, 10, 0.040],
[1.5, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.075, 15, 0.030],
[2, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.050, 20, 0.020],
[2.5, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.025, 25, 0.010],
[3, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.010, 30, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.010, 25, 1],
[5, ACT_NOP, 0, 0, 0]
]
# pylint: disable=global-statement
def nextspectrumcolor():
global spectrum_part, color_idx, curr_color_granularity, color
# spectral wipe from green to red
if spectrum_part == 2:
color = (color_idx, 0, 255-color_idx)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 0
color_idx = 0
# spectral wipe from blue to green
elif spectrum_part == 1:
color = (0, 255 - color_idx, color_idx)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 2
color_idx = 0
# spectral wipe from red to blue
elif spectrum_part == 0:
color = (255 - color_idx, color_idx, 0)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 1
color_idx = 0
def nextrandomcolor():
global color
# granularity = 1 --> [0 .. 255] * 1 --> 0,1,2,3 ... 255
# granularity = 10 --> [0 .. 25] * 10 --> 0,10,20,30 ... 250
# granularity = 100 --> [0 .. 2] * 100 --> 0,100, 200 (boaring...)
random_red = random.randint(0, int(256 / curr_color_granularity))
random_red *= curr_color_granularity
random_green = random.randint(0, int(256 / curr_color_granularity))
random_green *= curr_color_granularity
random_blue = random.randint(0, int(256 / curr_color_granularity))
random_blue *= curr_color_granularity
color = (random_red, random_green, random_blue)
def nextcolor():
# save some RAM for more animation actions
if curr_color_gen & COL_RANDOM:
nextrandomcolor()
else:
nextspectrumcolor()
def setup():
# fingers corssed, the seeding makes sense to really get random colors...
apin = AnalogIn(analog_input)
random.seed(apin.value)
apin.deinit()
# let's go!
nextcolor()
strip.write()
setup()
while True: # Loop forever...
# do we need to load the next action?
if (time.monotonic() - action_timer) > curr_action_duration:
current_action = theactionlist[curr_action_idx]
curr_action_duration = current_action[action_duration]
curr_action = current_action[action_and_color_gen] & 0x3F
curr_action_step_duration = current_action[action_step_duration]
curr_color_gen = current_action[action_and_color_gen] & 0xC0
curr_color_granularity = current_action[color_granularity]
curr_color_interval = current_action[color_interval]
curr_action_idx += 1
# take care to rotate the action list!
curr_action_idx %= number_of_actions
action_timer = time.monotonic()
# do we need to change to the next color?
if (time.monotonic() - color_timer) > curr_color_interval:
nextcolor()
color_timer = time.monotonic()
# do we need to step up the current action?
if (time.monotonic() - action_step_timer) > curr_action_step_duration:
if curr_action:
is_act_cycling = (ACT_CYCLING_RING_ACLK or ACT_CYCLING_RING_CLKW)
if curr_action == ACT_NOP:
# rather trivial even tho this will be repeated as long as the
# NOP continues - i could have prevented it from repeating
# unnecessarily, but that would mean more code and less
# space for more actions within the animation
for i in range(0, numpix):
strip[i] = (0, 0, 0)
elif curr_action == ACT_SIMPLE_RING:
# even more trivial - just set the new color, if there is one
for i in range(0, numpix):
strip[i] = color
elif curr_action == is_act_cycling:
# spin the ring clockwise or anti clockwise
if curr_action == ACT_CYCLING_RING_ACLK:
idx += 1
else:
idx -= 1
# prevent overflows or underflows
idx %= numpix
# set the new color, if there is one
strip[idx] = color
elif curr_action == ACT_WHEEL_ACLK or ACT_WHEEL_CLKW:
# switch on / off the appropriate pixels according to
# the current offset
for idx in range(0, numpix):
if ((offset + idx) & 7) < 2:
strip[idx] = color
else:
strip[idx] = (0, 0, 0)
# advance the offset and thus, spin the wheel
if curr_action == ACT_WHEEL_CLKW:
offset += 1
else:
offset -= 1
# prevent overflows or underflows
offset %= numpix
elif curr_action == ACT_SPARKLING_RING:
# switch current pixel off
strip[idx] = (0, 0, 0)
# pick a new pixel
idx = random.randint(0, numpix)
# set new pixel to the current color
strip[idx] = color
strip.write()
action_step_timer = time.monotonic()

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2015 Phil Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
#include <Adafruit_NeoPixel.h>
#define PIN 1

View file

@ -0,0 +1,48 @@
import time
import board
import neopixel
from digitalio import DigitalInOut, Direction
pixpin = board.D1
numpix = 8
led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT
strip = neopixel.NeoPixel(pixpin, numpix, brightness=1, auto_write=True)
def wheel(pos):
# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
if (pos < 0) or (pos > 255):
return (0, 0, 0)
if pos < 85:
return (int(pos * 3), int(255 - (pos*3)), 0)
elif pos < 170:
pos -= 85
return (int(255 - pos * 3), 0, int(pos * 3))
else:
pos -= 170
return (0, int(pos * 3), int(255 - pos * 3))
def rainbow_cycle(wait):
for j in range(255 * 5):
for i in range(len(strip)):
idx = int((i * 256 / len(strip)) + j)
strip[i] = wheel(idx & 255)
time.sleep(wait)
def rainbow(wait):
for j in range(255):
for i in range(len(strip)):
idx = int(i + j)
strip[i] = wheel(idx & 255)
time.sleep(wait)
while True:
rainbow_cycle(0.05)

View file

@ -1,39 +0,0 @@
# SPDX-FileCopyrightText: 2017 Mikey Sklar for Adafruit Industries
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
import time
import board
import neopixel
from rainbowio import colorwheel
from digitalio import DigitalInOut, Direction
pixpin = board.D1
numpix = 8
led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT
strip = neopixel.NeoPixel(pixpin, numpix, brightness=1, auto_write=True)
def rainbow_cycle(wait):
for j in range(255 * 5):
for i in range(len(strip)):
idx = int((i * 256 / len(strip)) + j)
strip[i] = colorwheel(idx & 255)
time.sleep(wait)
def rainbow(wait):
for j in range(255):
for i in range(len(strip)):
idx = int(i + j)
strip[i] = colorwheel(idx & 255)
time.sleep(wait)
while True:
rainbow_cycle(0.05)

Binary file not shown.

View file

@ -1,310 +0,0 @@
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT
import time
import asyncio
import board
import digitalio
from rainbowio import colorwheel
import keypad
import displayio
import i2cdisplaybus
import busio
import adafruit_seesaw.seesaw
import adafruit_seesaw.neopixel
import adafruit_seesaw.rotaryio
import adafruit_seesaw.digitalio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label
import adafruit_displayio_ssd1306
import adafruit_midi
from adafruit_midi.control_change import ControlChange
import neopixel
# default MIDI channel (1-16)
midi_in_channel = 2
midi_out_channel = 2
# MIDI CC messages, values and names assigned to each encoder
cc_values = [
{'cc_val': (0, 127), 'cc_message': (14), 'cc_name': "Volume"},
{'cc_val': (0, 127), 'cc_message': (15), 'cc_name': "Repeats"},
{'cc_val': (0, 127), 'cc_message': (16), 'cc_name': "Size"},
{'cc_val': (0, 127), 'cc_message': (17), 'cc_name': "Mod"},
{'cc_val': (0, 127), 'cc_message': (18), 'cc_name': "Spread"},
{'cc_val': (0, 127), 'cc_message': (19), 'cc_name': "Scan"},
{'cc_val': (0, 127), 'cc_message': (20), 'cc_name': "Ramp"},
{'cc_val': (1, 3), 'cc_message': (21), 'cc_name': "Mod Number"},
{'cc_val': (1, 3), 'cc_message': (22), 'cc_name': "Mod Bank"},
{'cc_val': (1, 3), 'cc_message': (23), 'cc_name': "Mode"},
{'cc_val': (0, 1), 'cc_message': (102), 'cc_name': "Bypass/Engage"},
{'cc_val': (0, 127), 'cc_message': (93), 'cc_name': "Tap Tempo"},
{'cc_val': (0, 1), 'cc_message': (24), 'cc_name': "Loop (R Hold)"},
{'cc_val': (0, 1), 'cc_message': (25), 'cc_name': "Scan (L Hold)"},
{'cc_val': (0, 127), 'cc_message': (26), 'cc_name': "Clear (Both Hold)"},
{'cc_val': (0, 1), 'cc_message': (51), 'cc_name': "MIDI Clock Ignore"}
]
displayio.release_displays()
oled_reset = board.D13
i2c = board.STEMMA_I2C()
# STEMMA OLED setup
display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)
splash = displayio.Group()
display.root_group = splash
font = bitmap_font.load_font('/OCRA_small.pcf')
# main label/MIDI message name text; centered
main_area = label.Label(
font, text="4x4 MIDI Messenger", color=0xFFFFFF)
main_area.anchor_point = (0.5, 0.0)
main_area.anchored_position = (display.width / 2, 0)
# MIDI message number text
msg_area = label.Label(
font, text="CC Msg: 10", color=0xFFFFFF)
msg_area.anchor_point = (0.0, 0.5)
msg_area.anchored_position = (0, display.height / 2)
# MIDI message value text
val_area = label.Label(
font, text="CC Val: 50", color=0xFFFFFF)
val_area.anchor_point = (0.0, 1.0)
val_area.anchored_position = (0, display.height)
# MIDI message status text
status_area = label.Label(
font, text="Sent!", color=0xFFFFFF)
status_area.anchor_point = (1.0, 1.0)
status_area.anchored_position = (display.width, display.height)
splash.append(main_area)
splash.append(msg_area)
splash.append(val_area)
splash.append(status_area)
# MIDI over UART setup for MIDI FeatherWing
uart = busio.UART(board.TX, board.RX, baudrate=31250, timeout=0.001)
midi = adafruit_midi.MIDI(
midi_in=uart,
midi_out=uart,
in_channel=(midi_in_channel - 1),
out_channel=(midi_out_channel - 1),
debug=False,
)
# quad rotary encoder setup
ss0 = adafruit_seesaw.seesaw.Seesaw(i2c, 0x49)
ss1 = adafruit_seesaw.seesaw.Seesaw(i2c, 0x4A)
ss2 = adafruit_seesaw.seesaw.Seesaw(i2c, 0x4B)
ss3 = adafruit_seesaw.seesaw.Seesaw(i2c, 0x4C)
# button pins for the encoders
pins = [12, 14, 17, 9]
# interrupts for the button pins. pins are passed as a bitmask
ss0.set_GPIO_interrupts(1 << pins[0] | 1 << pins[1] | 1 << pins[2] | 1 << pins[3], True)
ss1.set_GPIO_interrupts(1 << pins[0] | 1 << pins[1] | 1 << pins[2] | 1 << pins[3], True)
ss2.set_GPIO_interrupts(1 << pins[0] | 1 << pins[1] | 1 << pins[2] | 1 << pins[3], True)
ss3.set_GPIO_interrupts(1 << pins[0] | 1 << pins[1] | 1 << pins[2] | 1 << pins[3], True)
# arrays for the encoders and switches
enc0 = []
enc1 = []
enc2 = []
enc3 = []
sw0 = []
sw1 = []
sw2 = []
sw3 = []
# creating encoders and switches, enabling interrupts for encoders
for i in range(4):
enc0.append(adafruit_seesaw.rotaryio.IncrementalEncoder(ss0, i))
enc1.append(adafruit_seesaw.rotaryio.IncrementalEncoder(ss1, i))
enc2.append(adafruit_seesaw.rotaryio.IncrementalEncoder(ss2, i))
enc3.append(adafruit_seesaw.rotaryio.IncrementalEncoder(ss3, i))
sw0.append(adafruit_seesaw.digitalio.DigitalIO(ss0, pins[i]))
sw0[i].switch_to_input(digitalio.Pull.UP)
sw1.append(adafruit_seesaw.digitalio.DigitalIO(ss1, pins[i]))
sw1[i].switch_to_input(digitalio.Pull.UP)
sw2.append(adafruit_seesaw.digitalio.DigitalIO(ss2, pins[i]))
sw2[i].switch_to_input(digitalio.Pull.UP)
sw3.append(adafruit_seesaw.digitalio.DigitalIO(ss3, pins[i]))
sw3[i].switch_to_input(digitalio.Pull.UP)
ss0.enable_encoder_interrupt(encoder=i)
ss1.enable_encoder_interrupt(encoder=i)
ss2.enable_encoder_interrupt(encoder=i)
ss3.enable_encoder_interrupt(encoder=i)
# neopixels on each PCB
pix0 = adafruit_seesaw.neopixel.NeoPixel(ss0, 18, 4, auto_write = True)
pix0.brightness = 0.5
pix1 = adafruit_seesaw.neopixel.NeoPixel(ss1, 18, 4, auto_write = True)
pix1.brightness = 0.5
pix2 = adafruit_seesaw.neopixel.NeoPixel(ss2, 18, 4, auto_write = True)
pix2.brightness = 0.5
pix3 = adafruit_seesaw.neopixel.NeoPixel(ss3, 18, 4, auto_write = True)
pix3.brightness = 0.5
# onboard Feather neopixel
pix_feather = neopixel.NeoPixel(board.NEOPIXEL, 1, auto_write = True)
pix_feather.brightness = 0.5
# encoder position arrays
last_pos0 = [60, 60, 60, 60]
last_pos1 = [60, 60, 60, 0]
last_pos2 = [0, 0, 0, 120]
last_pos3 = [0, 0, 0, 0]
pos0 = [60, 60, 60, 60]
pos1 = [60, 60, 60, 0]
pos2 = [0, 0, 0, 120]
pos3 = [0, 0, 0, 0]
# color arrays for the neopixels
c0 = [0, 16, 32, 48]
c1 = [64, 80, 96, 112]
c2 = [128, 144, 160, 176]
c3 = [192, 208, 224, 240]
# setting starting colors for neopixels
for r in range(4):
pix0[r] = colorwheel(c0[r])
pix1[r] = colorwheel(c1[r])
pix2[r] = colorwheel(c2[r])
pix3[r] = colorwheel(c3[r])
# feather neopixel color
c_feather = 0
pix_feather[0] = colorwheel(c_feather)
# array of all 16 encoder positions
encoder_posititions = [60, 60, 60, 60, 60, 60, 60, 60, 0, 0, 0, 120, 0, 0, 0, 0]
class MIDI_Messages:
# tracks sending a message and index 0-15
def __init__(self):
self.send_msg = False
self.midi_index = 0
class NeoPixel_Attributes:
# tracks color, neopixel index and seesaw
def __init__(self):
self.color = c0
self.index = 0
self.strip = pix0
self.feather_color = c_feather
async def send_midi(midi_msg):
# sends MIDI message if send_msg is True/button pressed
while True:
if midi_msg.send_msg is True:
m = midi_msg.midi_index
main_area.text = f"{cc_values[m]['cc_name']}"
msg_area.text = f"CC Msg: {cc_values[m]['cc_message']}"
val_area.text = f"CC Val: {encoder_posititions[m]}"
midi.send(ControlChange(cc_values[m]['cc_message'], encoder_posititions[m]))
status_area.text = "Sent!"
print(f"sending midi: {m}, {encoder_posititions[m]}, {cc_values[m]['cc_message']}")
time.sleep(1)
midi_msg.send_msg = False
else:
status_area.text = " "
await asyncio.sleep(0)
async def rainbows(the_color):
# Updates colors of the neopixels to scroll through rainbow
while True:
the_color.feather_color += 8
the_color.strip[the_color.index] = colorwheel(the_color.color[the_color.index])
pix_feather[0] = colorwheel(the_color.feather_color)
await asyncio.sleep(0)
async def monitor_interrupts(pin0, pin1, pin2, pin3, the_color, midi_msg): #pylint: disable=too-many-statements
# function to keep encoder value pinned between CC value range
def normalize(val, min_v, max_v):
return max(min(max_v, val), min_v)
# read encoder function
def read_encoder(enc_group, pos, last_pos, pix, colors, index_diff):
# check all four encoders if interrupt is detected
for p in range(4):
pos[p] = enc_group[p].position
if pos[p] != last_pos[p]:
main_index = p + index_diff
# update CC value
if pos[p] > last_pos[p]:
colors[p] += 8
encoder_posititions[main_index] = encoder_posititions[main_index] + 1
else:
colors[p] -= 8
encoder_posititions[main_index] = encoder_posititions[main_index] - 1
encoder_posititions[main_index] = normalize(encoder_posititions[main_index],
cc_values[main_index]['cc_val'][0],
cc_values[main_index]['cc_val'][1])
colors[p] = (colors[p] + 256) % 256 # wrap around to 0-256
print(main_index, encoder_posititions[main_index])
main_area.text = f"{cc_values[main_index]['cc_name']}"
msg_area.text = f"CC Msg: {cc_values[main_index]['cc_message']}"
val_area.text = f"CC Val: {encoder_posititions[main_index]}"
last_pos[p] = pos[p]
# update NeoPixel colors
the_color.color = colors
the_color.index = p
the_color.strip = pix
# function to read button press
def press_switches(sw, index):
if not sw[index].value:
# signals that a MIDI message should be sent
midi_msg.send_msg = True
midi_msg.midi_index = index
print(f"button {index} pressed")
# interrupt pins are passed as a keypad
with keypad.Keys(
(pin0, pin1, pin2, pin3,), value_when_pressed=False, pull=True
) as keys:
while True:
key_event = keys.events.get()
if key_event and key_event.pressed:
key_number = key_event.key_number
# seesaw 0
if key_number == 0:
read_encoder(enc0, pos0, last_pos0, pix0, c0, 0)
press_switches(sw0, 0)
press_switches(sw0, 1)
press_switches(sw0, 2)
press_switches(sw0, 3)
# seesaw 1
elif key_number == 1:
read_encoder(enc1, pos1, last_pos1, pix1, c1, 4)
press_switches(sw1, 0)
press_switches(sw1, 1)
press_switches(sw1, 2)
press_switches(sw1, 3)
# update index to 4-7
midi_msg.midi_index = midi_msg.midi_index + 4
# seesaw 2
elif key_number == 2:
read_encoder(enc2, pos2, last_pos2, pix2, c2, 8)
press_switches(sw2, 0)
press_switches(sw2, 1)
press_switches(sw2, 2)
press_switches(sw2, 3)
# update index 8-11
midi_msg.midi_index = midi_msg.midi_index + 8
# seesaw 3
else:
read_encoder(enc3, pos3, last_pos3, pix3, c3, 12)
press_switches(sw3, 0)
press_switches(sw3, 1)
press_switches(sw3, 2)
press_switches(sw3, 3)
# update index 12-15
midi_msg.midi_index = midi_msg.midi_index + 12
# clear interrupt flag to reset interrupt pin
ss0.get_GPIO_interrupt_flag()
ss1.get_GPIO_interrupt_flag()
ss2.get_GPIO_interrupt_flag()
ss3.get_GPIO_interrupt_flag()
await asyncio.sleep(0)
async def main():
the_color = NeoPixel_Attributes()
midi_msg = MIDI_Messages()
# interrupt listener task
interrupt_task = asyncio.create_task(monitor_interrupts(board.D5, board.D6, board.D9,
board.D10, the_color, midi_msg))
# neopixel task
pixels_task = asyncio.create_task(rainbows(the_color))
# midi task
midi_task = asyncio.create_task(send_midi(midi_msg))
await asyncio.gather(interrupt_task, pixels_task, midi_task)
asyncio.run(main())

View file

@ -1,61 +0,0 @@
// SPDX-FileCopyrightText: 2022 Phil B. for Adafruit Industries
//
// SPDX-License-Identifier: MIT
// Example for 5x5 NeoBFF - scrolls a message across the LED matrix.
// Requires Adafruit_GFX, Adafruit_NeoPixel and Adafruit_NeoMatrix libraries.
#include <Adafruit_GFX.h> // Graphics library
#include <Adafruit_NeoPixel.h> // NeoPixel library
#include <Adafruit_NeoMatrix.h> // Bridges GFX and NeoPixel
#include <Fonts/TomThumb.h> // A tiny 3x5 font incl. w/GFX
#define PIN A3
// NeoMatrix declaration for BFF with the power and
// Neo pins at the top (same edge as QT Py USB port):
Adafruit_NeoMatrix matrix(5, 5, PIN,
NEO_MATRIX_TOP + NEO_MATRIX_RIGHT +
NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_GRB + NEO_KHZ800);
// Message to display, and a set of colors to cycle through. Because
// the matrix is only 5 pixels tall, characters with descenders (e.g.
// lowercase p or y) are best avoided. There are even smaller fonts
// but these get progressively less legible. ALL CAPS helps!
const char message[] = "HELLO BFF";
const uint16_t colors[] = {
matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(0, 0, 255) };
uint16_t message_width; // Computed in setup() below
void setup() {
matrix.begin();
matrix.setBrightness(40); // Turn down brightness to about 15%
matrix.setFont(&TomThumb); // Use custom font
matrix.setTextWrap(false); // Allows text to scroll off edges
matrix.setTextColor(colors[0]); // Start with first color in list
// To determine when the message has fully scrolled off the left side,
// get the bounding rectangle of the text. As we only need the width
// value, a couple of throwaway variables are passed to the bounds
// function for the other values:
int16_t d1;
uint16_t d2;
matrix.getTextBounds(message, 0, 0, &d1, &d1, &message_width, &d2);
}
int x = matrix.width(); // Start with message off right edge
int y = matrix.height(); // With custom fonts, y is the baseline, not top
int pass = 0; // Counts through the colors[] array
void loop() {
matrix.fillScreen(0); // Erase message in old position.
matrix.setCursor(x, y); // Set new cursor position,
matrix.print(message); // draw the message
matrix.show(); // and update the matrix.
if(--x < -message_width) { // Move 1 pixel left. Then, if scrolled off left...
x = matrix.width(); // reset position off right edge and
if(++pass >= 3) pass = 0; // increment color in list, rolling over if needed.
matrix.setTextColor(colors[pass]);
}
delay(100); // 1/10 sec pause
}

View file

@ -1,37 +0,0 @@
# SPDX-FileCopyrightText: Copyright (c) 2022 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
import time
import board
import neopixel
from adafruit_display_text.bitmap_label import Label
from adafruit_bitmap_font import bitmap_font
from displayio import Bitmap
from rainbowio import colorwheel
font = bitmap_font.load_font("tom-thumb.pcf", Bitmap)
label = Label(text="Hello World!! Adafruit QT Py RP2040 + NeoPixel BFF ", font=font)
bitmap = label.bitmap
pixels = neopixel.NeoPixel(board.A3, 5*5, brightness=.07, auto_write=False)
pixels.fill(0)
pixels.show()
colors = [0, 0]
hue = 0
while True:
for i in range(bitmap.width):
# Use a rainbow of colors, shifting each column of pixels
hue = hue + 7
if hue >= 256:
hue = hue - 256
colors[1] = colorwheel(hue)
# Scoot the old text left by 1 pixel
pixels[0:20] = pixels[5:25]
# Draw in the next line of text
for y in range(5):
# Select black or color depending on the bitmap pixel
pixels[20+y] = colors[bitmap[i,y]]
pixels.show()
time.sleep(.1)

View file

@ -1,83 +0,0 @@
# SPDX-FileCopyrightText: Copyright (c) 2022 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
import time
import board
import neopixel
import fontio
from adafruit_display_text.bitmap_label import Label
from adafruit_bitmap_font import bitmap_font
from displayio import Bitmap
from rainbowio import colorwheel
tom_thumb = bitmap_font.load_font("tom-thumb.pcf", Bitmap)
_glyph_keys = ['bitmap', 'tile_index', 'width', 'height', 'dx', 'dy', 'shift_x', 'shift_y']
def patch_glyph(base, **kw):
d = {}
for k in _glyph_keys:
d[k] = kw.get(k, getattr(base, k))
return fontio.Glyph(**d)
class PatchedFont:
def __init__(self, base_font, patches):
self.base_font = base_font
self.patches = patches
def get_glyph(self, glyph):
g = self.base_font.get_glyph(glyph)
patch = self.patches.get(glyph)
if patch is not None:
print("patching", repr(chr(glyph)), g)
g = patch_glyph(g, **patch)
print("patched", g)
return g
def get_bounding_box(self):
return self.base_font.get_bounding_box()
font = PatchedFont(tom_thumb,
{
32: {'shift_x': 1, 'dx': 0},
105: {'dx': 0, 'shift_x': 2},
33: {'dx': 0, 'shift_x': 2},
})
label = Label(text=" adafruit! ", font=font)
bitmap = label.bitmap
heart_bitmap = [
0,1,1,0,0,
1,1,1,1,0,
0,1,1,1,1,
1,1,1,1,0,
0,1,1,0,0,
]
pixels = neopixel.NeoPixel(board.A3, 5*5, brightness=.06, auto_write=False)
while True:
for hue in range(0, 255, 3):
color = colorwheel(hue)
pixels[:] = [pixel * color for pixel in heart_bitmap]
pixels.show()
time.sleep(.01)
hue = 0
for i in range(bitmap.width):
# Use a rainbow of colors, shifting each column of pixels
hue = hue + 7
if hue >= 256:
hue = hue - 256
color = colorwheel(hue)
# Scoot the old text left by 1 pixel
pixels[:20] = pixels[5:]
# Draw in the next line of text
for y in range(5):
# Select black or color depending on the bitmap pixel
pixels[20+y] = color * bitmap[i,y]
pixels.show()
time.sleep(.1)

View file

@ -1,47 +0,0 @@
// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <Adafruit_MCP23X17.h>
#define NOID_1 0 // MCP23XXX pin LED is attached to
#define NOID_2 4 // MCP23XXX pin LED is attached to
Adafruit_MCP23X17 mcp;
void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("8 Channel Solenoid Driver Demo");
if (!mcp.begin_I2C()) {
Serial.println("Couldn't find MCP23017..");
while (1);
}
mcp.pinMode(NOID_1, OUTPUT);
mcp.pinMode(NOID_2, OUTPUT);
Serial.println("Found MCP23017, looping...");
}
void loop() {
Serial.println("Solenoid 1!");
mcp.digitalWrite(NOID_1, HIGH);
delay(500);
mcp.digitalWrite(NOID_1, LOW);
delay(500);
Serial.println("Solenoid 2!");
mcp.digitalWrite(NOID_2, HIGH);
delay(500);
mcp.digitalWrite(NOID_2, LOW);
delay(500);
Serial.println("Together!");
mcp.digitalWrite(NOID_1, HIGH);
mcp.digitalWrite(NOID_2, HIGH);
delay(1000);
mcp.digitalWrite(NOID_1, LOW);
mcp.digitalWrite(NOID_2, LOW);
delay(2000);
Serial.println("Repeat!");
Serial.println();
delay(500);
}

View file

@ -1,38 +0,0 @@
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
from adafruit_mcp230xx.mcp23017 import MCP23017
i2c = board.STEMMA_I2C()
mcp = MCP23017(i2c)
noid_1 = mcp.get_pin(0)
noid_2 = mcp.get_pin(4)
noid_1.switch_to_output(value=False)
noid_2.switch_to_output(value=False)
while True:
noid_1.value = True
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
time.sleep(0.2)
noid_1.value = False
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
time.sleep(0.2)
noid_2.value = True
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
time.sleep(0.2)
noid_2.value = False
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
time.sleep(1)
noid_1.value = True
noid_2.value = True
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
time.sleep(1)
noid_1.value = False
noid_2.value = False
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
time.sleep(2)

View file

@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
//
// SPDX-License-Identifier: MIT
const int DIR = 5;
const int STEP = 6;
const int microMode = 16; // microstep mode, default is 1/16 so 16; ex: 1/4 would be 4
// full rotation * microstep divider
const int steps = 200 * microMode;
void setup()
{
// setup step and dir pins as outputs
pinMode(STEP, OUTPUT);
pinMode(DIR, OUTPUT);
}
void loop()
{
// change direction every loop
digitalWrite(DIR, !digitalRead(DIR));
// toggle STEP to move
for(int x = 0; x < steps; x++)
{
digitalWrite(STEP, HIGH);
delay(2);
digitalWrite(STEP, LOW);
delay(2);
}
delay(1000); // 1 second delay
}

View file

@ -1,32 +0,0 @@
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
from digitalio import DigitalInOut, Direction
# direction and step pins as outputs
DIR = DigitalInOut(board.D5)
DIR.direction = Direction.OUTPUT
STEP = DigitalInOut(board.D6)
STEP.direction = Direction.OUTPUT
# microstep mode, default is 1/16 so 16
# another ex: 1/4 microstep would be 4
microMode = 16
# full rotation multiplied by the microstep divider
steps = 200 * microMode
while True:
# change direction every loop
DIR.value = not DIR.value
# toggle STEP pin to move the motor
for i in range(steps):
STEP.value = True
time.sleep(0.001)
STEP.value = False
time.sleep(0.001)
print("rotated! now reverse")
# 1 second delay before starting again
time.sleep(1)

View file

@ -1,2 +0,0 @@
ABC_Soundboards_for_NeoTrellis/code.py 169: Comparison 'currently_playing['voice'] != None' should be 'currently_playing['voice'] is not None' (singleton-comparison)
ABC_Soundboards_for_NeoTrellis/code.py 186: Comparison 'currently_playing['voice'] != None' should be 'currently_playing['voice'] is not None' (singleton-comparison)

View file

@ -1,7 +1,3 @@
# SPDX-FileCopyrightText: 2020 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
# Talking A, B, Cs Soundboards: Animal ABCs and "E is for Electronics" ABCs
import time

View file

@ -1,65 +0,0 @@
// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <Adafruit_ADG72x.h>
Adafruit_ADG72x adg72x;
bool isADG728 = false; // which chip are we connected to?
int analogIn = A0;
int analogValue = 0;
unsigned long switchTimer = 1000; // 1000 ms = 1 second for channel switch
unsigned long readTimer = 10; // 10 ms for analog read
unsigned long lastSwitchTime = 0; // Last time the channels were switched
unsigned long lastReadTime = 0; // Last time the analog was read
uint8_t currentChannel = 0; // Current channel being selected
void setup() {
Serial.begin(115200);
// Wait for serial port to open
while (!Serial) {
delay(1);
}
// Try with the ADG728 default address first...
if (adg72x.begin(ADG728_DEFAULT_ADDR, &Wire)) {
Serial.println("ADG728 found!");
isADG728 = true;
}
// Maybe they have an ADG729?
else if (adg72x.begin(ADG729_DEFAULT_ADDR, &Wire)) {
Serial.println("ADG729 found!");
isADG728 = false;
}
else {
Serial.println("No ADG device found? Check wiring!");
while (1); // Stop here if no device was found
}
}
void loop() {
unsigned long currentTime = millis();
// read and print analog value every 10ms
if ((currentTime - lastReadTime) >= readTimer) {
analogValue = analogRead(analogIn);
Serial.println(analogValue);
lastReadTime = currentTime;
}
// switch channels every 1 second
if ((currentTime - lastSwitchTime) >= switchTimer) {
uint8_t bits = 1 << currentChannel; // Shift a '1' from LSB to MSB
if (!adg72x.selectChannels(bits)) {
Serial.println("Failed to set channels...");
}
/*Serial.print((currentChannel % 4) + 1);
if (currentChannel < 4) Serial.println("A");
else Serial.println("B");*/
currentChannel = (currentChannel + 1) % 8; // Move to the next channel, wrap around at 8
lastSwitchTime = currentTime;
}
}

View file

@ -1,66 +0,0 @@
// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <Adafruit_ADG72x.h>
Adafruit_ADG72x adg72x;
int analogInA0 = A0;
int analogInA1 = A1;
int analogValueDA = 0;
int analogValueDB = 0;
unsigned long switchTimer = 1000; // 1000 ms = 1 second for channel switch
unsigned long readTimer = 10; // 10 ms for analog read
unsigned long lastSwitchTime = 0; // Last time the channels were switched
unsigned long lastReadTime = 0; // Last time the analog was read
uint8_t currentChannel = 0; // Current channel being selected
void setup() {
Serial.begin(115200);
// Wait for serial port to open
while (!Serial) {
delay(1);
}
// Try with the ADG728 default address first...
if (adg72x.begin(ADG728_DEFAULT_ADDR, &Wire)) {
//Serial.println("ADG728 found!");
}
// Maybe they have an ADG729?
else if (adg72x.begin(ADG729_DEFAULT_ADDR, &Wire)) {
//Serial.println("ADG729 found!");
}
else {
Serial.println("No ADG72x device found? Check wiring!");
while (1); // Stop here if no device was found
}
}
void loop() {
unsigned long currentTime = millis();
// read and print analog value every 10ms
if ((currentTime - lastReadTime) >= readTimer) {
analogValueDA = analogRead(analogInA0);
analogValueDB = analogRead(analogInA1);
Serial.print(analogValueDA);
Serial.print(",");
Serial.println(analogValueDB);
lastReadTime = currentTime;
}
// switch channels every 1 second
if ((currentTime - lastSwitchTime) >= switchTimer) {
uint8_t bits = 1 << currentChannel; // Shift a '1' from LSB to MSB
if (!adg72x.selectChannels(bits)) {
Serial.println("Failed to set channels...");
}
/*Serial.print((currentChannel % 4) + 1);
if (currentChannel < 4) Serial.println("A");
else Serial.println("B");*/
currentChannel = (currentChannel + 1) % 8; // Move to the next channel, wrap around at 8
lastSwitchTime = currentTime;
}
}

View file

@ -1,26 +0,0 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
import adafruit_adg72x
from analogio import AnalogIn
analog_in = AnalogIn(board.A0)
i2c = board.I2C()
switch = adafruit_adg72x.ADG72x(i2c)
c = 0
switch_time = 2
channels = [0, 4]
clock = time.monotonic()
while True:
if (time.monotonic() - clock) > switch_time:
print(f"Selecting channel {channels[c] + 1}")
switch.channel = channels[c]
c = (c + 1) % 2
clock = time.monotonic()
print((analog_in.value,))
time.sleep(0.1)

View file

@ -1,31 +0,0 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
import adafruit_adg72x
from analogio import AnalogIn
analog_in_DA = AnalogIn(board.A0)
analog_in_DB = AnalogIn(board.A1)
i2c = board.I2C()
switch = adafruit_adg72x.ADG72x(i2c, 0x44)
c = 0
switch_time = 3
clock = time.monotonic()
while True:
if (time.monotonic() - clock) > switch_time:
if c < 4:
channels = "A"
else:
channels = "B"
print(f"Selecting channel {(c % 4) + 1}{channels}")
switch.channel = c
c = (c + 1) % 8
clock = time.monotonic()
print((analog_in_DA.value, analog_in_DB.value,))
time.sleep(0.1)

View file

@ -1,7 +1,3 @@
# SPDX-FileCopyrightText: 2020 Andy Doro for Adafruit Industries
#
# SPDX-License-Identifier: MIT
""" Example for using the AHT20 and OLED with CircuitPython and the Adafruit library"""
import time
@ -11,7 +7,6 @@ import adafruit_ahtx0
# OLED
import displayio
import i2cdisplaybus
import terminalio
from adafruit_display_text import label
import adafruit_displayio_ssd1306
@ -26,15 +21,15 @@ aht20 = adafruit_ahtx0.AHTx0(i2c)
#OLED
display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3C)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
# Make the display context
splash = displayio.Group()
display.root_group = splash
splash = displayio.Group(max_size=8)
display.show(splash)
text = "hello world"
text_area = label.Label(terminalio.FONT, color=0xFFFF00, x=15, y=0)
text_area = label.Label(terminalio.FONT, color=0xFFFF00, x=15, y=0, max_glyphs=200)
splash.append(text_area)
while True:

View file

@ -1,112 +0,0 @@
# SPDX-FileCopyrightText: 2018 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
# Adafruit IO Environmental Monitor for Feather or Raspberry Pi -
# an internet-enabled environmental monitor
# Import standard python modules
import time
# import Adafruit Blinka
import board
import busio
# import CircuitPython sensor libraries
import adafruit_sgp30
import adafruit_veml6070
from adafruit_bme280 import basic as adafruit_bme280
# import Adafruit IO REST client
from Adafruit_IO import Client, Feed, RequestError
# loop timeout, in seconds.
LOOP_DELAY = 10
# Set to your Adafruit IO key.
# Remember, your key is a secret,
# so make sure not to publish it when you publish this code!
ADAFRUIT_IO_KEY = 'YOUR_AIO_KEY'
# Set to your Adafruit IO username.
# (go to https://accounts.adafruit.com to find your username)
ADAFRUIT_IO_USERNAME = 'YOUR_AIO_USERNAME'
# Create an instance of the REST client
aio = Client(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)
try: # if we already have the feeds, assign them.
tvoc_feed = aio.feeds('tvoc')
eCO2_feed = aio.feeds('eco2')
uv_feed = aio.feeds('uv')
temperature_feed = aio.feeds('temperature')
humidity_feed = aio.feeds('humidity')
pressure_feed = aio.feeds('pressure')
altitude_feed = aio.feeds('altitude')
except RequestError: # if we don't, create and assign them.
tvoc_feed = aio.create_feed(Feed(name='tvoc'))
eCO2_feed = aio.create_feed(Feed(name='eco2'))
uv_feed = aio.create_feed(Feed(name='uv'))
temperature_feed = aio.create_feed(Feed(name='temperature'))
humidity_feed = aio.create_feed(Feed(name='humidity'))
pressure_feed = aio.create_feed(Feed(name='pressure'))
altitude_feed = aio.create_feed(Feed(name='altitude'))
# Create busio I2C
i2c = busio.I2C(board.SCL, board.SDA)
# Create VEML6070 object.
uv = adafruit_veml6070.VEML6070(i2c)
# Create BME280 object.
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
bme280.sea_level_pressure = 1013.25
# Create SGP30 object using I2C.
sgp30 = adafruit_sgp30.Adafruit_SGP30(i2c)
sgp30.iaq_init()
sgp30.set_iaq_baseline(0x8973, 0x8aae)
# Sample VEML6070
def sample_VEML():
for _ in range(10):
uv_raw = uv.uv_raw
return uv_raw
while True:
print('Reading sensors...')
# Read SGP30.
eCO2_data = sgp30.eCO2
tvoc_data = sgp30.TVOC
# Read VEML6070.
uv_data = sample_VEML()
# Read BME280.
temp_data = bme280.temperature
# convert temperature (C->F)
temp_data = int(temp_data) * 1.8 + 32
humid_data = bme280.humidity
pressure_data = bme280.pressure
alt_data = bme280.altitude
print('sending data to adafruit io...')
# Send SGP30 Data to Adafruit IO.
print('eCO2:', eCO2_data)
aio.send(eCO2_feed.key, eCO2_data)
print('tvoc:', tvoc_data)
aio.send(tvoc_feed.key, tvoc_data)
time.sleep(2)
# Send VEML6070 Data to Adafruit IO.
print('UV Level: ', uv_data)
aio.send(uv_feed.key, uv_data)
time.sleep(2)
# Send BME280 Data to Adafruit IO.
print('Temperature: %0.1f C' % temp_data)
aio.send(temperature_feed.key, temp_data)
print("Humidity: %0.1f %%" % humid_data)
aio.send(humidity_feed.key, int(humid_data))
time.sleep(2)
print("Pressure: %0.1f hPa" % pressure_data)
aio.send(pressure_feed.key, int(pressure_data))
print("Altitude = %0.2f meters" % alt_data)
aio.send(altitude_feed.key, int(alt_data))
# avoid timeout from adafruit io
time.sleep(LOOP_DELAY * 60)

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2018 John Edgar Park for Adafruit Industries
//
// SPDX-License-Identifier: MIT
// For Adafruit_AMRadio library -- Morse code transmits on AM 540.
// Connect antenna (40" wire) to pin A0 and GND
// RANGE IS LIMITED TO A FEW FEET

View file

@ -1,88 +0,0 @@
// SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <Adafruit_NeoPixel.h>
#include <RotaryEncoder.h>
#define PIN_ENCODER_A 13
#define PIN_ENCODER_B 12
#define COM_A 11
#define COM_B SDA
#define BUTTON_UP 5
#define BUTTON_LEFT SCL
#define BUTTON_DOWN 9
#define BUTTON_RIGHT 6
#define BUTTON_IN 10
RotaryEncoder encoder(PIN_ENCODER_A, PIN_ENCODER_B, RotaryEncoder::LatchMode::TWO03);
// This interrupt will do our encoder reading/checking!
void checkPosition() {
encoder.tick(); // just call tick() to check the state.
}
int last_rotary = 0;
#define NUMPIXELS 12
Adafruit_NeoPixel pixels(NUMPIXELS, A0, NEO_GRB + NEO_KHZ800);
void setup(void) {
Serial.begin(115200);
while (!Serial);
Serial.println("ANO Rotary Encoder Demo");
pinMode(COM_A, OUTPUT);
digitalWrite(COM_A, LOW);
pinMode(COM_B, OUTPUT);
digitalWrite(COM_B, LOW);
attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_A), checkPosition, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_B), checkPosition, CHANGE);
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_LEFT, INPUT_PULLUP);
pinMode(BUTTON_RIGHT, INPUT_PULLUP);
pinMode(BUTTON_IN, INPUT_PULLUP);
pixels.begin();
pixels.setBrightness(30);
pixels.show();
}
void loop(void) {
// read encoder
int curr_rotary = encoder.getPosition();
RotaryEncoder::Direction direction = encoder.getDirection();
pixels.clear();
if (curr_rotary != last_rotary) {
Serial.print("Encoder value: ");
Serial.print(curr_rotary);
Serial.print(" direction: ");
Serial.println((int)direction);
}
last_rotary = curr_rotary;
pixels.setPixelColor((curr_rotary + (1000*NUMPIXELS)) % NUMPIXELS, pixels.Color(0, 150, 0));
if (! digitalRead(BUTTON_UP)) {
pixels.setPixelColor(0, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_LEFT)) {
pixels.setPixelColor(NUMPIXELS/4, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_DOWN)) {
pixels.setPixelColor(NUMPIXELS/2, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_RIGHT)) {
pixels.setPixelColor(NUMPIXELS*3/4, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_IN)) {
pixels.fill(pixels.Color(50, 50, 50));
}
pixels.show();
delay(20);
}

View file

@ -1,78 +0,0 @@
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
CircuitPython ANO Rotary Encoder and NeoPixel Ring example.
"""
import board
import digitalio
import rotaryio
import neopixel
# The pin assignments for the breakout pins. Update this is you are not using a Feather.
ENCA = board.D13
ENCB = board.D12
COMA = board.D11
SW1 = board.D10
SW2 = board.D9
SW3 = board.D6
SW4 = board.D5
SW5 = board.SCL
COMB = board.SDA
# Rotary encoder setup
encoder = rotaryio.IncrementalEncoder(ENCA, ENCB)
last_position = None
# NeoPixel ring setup. Update num_pixels if using a different ring.
num_pixels = 12
pixels = neopixel.NeoPixel(board.A0, num_pixels, auto_write=False)
# Set the COMA and COMB pins LOW. This is only necessary when using the direct-to-Feather or other
# GPIO-based wiring method. If connecting COMA and COMB to ground, you do not need to include this.
com_a = digitalio.DigitalInOut(COMA)
com_a.switch_to_output()
com_a = False
com_b = digitalio.DigitalInOut(COMB)
com_b.switch_to_output()
com_b = False
# Button pin setup
button_pins = (SW1, SW2, SW3, SW4, SW5)
buttons = []
for button_pin in button_pins:
pin = digitalio.DigitalInOut(button_pin)
pin.switch_to_input(digitalio.Pull.UP)
buttons.append(pin)
while True:
position = encoder.position
if last_position is None or position != last_position:
print("Position: {}".format(position))
last_position = position
pixels.fill((0, 0, 0))
pixels[position % num_pixels] = (0, 150, 0)
if not buttons[0].value:
print("Center button!")
pixels.fill((100, 100, 100))
if not buttons[1].value:
print("Up button!")
pixels[0] = (150, 0 ,0)
if not buttons[2].value:
print("Left button!")
pixels[3] = (150, 0, 0)
if not buttons[3].value:
print("Down button!")
pixels[6] = (150, 0, 0)
if not buttons[4].value:
print("Right button!")
pixels[9] = (150, 0, 0)
pixels.show()

View file

@ -1,740 +0,0 @@
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT
from random import randint
import ulab.numpy as np
import board
import audiobusio
import audiomixer
import synthio
import simpleio
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
from adafruit_ht16k33 import segments
from adafruit_ht16k33.matrix import Matrix8x8x2
from adafruit_seesaw import seesaw, rotaryio, digitalio
SAMPLE_RATE = 44100
SAMPLE_SIZE = 256
VOLUME = 5000
# waveforms, envelopes and synth setup
square = np.concatenate((np.ones(SAMPLE_SIZE//2, dtype=np.int16)*VOLUME,np.ones(SAMPLE_SIZE//2,
dtype=np.int16)*-VOLUME))
sine = np.array(np.sin(np.linspace(0, 4*np.pi, SAMPLE_SIZE, endpoint=False)) * VOLUME,
dtype=np.int16)
saw = np.linspace(VOLUME, -VOLUME, num=SAMPLE_SIZE, dtype=np.int16)
noise = np.array([randint(-VOLUME, VOLUME) for i in range(SAMPLE_SIZE)], dtype=np.int16)
lfo = synthio.LFO(rate = .5, waveform = sine)
amp_env0 = synthio.Envelope(attack_time=0.1, decay_time = 0.1, release_time=0.1,
attack_level=1, sustain_level=0.05)
amp_env1 = synthio.Envelope(attack_time=0.05, decay_time = 0.1, release_time=0.1,
attack_level=1, sustain_level=0.05)
# synth plays the notes
synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE)
# these are the notes
synth0 = synthio.Note(frequency = 0.0, envelope=amp_env0, waveform=square, ring_frequency = 0,
ring_bend = lfo, ring_waveform = sine)
synth1 = synthio.Note(frequency = 0.0, envelope=amp_env1, waveform=sine, ring_frequency = 0,
ring_bend = lfo, ring_waveform = sine)
synth2 = synthio.Note(frequency = 0.0, envelope=amp_env0, waveform=square, ring_frequency = 0,
ring_bend = lfo, ring_waveform = sine)
synth3 = synthio.Note(frequency = 0.0, envelope=amp_env1, waveform=sine, ring_frequency = 0,
ring_bend = lfo, ring_waveform = sine)
synths = [synth0, synth1, synth2, synth3]
wave_names = ["SQUR", "SINE", "SAW ", "NOIZ"]
waveforms = [square, sine, saw, noise]
synth0_wave = 0
synth1_wave = 1
synth2_wave = 0
synth3_wave = 1
# i2s amp setup
audio = audiobusio.I2SOut(bit_clock=board.D10, word_select=board.D11, data=board.D9)
mixer = audiomixer.Mixer(voice_count=4, sample_rate=SAMPLE_RATE, channel_count=1,
bits_per_sample=16, samples_signed=True, buffer_size=2048 )
audio.play(mixer)
vol_val = 2
mixer.voice[0].play(synth)
mixer.voice[0].level = 0.3
# these are the triads, all major
c_tones = [130.81, 164.81, 196.00]
g_tones = [196.00, 246.94, 293.66]
d_tones = [146.83, 185.00, 220.00]
a_tones = [220.00, 277.18, 329.63]
e_tones = [164.81, 207.65, 246.94]
b_tones = [246.94, 311.13, 369.99]
fsharp_tones = [185.00, 233.08, 277.18]
csharp_tones = [138.59, 174.61, 207.65]
aflat_tones = [207.65, 261.63, 311.13]
eflat_tones = [155.56, 196.00, 233.08]
bflat_tones = [233.08, 293.66, 349.23]
f_tones = [174.61, 220.00, 261.63]
# names for the alphanumeric displays
chord_names = ["Cmaj", "Gmaj", "Dmaj", "Amaj", "Emaj", "Bmaj",
"F#ma", "C#ma", "Abma", "Ebma", "Bbma", "Fmaj"]
chords = [c_tones, g_tones, d_tones, a_tones, e_tones, b_tones, fsharp_tones, csharp_tones,
aflat_tones, eflat_tones, bflat_tones, f_tones]
# i2c setup
i2c = board.I2C()
# the encoders
seesaw0 = seesaw.Seesaw(i2c, addr=0x49)
seesaw1 = seesaw.Seesaw(i2c, addr=0x4A)
seesaw2 = seesaw.Seesaw(i2c, addr=0x4B)
seesaw3 = seesaw.Seesaw(i2c, addr=0x4C)
menu_seesaw = seesaw.Seesaw(i2c, addr=0x4D)
# the alphanumeric displays
display0 = segments.Seg14x4(i2c, address=0x70)
display1 = segments.Seg14x4(i2c, address=0x71)
display2 = segments.Seg14x4(i2c, address=0x72)
display3 = segments.Seg14x4(i2c, address=0x73)
menu_display = segments.Seg14x4(i2c, address=0x74)
# the matrix
matrix0 = Matrix8x8x2(i2c, address=0x75)
seesaws = [seesaw0, seesaw1, seesaw2, seesaw3, menu_seesaw]
buttons0 = []
buttons1 = []
buttons2 = []
buttons3 = []
menu_buttons = []
button0_states = []
button1_states = []
button2_states = []
button3_states = []
menu_states = []
button0_names = ["Select", "Up", "Left", "Down", "Right"]
# setup the buttons on all of the encoders
for i in range(1, 6):
seesaw0.pin_mode(i, seesaw0.INPUT_PULLUP)
seesaw1.pin_mode(i, seesaw1.INPUT_PULLUP)
seesaw2.pin_mode(i, seesaw2.INPUT_PULLUP)
seesaw3.pin_mode(i, seesaw3.INPUT_PULLUP)
menu_seesaw.pin_mode(i, menu_seesaw.INPUT_PULLUP)
buttons0.append(digitalio.DigitalIO(seesaw0, i))
buttons1.append(digitalio.DigitalIO(seesaw1, i))
buttons2.append(digitalio.DigitalIO(seesaw2, i))
buttons3.append(digitalio.DigitalIO(seesaw3, i))
menu_buttons.append(digitalio.DigitalIO(menu_seesaw, i))
button0_states.append(False)
button1_states.append(False)
button2_states.append(False)
button3_states.append(False)
menu_states.append(False)
# make all of the encoders
encoder0 = rotaryio.IncrementalEncoder(seesaw0)
last_position0 = 0
encoder1 = rotaryio.IncrementalEncoder(seesaw1)
last_position1 = 0
encoder2 = rotaryio.IncrementalEncoder(seesaw2)
last_position2 = 0
encoder3 = rotaryio.IncrementalEncoder(seesaw3)
last_position3 = 0
menu_enc = rotaryio.IncrementalEncoder(menu_seesaw)
last_menuPosition = 0
# Python Implementation of Björklund's Algorithm by Brian House
# MIT License 2011
# https://github.com/brianhouse/bjorklund
def bjorklund(steps, pulses):
steps = int(steps)
pulses = int(pulses)
if pulses > steps:
raise ValueError
pattern = []
counts = []
remainders = []
divisor = steps - pulses
remainders.append(pulses)
level = 0
while True:
counts.append(divisor // remainders[level])
remainders.append(divisor % remainders[level])
divisor = remainders[level]
level = level + 1
if remainders[level] <= 1:
break
counts.append(divisor)
def build(level):
if level == -1:
pattern.append(0)
elif level == -2:
pattern.append(1)
else:
for _ in range(0, counts[level]):
build(level - 1)
if remainders[level] != 0:
build(level - 2)
build(level)
p = pattern.index(1)
pattern = pattern[p:] + pattern[0:p]
return pattern
# using ticks for time tracking
clock = ticks_ms()
# default BPM
bpm = 120
# beat divison
beat_div = [15, 30, 60, 120, 240]
beat_index = 2
beat_names = ["1/16", "1/8 ", "1/4 ", "1/2 ", "HOLE"]
delay = int((beat_div[beat_index] / bpm) * 1000)
# variables for euclidean
c0 = 0
c1 = 0
c2 = 0
c3 = 0
r0 = 0
r1 = 0
r2 = 0
r3 = 0
last_r0 = 0
last_r1 = 0
last_r2 = 0
last_r3 = 0
euclid0_steps = 8
euclid0_pulses = 4
euclid1_steps = 8
euclid1_pulses = 4
euclid2_steps = 8
euclid2_pulses = 4
euclid3_steps = 8
euclid3_pulses = 4
rhythm0 = bjorklund(euclid0_steps, euclid0_pulses)
rhythm1 = bjorklund(euclid1_steps, euclid1_pulses)
rhythm2 = bjorklund(euclid2_steps, euclid2_pulses)
rhythm3 = bjorklund(euclid3_steps, euclid3_pulses)
# read buttons to update Euclidean rhythms
# pylint: disable=too-many-branches
def read_buttons(button_array, button_states, euc, e_step, e_pulse, the_step):
for b in range(5):
if not button_array[b].value and button_states[b] is False:
button_states[b] = True
if button0_names[b] == "Select":
e_step = 8
e_pulse = 4
if the_step >= e_step:
the_step = 0
elif button0_names[b] == "Up":
if e_step > 16:
e_step = 16
else:
e_step += 1
elif button0_names[b] == "Down":
if e_step < 1:
e_step = 1
else:
e_step -= 1
if the_step >= e_step:
the_step = 0
elif button0_names[b] == "Left":
e_pulse -= 1
e_pulse = max(e_pulse, 1)
else:
e_pulse += 1
e_pulse = min(e_pulse, e_step)
euc = bjorklund(e_step, e_pulse)
if button_array[b].value and button_states[b] is True:
button_states[b] = False
if button0_names[b] in ("Select", "Up", "Down"):
matrix0.fill(matrix0.LED_OFF)
draw_steps(euclid0_steps, 0)
draw_steps(euclid1_steps, 2)
draw_steps(euclid2_steps, 4)
draw_steps(euclid3_steps, 6)
return euc, e_step, e_pulse, the_step
# play euclidean rhythms and update matrix
def play_euclidean(this_synth, n, the_rhythm, rhythm_count, last_count, c, matrix_slot):
if last_count <= 7:
matrix0[matrix_slot, last_count] = matrix0.LED_GREEN
else:
c -= 1
matrix0[matrix_slot + 1, (last_count - last_count) + c] = matrix0.LED_GREEN
c += 1
if the_rhythm[rhythm_count] == 1:
this_synth.frequency = n[randint(0, 2)]
synth.press(this_synth)
if rhythm_count <= 7:
matrix0[matrix_slot, rhythm_count] = matrix0.LED_RED
else:
matrix0[matrix_slot + 1, (rhythm_count - rhythm_count) + c] = matrix0.LED_RED
c += 1
else:
synth.release(this_synth)
if rhythm_count > 7:
c += 1
last_count = rhythm_count
rhythm_count += 1
if rhythm_count >= len(the_rhythm):
rhythm_count = 0
if rhythm_count == 1:
c = 0
return rhythm_count, last_count, c
# initial matrix draw
def draw_steps(euc_steps, col):
dif = 0
for m in range(euc_steps):
if m <= 7:
matrix0[col, m] = matrix0.LED_GREEN
else:
matrix0[col + 1, (m - m) + dif] = matrix0.LED_GREEN
dif += 1
draw_steps(euclid0_steps, 0)
draw_steps(euclid1_steps, 2)
draw_steps(euclid2_steps, 4)
draw_steps(euclid3_steps, 6)
# clocks for playing euclidean and reading menu encoder
enc_clock = ticks_ms()
menu_clock = ticks_ms()
# the modes menu
modes = ["PLAY", "EUC ", "BPM ", "BEAT", "ADSR", "WAVE", "RING", "LFO ", "VOL "]
mode_index = 0
mode = modes[mode_index]
menu_display.print(f" {mode}")
# default chords
chord0_sel = 0
chord1_sel = 1
chord2_sel = 0
chord3_sel = 1
display0.print(chord_names[chord0_sel])
display1.print(chord_names[chord1_sel])
display2.print(chord_names[chord2_sel])
display3.print(chord_names[chord3_sel])
# arrays of individual buttons
select_buttons = [buttons0[0], buttons1[0], buttons2[0], buttons3[0]]
left_buttons = [buttons0[2], buttons1[2], buttons2[2], buttons3[2]]
right_buttons = [buttons0[4], buttons1[4], buttons2[4], buttons3[4]]
select_states = [button0_states[0], button1_states[0], button2_states[0], button3_states[0]]
left_states = [button0_states[2], button1_states[2], button2_states[2], button3_states[2]]
right_states = [button0_states[4], button1_states[4], button2_states[4], button3_states[4]]
select_index = 0
left_index = 0
right_index = 0
# adsr mode
adsr_names = ["A", "D", "S", "R"]
synth_adsr_indexes = [0, 0, 0, 0]
adsr_properties = [0, 1, 4, 2]
adsr0_values = [amp_env0.attack_time, amp_env0.decay_time,
amp_env0.sustain_level, amp_env0.release_time]
adsr1_values = [amp_env1.attack_time, amp_env1.decay_time,
amp_env1.sustain_level, amp_env1.release_time]
adsr2_values = [amp_env0.attack_time, amp_env0.decay_time,
amp_env0.sustain_level, amp_env0.release_time]
adsr3_values = [amp_env1.attack_time, amp_env1.decay_time,
amp_env1.sustain_level, amp_env1.release_time]
all_adsr_values = [adsr0_values, adsr1_values, adsr2_values, adsr3_values]
adsr0_val = int(simpleio.map_range(amp_env0.attack_time, 0.0, 1.0, 0, 19))
adsr1_val = int(simpleio.map_range(amp_env0.decay_time, 0.0, 1.0, 0, 19))
adsr2_val = int(simpleio.map_range(amp_env0.sustain_level, 0.0, 1.0, 0, 19))
adsr3_val = int(simpleio.map_range(amp_env0.release_time, 0.0, 1.0, 0, 19))
clock_stretch = False
ring0_val = 0
ring1_val = 0
ring2_val = 0
ring3_val = 0
lfo_val = 0
# used to play/pause
play_states = [True, True, True, True]
while True:
# rotary encoder reading
if ticks_diff(ticks_ms(), enc_clock) >= 100:
position0 = encoder0.position
position1 = encoder1.position
position2 = encoder2.position
position3 = encoder3.position
menuPosition = menu_enc.position
# menu changes mode
if menuPosition != last_menuPosition:
if menuPosition > last_menuPosition:
mode_index = (mode_index + 1) % len(modes)
else:
mode_index = (mode_index - 1) % len(modes)
if mode in ("EUC ", "ADSR"):
clock_stretch = True
if mode in ("PLAY", "BPM ", "BEAT", "WAVE") and clock_stretch:
clock = ticks_ms()
clock_stretch = False
mode = modes[mode_index]
menu_display.print(f" {mode}")
last_menuPosition = menuPosition
# encoder functionality depends on mode
# encoder 0 has most functionality
if position0 != last_position0:
if position0 > last_position0:
if mode == "PLAY":
chord0_sel = (chord0_sel + 1) % len(chords)
display0.print(chord_names[chord0_sel])
elif mode == "BEAT":
beat_index = (beat_index + 1) % 5
delay = int((beat_div[beat_index] / bpm) * 1000)
display0.print(f" {beat_names[beat_index]}")
elif mode == "BPM ":
bpm += 1
delay = int((beat_div[beat_index] / bpm) * 1000)
display0.print(f" {bpm}")
elif mode == "ADSR":
adsr0_val = (adsr0_val + 1) % 20
mapped_val = simpleio.map_range(adsr0_val, 0, 19, 0.0, 1.0)
all_adsr_values[0][synth_adsr_indexes[0]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[0][0],
decay_time = all_adsr_values[0][1],
release_time=all_adsr_values[0][3],
attack_level=1, sustain_level=all_adsr_values[0][2])
synth0.envelope = the_env
elif mode == "WAVE":
synth0_wave = (synth0_wave + 1) % len(wave_names)
synth0.waveform = waveforms[synth0_wave]
elif mode == "RING":
ring0_val = (ring0_val + 1) % 25
mapped_val = simpleio.map_range(ring0_val, 0, 24, 0.0, 220.0)
synth0.ring_frequency = mapped_val
elif mode == "LFO ":
lfo_val = (lfo_val + 1) % 10
mapped_val = simpleio.map_range(lfo_val, 0, 9, 0.0, 5.0)
lfo.rate = mapped_val
elif mode == "VOL ":
vol_val = (vol_val + 1) % 10
mapped_val = simpleio.map_range(vol_val, 0, 9, 0.0, 1.0)
mixer.voice[0].level = mapped_val
else:
if mode == "PLAY":
chord0_sel = (chord0_sel - 1) % len(chords)
display0.print(chord_names[chord0_sel])
elif mode == "BEAT":
beat_index = (beat_index - 1) % 5
delay = int((beat_div[beat_index] / bpm) * 1000)
display0.print(f" {beat_names[beat_index]}")
elif mode == "BPM ":
bpm -= 1
display0.print(f" {bpm}")
elif mode == "ADSR":
adsr0_val = (adsr0_val - 1) % 20
mapped_val = simpleio.map_range(adsr0_val, 0, 19, 0.0, 1.0)
all_adsr_values[0][synth_adsr_indexes[0]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[0][0],
decay_time = all_adsr_values[0][1],
release_time=all_adsr_values[0][3],
attack_level=1, sustain_level=all_adsr_values[0][2])
synth0.envelope = the_env
elif mode == "WAVE":
synth0_wave = (synth0_wave - 1) % len(wave_names)
synth0.waveform = waveforms[synth0_wave]
elif mode == "RING":
ring0_val = (ring0_val - 1) % 25
mapped_val = simpleio.map_range(ring0_val, 0, 24, 0.0, 220.0)
synth0.ring_frequency = mapped_val
elif mode == "LFO ":
lfo_val = (lfo_val - 1) % 10
mapped_val = simpleio.map_range(lfo_val, 0, 9, 0.0, 5.0)
lfo.rate = mapped_val
elif mode == "VOL ":
vol_val = (vol_val - 1) % 10
mapped_val = simpleio.map_range(vol_val, 0, 9, 0.0, 1.0)
mixer.voice[0].level = mapped_val
last_position0 = position0
if position1 != last_position1:
if position1 > last_position1:
if mode == "PLAY":
chord1_sel = (chord1_sel + 1) % len(chords)
display1.print(chord_names[chord1_sel])
elif mode == "ADSR":
adsr1_val = (adsr1_val + 1) % 20
mapped_val = simpleio.map_range(adsr1_val, 0, 19, 0.0, 1.0)
all_adsr_values[1][synth_adsr_indexes[1]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[1][0],
decay_time = all_adsr_values[1][1],
release_time=all_adsr_values[1][3],
attack_level=1, sustain_level=all_adsr_values[1][2])
synth1.envelope = the_env
elif mode == "WAVE":
synth1_wave = (synth1_wave + 1) % len(wave_names)
synth1.waveform = waveforms[synth1_wave]
elif mode == "RING":
ring1_val = (ring1_val + 1) % 25
mapped_val = simpleio.map_range(ring1_val, 0, 24, 0.0, 220.0)
synth1.ring_frequency = mapped_val
else:
if mode == "PLAY":
chord1_sel = (chord1_sel - 1) % len(chords)
display1.print(chord_names[chord1_sel])
elif mode == "ADSR":
adsr1_val = (adsr1_val - 1) % 20
mapped_val = simpleio.map_range(adsr1_val, 0, 19, 0.0, 1.0)
all_adsr_values[1][synth_adsr_indexes[1]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[1][0],
decay_time = all_adsr_values[1][1],
release_time=all_adsr_values[1][3],
attack_level=1, sustain_level=all_adsr_values[1][2])
synth1.envelope = the_env
elif mode == "WAVE":
synth1_wave = (synth1_wave - 1) % len(wave_names)
synth1.waveform = waveforms[synth1_wave]
elif mode == "RING":
ring1_val = (ring1_val - 1) % 25
mapped_val = simpleio.map_range(ring1_val, 0, 24, 0.0, 220.0)
synth1.ring_frequency = mapped_val
last_position1 = position1
if position2 != last_position2:
if position2 > last_position2:
if mode == "PLAY":
chord2_sel = (chord2_sel + 1) % len(chords)
elif mode == "ADSR":
adsr2_val = (adsr2_val + 1) % 20
mapped_val = simpleio.map_range(adsr2_val, 0, 19, 0.0, 1.0)
all_adsr_values[2][synth_adsr_indexes[2]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[2][0],
decay_time = all_adsr_values[2][1],
release_time=all_adsr_values[2][3],
attack_level=1, sustain_level=all_adsr_values[2][2])
synth2.envelope = the_env
elif mode == "WAVE":
synth2_wave = (synth2_wave + 1) % len(wave_names)
synth2.waveform = waveforms[synth2_wave]
elif mode == "RING":
ring2_val = (ring2_val + 1) % 25
mapped_val = simpleio.map_range(ring2_val, 0, 24, 0.0, 220.0)
synth2.ring_frequency = mapped_val
else:
if mode == "PLAY":
chord2_sel = (chord2_sel - 1) % len(chords)
display2.print(chord_names[chord2_sel])
elif mode == "ADSR":
adsr2_val = (adsr2_val - 1) % 20
mapped_val = simpleio.map_range(adsr2_val, 0, 19, 0.0, 1.0)
all_adsr_values[2][synth_adsr_indexes[2]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[2][0],
decay_time = all_adsr_values[2][1],
release_time=all_adsr_values[2][3],
attack_level=1, sustain_level=all_adsr_values[2][2])
synth2.envelope = the_env
elif mode == "WAVE":
synth2_wave = (synth2_wave - 1) % len(wave_names)
synth2.waveform = waveforms[synth2_wave]
elif mode == "RING":
ring2_val = (ring2_val - 1) % 25
mapped_val = simpleio.map_range(ring2_val, 0, 24, 0.0, 220.0)
synth2.ring_frequency = mapped_val
last_position2 = position2
if position3 != last_position3:
if position3 > last_position3:
if mode == "PLAY":
chord3_sel = (chord3_sel + 1) % len(chords)
display3.print(chord_names[chord3_sel])
elif mode == "ADSR":
adsr3_val = (adsr3_val + 1) % 20
mapped_val = simpleio.map_range(adsr3_val, 0, 19, 0.0, 1.0)
all_adsr_values[3][synth_adsr_indexes[3]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[3][0],
decay_time = all_adsr_values[3][1],
release_time=all_adsr_values[3][3],
attack_level=1, sustain_level=all_adsr_values[3][2])
synth3.envelope = the_env
elif mode == "WAVE":
synth3_wave = (synth3_wave + 1) % len(wave_names)
synth3.waveform = waveforms[synth3_wave]
elif mode == "RING":
ring3_val = (ring3_val + 1) % 25
mapped_val = simpleio.map_range(ring3_val, 0, 24, 0.0, 220.0)
synth3.ring_frequency = mapped_val
else:
if mode == "PLAY":
chord3_sel = (chord3_sel - 1) % len(chords)
display3.print(chord_names[chord3_sel])
elif mode == "ADSR":
adsr3_val = (adsr3_val - 1) % 20
mapped_val = simpleio.map_range(adsr3_val, 0, 19, 0.0, 1.0)
all_adsr_values[3][synth_adsr_indexes[3]] = mapped_val
the_env = synthio.Envelope(attack_time=all_adsr_values[3][0],
decay_time = all_adsr_values[3][1],
release_time=all_adsr_values[3][3],
attack_level=1, sustain_level=all_adsr_values[3][2])
synth3.envelope = the_env
elif mode == "WAVE":
synth3_wave = (synth3_wave - 1) % len(wave_names)
synth3.waveform = waveforms[synth3_wave]
elif mode == "RING":
ring3_val = (ring3_val - 1) % 25
mapped_val = simpleio.map_range(ring3_val, 0, 24, 0.0, 220.0)
synth3.ring_frequency = mapped_val
last_position3 = position3
enc_clock = ticks_add(enc_clock, 100)
# synth plays based on ticks timing
if ticks_diff(ticks_ms(), clock) >= delay:
if play_states[0] is True:
r0, last_r0, c0 = play_euclidean(synth0, chords[chord0_sel],
rhythm0, r0, last_r0, c0, 0)
if play_states[1] is True:
r1, last_r1, c1 = play_euclidean(synth1, chords[chord1_sel],
rhythm1, r1, last_r1, c1, 2)
if play_states[2] is True:
r2, last_r2, c2 = play_euclidean(synth2, chords[chord2_sel],
rhythm2, r2, last_r2, c2, 4)
if play_states[3] is True:
r3, last_r3, c3 = play_euclidean(synth3, chords[chord3_sel],
rhythm3, r3, last_r3, c3, 6)
clock = ticks_add(clock, delay)
# in PLAY select button controls play/pause
if mode == "PLAY":
for i in range(4):
if not select_buttons[i].value and select_states[i] is False:
select_states[i] = True
if play_states[i] is True:
synth.release(synths[i])
play_states[i] = False
else:
play_states[i] = True
if select_buttons[i].value and select_states[i] is True:
select_states[i] = False
display0.print(chord_names[chord0_sel])
display1.print(chord_names[chord1_sel])
display2.print(chord_names[chord2_sel])
display3.print(chord_names[chord3_sel])
# EUC menu select resets cycle count
elif mode == "EUC ":
if not menu_buttons[0].value and menu_states[0] is False:
r0 = 0
r1 = 0
r2 = 0
r3 = 0
menu_states[0] = True
if menu_buttons[0].value and menu_states[0] is True:
menu_states[0] = False
rhythm0, euclid0_steps, euclid0_pulses, r0 = read_buttons(buttons0, button0_states,
rhythm0, euclid0_steps,
euclid0_pulses, r0)
rhythm1, euclid1_steps, euclid1_pulses, r1 = read_buttons(buttons1, button1_states,
rhythm1, euclid1_steps,
euclid1_pulses, r1)
rhythm2, euclid2_steps, euclid2_pulses, r2 = read_buttons(buttons2, button2_states,
rhythm2, euclid2_steps,
euclid2_pulses, r2)
rhythm3, euclid3_steps, euclid3_pulses, r3 = read_buttons(buttons3, button3_states,
rhythm3, euclid3_steps,
euclid3_pulses, r3)
display0.print(f" {euclid0_pulses}")
display1.print(f" {euclid1_pulses}")
display2.print(f" {euclid2_pulses}")
display3.print(f" {euclid3_pulses}")
# BPM is adjusted
elif mode == "BPM ":
if not select_buttons[0].value and select_states[0] is False:
bpm = 120
select_states[0] = True
if select_buttons[0].value and select_states[0] is True:
select_states[0] = False
display0.print(f" {bpm}")
display1.print(" ")
display2.print(" ")
display3.print(" ")
# beat division is changed
elif mode == "BEAT":
if not select_buttons[0].value and select_states[0] is False:
beat_names[beat_index] = 2
select_states[0] = True
if select_buttons[0].value and select_states[0] is True:
select_states[0] = False
display0.print(f" {beat_names[beat_index]}")
display1.print(" ")
display2.print(" ")
display3.print(" ")
# adsr for each voice
elif mode == "ADSR":
for i in range(4):
if not left_buttons[i].value and left_states[i] is False:
synth_adsr_indexes[i] = (synth_adsr_indexes[i] - 1) % 4
left_states[i] = True
the_synth = synths[i]
if left_buttons[i].value and left_states[i] is True:
left_states[i] = False
if not right_buttons[i].value and right_states[i] is False:
synth_adsr_indexes[i] = (synth_adsr_indexes[i] + 1) % 4
right_states[i] = True
if right_buttons[i].value and right_states[i] is True:
right_states[i] = False
if not select_buttons[i].value and select_states[i] is False:
the_synth = synths[i]
all_adsr_values[i][0] = 0.1
all_adsr_values[i][1] = 0.1
all_adsr_values[i][3] = 0.1
all_adsr_values[i][2] = 0.05
the_env = synthio.Envelope(attack_time=all_adsr_values[i][0],
decay_time = all_adsr_values[i][1],
release_time=all_adsr_values[i][3],
attack_level=1, sustain_level=all_adsr_values[i][2])
the_synth.envelope = the_env
select_states[i] = True
if select_buttons[i].value and select_states[i] is True:
select_states[i] = False
# pylint: disable=line-too-long
display0.print(f"{adsr_names[synth_adsr_indexes[0]]}{synth0.envelope[adsr_properties[synth_adsr_indexes[0]]]:.2f}")
display1.print(f"{adsr_names[synth_adsr_indexes[1]]}{synth1.envelope[adsr_properties[synth_adsr_indexes[1]]]:.2f}")
display2.print(f"{adsr_names[synth_adsr_indexes[2]]}{synth2.envelope[adsr_properties[synth_adsr_indexes[2]]]:.2f}")
display3.print(f"{adsr_names[synth_adsr_indexes[3]]}{synth3.envelope[adsr_properties[synth_adsr_indexes[3]]]:.2f}")
# change waveform
elif mode == "WAVE":
display0.print(f" {wave_names[synth0_wave]}")
display1.print(f" {wave_names[synth1_wave]}")
display2.print(f" {wave_names[synth2_wave]}")
display3.print(f" {wave_names[synth3_wave]}")
# adjust ring modulation
elif mode == "RING":
display0.print(f" {synth0.ring_frequency:.1f}")
display1.print(f" {synth1.ring_frequency:.1f}")
display2.print(f" {synth2.ring_frequency:.1f}")
display3.print(f" {synth3.ring_frequency:.1f}")
# adjust lfo rate used for ring modulation
elif mode == "LFO ":
display0.print("RATE")
display1.print(f" {lfo.rate:.1f}")
display2.print(" ")
display3.print(" ")
# overall volume 0.0 - 1.0
elif mode == "VOL ":
display0.print(f" {mixer.voice[0].level:.1f}")
display1.print(" ")
display2.print(" ")
display3.print(" ")

View file

@ -1,88 +0,0 @@
// SPDX-FileCopyrightText: 2021 Limor Fried for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include <Adafruit_NeoPixel.h>
#include <RotaryEncoder.h>
#define PIN_ENCODER_A 12
#define PIN_ENCODER_B 13
#define COM_A 11 // for wiring simplicity we set these output LOW
#define COM_B SDA // ... but you can just wire these to GND instead!
#define BUTTON_UP SCL
#define BUTTON_LEFT 5
#define BUTTON_DOWN 6
#define BUTTON_RIGHT 9
#define BUTTON_IN 10
RotaryEncoder encoder(PIN_ENCODER_A, PIN_ENCODER_B, RotaryEncoder::LatchMode::TWO03);
// This interrupt will do our encoder reading/checking!
void checkPosition() {
encoder.tick(); // just call tick() to check the state.
}
int last_rotary = 0;
#define NUMPIXELS 12
Adafruit_NeoPixel pixels(NUMPIXELS, A0, NEO_GRB + NEO_KHZ800);
void setup(void) {
Serial.begin(115200);
// while (!Serial);
Serial.println("ANO encoder + NeoPixel test");
pinMode(COM_A, OUTPUT);
digitalWrite(COM_A, LOW);
pinMode(COM_B, OUTPUT);
digitalWrite(COM_B, LOW);
attachInterrupt(PIN_ENCODER_A, checkPosition, CHANGE);
attachInterrupt(PIN_ENCODER_B, checkPosition, CHANGE);
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_LEFT, INPUT_PULLUP);
pinMode(BUTTON_RIGHT, INPUT_PULLUP);
pinMode(BUTTON_IN, INPUT_PULLUP);
pixels.begin();
pixels.setBrightness(30);
pixels.show();
}
void loop(void) {
// read encoder
int curr_rotary = encoder.getPosition();
RotaryEncoder::Direction direction = encoder.getDirection();
pixels.clear();
if (curr_rotary != last_rotary) {
Serial.print("Encoder value: ");
Serial.print(curr_rotary);
Serial.print(" direction: ");
Serial.println((int)direction);
}
last_rotary = curr_rotary;
pixels.setPixelColor((curr_rotary + (1000*NUMPIXELS)) % NUMPIXELS, pixels.Color(0, 150, 0));
if (! digitalRead(BUTTON_UP)) {
pixels.setPixelColor(0, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_LEFT)) {
pixels.setPixelColor(NUMPIXELS/4, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_DOWN)) {
pixels.setPixelColor(NUMPIXELS/2, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_RIGHT)) {
pixels.setPixelColor(NUMPIXELS*3/4, pixels.Color(150, 0, 0));
}
if (! digitalRead(BUTTON_IN)) {
pixels.fill(pixels.Color(50, 50, 50));
}
pixels.show();
delay(20);
}

View file

@ -1,43 +0,0 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""AS5600 Encoder"""
import usb_hid
import board
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
import adafruit_as5600
i2c = board.STEMMA_I2C()
sensor = adafruit_as5600.AS5600(i2c)
enc_inc = ConsumerControlCode.VOLUME_INCREMENT
enc_dec = ConsumerControlCode.VOLUME_DECREMENT
cc = ConsumerControl(usb_hid.devices)
last_val = sensor.angle
THRESHOLD = sensor.max_angle // 2 # default max_angle is 4095
# you can change the max_angle. ex: sensor.max_angle = 1000
MIN_CHANGE = 25 # minimum change to register as movement
# increase to make less sensitive, decrease to make more sensitive
while True:
enc_val = sensor.angle
if abs(enc_val - last_val) >= MIN_CHANGE or abs(enc_val - last_val) > THRESHOLD:
# Calculate the difference
diff = enc_val - last_val
# Check for wraparound
if diff > THRESHOLD:
# Wrapped from ~4095 to ~0 (actually turning backwards)
cc.send(enc_dec)
elif diff < -THRESHOLD:
# Wrapped from ~0 to ~4095 (actually turning forwards)
cc.send(enc_inc)
elif diff > 0:
# Normal forward rotation
cc.send(enc_inc)
else:
# Normal backward rotation (diff < 0)
cc.send(enc_dec)
last_val = enc_val

View file

@ -1,7 +1,3 @@
# SPDX-FileCopyrightText: 2020 Collin Cunningham for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
"""ACTIVITY GENERATOR for Adafruit CLUE"""
import time

View file

@ -1,7 +1,3 @@
# SPDX-FileCopyrightText: 2020 Collin Cunningham for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
activities = [
"DRAWING",
"SONG",

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*
ADAVOICE is an Arduino-based voice pitch changer plus WAV playback.
Fun for Halloween costumes, comic convention getups and other shenanigans!

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*
This is a mash-up of the adavoice and wavface sketches.
Using an Arduino, Wave Shield and some supporting components,

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*
Dalek voice effect using Wave Shield. This is based on the adavoice sketch
with a lot of code & comments ripped out, so see that code for more insight,

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2016 James DeVito for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
/*********************************************************************
This is an example for our nRF51822 based Bluefruit LE modules

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2016 James DeVito for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
// COMMON SETTINGS
// ----------------------------------------------------------------------------------------------
// These settings are used in both SW UART, HW UART and SPI mode

View file

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2016 James DeVito for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
#include <string.h>
#include <Arduino.h>
#include <SPI.h>

View file

@ -1,8 +1,3 @@
// SPDX-FileCopyrightText: 2019 Erin St. Blaine for Adafruit Industries
// SPDX-FileCopyrightText: 2019 John Edgar Park for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
//Ada_remoteFXTrigger_RX_NeoPixel
//Remote Effects Trigger Box Receiver
//by John Park & Erin St Blaine

View file

@ -1,8 +1,3 @@
// SPDX-FileCopyrightText: 2019 Erin St. Blaine for Adafruit Industries
// SPDX-FileCopyrightText: 2019 John Edgar Park for Adafruit Industries
//
// SPDX-License-Identifier: MIT
//
//Ada_remoteFXTrigger_NeoTrellis_TX
//Remote Effects Trigger Box Transmitter
//by John Park

View file

@ -0,0 +1,42 @@
# Adabot Operation Game
# CPX, alligator clips, copper tape, tweezers, surgery, and fun!
import board
import touchio
from adafruit_circuitplayground.express import cpx
# import time # uncomment if testing raw read values
cap_pins = (board.A1, board.A2, board.A3, board.A4, board.A5,
board.A6, board.A7)
touch_pads = []
for i in range(7):
touch_pads.append(touchio.TouchIn(cap_pins[i]))
for touch_pad in touch_pads:
touch_pad.threshold = 3500 # adjust value to fine-tune touch threshold
MAGENTA = (10, 0, 10)
VIOLET = (5, 0, 15)
BLUE = (0, 0, 20)
CYAN = (0, 10, 10)
GREEN = (0, 20, 0)
YELLOW = (10, 10, 0)
ORANGE = (15, 5, 0)
RED = (20, 0, 0)
WHITE = (3, 3, 3)
COLORS = [MAGENTA, VIOLET, BLUE, CYAN, GREEN, YELLOW, ORANGE, RED, WHITE]
cpx.pixels.fill(WHITE)
while True:
for i in range(7):
# uncomment block to check the raw touch pad values
# print("raw %s value for pad " % i)
# print(touch_pads[i].raw_value)
# time.sleep(.5)
if touch_pads[i].value:
# print("Touched %s" % i) # uncomment for debugging
cpx.pixels.fill(RED)
cpx.play_tone(660, 0.7)
cpx.pixels.fill(COLORS[i])

View file

@ -1,46 +0,0 @@
# SPDX-FileCopyrightText: 2018 John Park for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
# Adabot Operation Game
# CPX, alligator clips, copper tape, tweezers, surgery, and fun!
import board
import touchio
from adafruit_circuitplayground.express import cpx
# import time # uncomment if testing raw read values
cap_pins = (board.A1, board.A2, board.A3, board.A4, board.A5,
board.A6, board.A7)
touch_pads = []
for i in range(7):
touch_pads.append(touchio.TouchIn(cap_pins[i]))
for touch_pad in touch_pads:
touch_pad.threshold = 3500 # adjust value to fine-tune touch threshold
MAGENTA = (10, 0, 10)
VIOLET = (5, 0, 15)
BLUE = (0, 0, 20)
CYAN = (0, 10, 10)
GREEN = (0, 20, 0)
YELLOW = (10, 10, 0)
ORANGE = (15, 5, 0)
RED = (20, 0, 0)
WHITE = (3, 3, 3)
COLORS = [MAGENTA, VIOLET, BLUE, CYAN, GREEN, YELLOW, ORANGE, RED, WHITE]
cpx.pixels.fill(WHITE)
while True:
for i in range(7):
# uncomment block to check the raw touch pad values
# print("raw %s value for pad " % i)
# print(touch_pads[i].raw_value)
# time.sleep(.5)
if touch_pads[i].value:
# print("Touched %s" % i) # uncomment for debugging
cpx.pixels.fill(RED)
cpx.play_tone(660, 0.7)
cpx.pixels.fill(COLORS[i])

Some files were not shown because too many files have changed in this diff Show more