Skip to content

Commit

Permalink
Support of segments of NeoPixel bars etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
ArminJo committed Sep 20, 2019
1 parent 7e57636 commit 8059f8a
Show file tree
Hide file tree
Showing 20 changed files with 415 additions and 139 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ script:
- build_platform mega2560
notifications:
email:
recipients:
- [email protected]
on_success: always
on_failure: always
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
This is an extended version version of the NeoPattern example by Adafruit https://learn.adafruit.com/multi-tasking-the-arduino-part-3?view=all.
New Patterns are added, a snake game running on a matrix is included and you can run multiple patterns simultaneously on the same strip.

| Youtube Video of NeoPatternsDemo | Youtube Video of MatrixDemo on a 10x10 matrix |
| YouTube Video of NeoPatternsDemo | YouTube Video of MatrixDemo on a 10x10 matrix |
| :-: | :-: |
| [![Demonstration of NeoPatterns](https://i.ytimg.com/vi/CsB7FkywCRQ/hqdefault.jpg)](https://www.youtube.com/watch?v=CsB7FkywCRQ) | [![Demonstration of MatrixDemo on a 10x10 matrix](https://i.ytimg.com/vi/URsq28l2PEQ/hqdefault.jpg)](https://www.youtube.com/watch?v=URsq28l2PEQ) |

Expand Down Expand Up @@ -55,6 +55,8 @@ NeoPatterns on breadboard
![NeoPatterns on breadboard](https://github.com/ArminJo/NeoPatterns/blob/master/extras/Breadboard_complete.jpg)

# Revision History
### Version 1.0.1
Support of segments of NeoPixel bars etc.
### Version 1.0.0
Initial Arduino library version

Expand Down
4 changes: 2 additions & 2 deletions examples/AllPatternsDemo/ADCUtils.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ADCUtils.cpp
*
* ADC utility functions. Conversion time is defined as 0.104 milliseconds for 16MHz Arduinos in ADCUtils.h.
* ADC utility functions. Conversion time is defined as 0.104 milliseconds for 16 MHz Arduinos in ADCUtils.h.
*
* Created on: 23.02.2018
* Copyright (C) 2018 Armin Joachimsmeyer
Expand Down Expand Up @@ -284,7 +284,7 @@ float getTemperature(void) {
bool tReferenceMustBeChanged = (ADMUX & (DEFAULT << SHIFT_VALUE_FOR_REFERENCE));
if (tReferenceMustBeChanged) {
tOldADMUX = ADMUX;
// set AREF to 1.1V and wait for settling
// set AREF to 1.1 Volt and wait for settling
ADMUX = ADC_TEMPERATURE_CHANNEL_MUX | (INTERNAL << SHIFT_VALUE_FOR_REFERENCE);
delayMicroseconds(4000); // measured value is 3500 us
}
Expand Down
6 changes: 4 additions & 2 deletions examples/AllPatternsDemo/ADCUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

#include <Arduino.h>

// PRESCALE4 => 13 * 4 = 52 microseconds per ADC conversion at 1 Mhz Clock => 19,2kHz
// PRESCALE4 => 13 * 4 = 52 microseconds per ADC conversion at 1 Mhz Clock => 19,2 kHz
#define ADC_PRESCALE2 1 // 26 microseconds per ADC conversion at 1 MHz
#define ADC_PRESCALE4 2 // 52 microseconds per ADC conversion at 1 MHz
// PRESCALE8 => 13 * 8 = 104 microseconds per ADC sample at 1 Mhz Clock => 9,6kHz
// PRESCALE8 => 13 * 8 = 104 microseconds per ADC sample at 1 Mhz Clock => 9,6 kHz
#define ADC_PRESCALE8 3 // 104 microseconds per ADC conversion at 1 MHz
#define ADC_PRESCALE16 4 // 208 microseconds per ADC conversion at 1 MHz
#define ADC_PRESCALE32 5 // 416 microseconds per ADC conversion at 1 MHz
Expand Down Expand Up @@ -72,3 +72,5 @@ uint16_t getVCCVoltageMillivolt(void);
float getTemperature(void);

#endif /* SRC_ADCUTILS_H_ */

#pragma once
85 changes: 52 additions & 33 deletions examples/AllPatternsDemo/AllPatternsDemo.ino
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@
#include <avr/power.h>
#include <avr/pgmspace.h>

#define VOLTAGE_CHECK_THRESHOLD_MILLIVOLT 3600
#define VOLTAGE_CHECK_PERIOD_MILLIS 2000
#define VOLTAGE_CHECK_PERIOD_REPETITIONS 9
#define VCC_STOP_THRESHOLD_MILLIVOLT 3400 // We have voltage drop at the connectors, so the battery voltage is assumed higher, than the Arduino VCC.
#define VCC_STOP_MIN_MILLIVOLT 3200 // We have voltage drop at the connectors, so the battery voltage is assumed higher, than the Arduino VCC.
#define VCC_STOP_PERIOD_MILLIS 2000 // Period of VCC checks
#define VCC_STOP_PERIOD_REPETITIONS 9 // Shutdown after 9 times (18 seconds) VCC below VCC_STOP_THRESHOLD_MILLIVOLT or 1 time below VCC_STOP_MIN_MILLIVOLT
#define FALLING_STAR_DURATION 12
#endif

Expand Down Expand Up @@ -106,32 +107,59 @@ void setup() {
bar16.PatternsGeometry = GEOMETRY_BAR;
bar24.PatternsGeometry = GEOMETRY_BAR;
ring12.ColorWipe(COLOR32_PURPLE, 50);
ring16.ColorWipe(COLOR32_RED, 50, DIRECTION_DOWN);
ring16.ColorWipe(COLOR32_RED, 50, 0, DIRECTION_DOWN);
ring24.ColorWipe(COLOR32_GREEN, 50);
bar16.ColorWipe(COLOR32_BLUE, 50, DIRECTION_DOWN);
bar16.ColorWipe(COLOR32_BLUE, 50, 0, DIRECTION_DOWN);
bar24.Stripes(COLOR32_BLUE, 5, COLOR32_RED, 3, 50, 48);
// bar24.ScannerExtended(COLOR32_BLUE, 5, 50, 1,
// FLAG_SCANNER_EXT_ROCKET | FLAG_SCANNER_EXT_VANISH_COMPLETE | FLAG_SCANNER_EXT_START_AT_BOTH_ENDS);
NeoPixelMatrix.clear(); // Clear matrix
NeoPixelMatrix.show();
NeoPixelMatrix.Delay(5000); // start later
setMatrixAndSnakePatternsDemoTickerText(F("I love R&C4Kids"));
setMatrixAndSnakePatternsDemoTickerText(F("I love NeoPixel"));
Serial.println("started");
}

uint8_t sWheelPosition = 0; // hold the color index for the changing ticker colors

/*
* Returns true if shutdown
*/
bool checkVCC(uint16_t aVCC) {
static uint8_t sVoltageTooLowCounter;

if (aVCC < VCC_STOP_THRESHOLD_MILLIVOLT) {
/*
* Voltage too low, wait VCC_STOP_PERIOD_REPETITIONS (9) times and then shut down.
*/
if (aVCC < VCC_STOP_MIN_MILLIVOLT) {
// emergency shutdown
sVoltageTooLowCounter = VCC_STOP_PERIOD_REPETITIONS;
Serial.println(F("Voltage < 3.2 Volt detected"));
} else {
sVoltageTooLowCounter++;
Serial.println(F("Voltage < 3.4 Volt detected"));
}
if (sVoltageTooLowCounter == VCC_STOP_PERIOD_REPETITIONS) {
Serial.println(F("Shut down"));
return true;
}
} else {
sVoltageTooLowCounter = 0;
}
return false;
}

void loop() {
#ifdef __AVR__
/*
* Check VCC every 2 seconds
*/
static long sLastMillisOfVoltageCheck;
static uint8_t sVoltageTooLowCounter;
static bool sVoltageTooLow = false;
static bool sVoltageTooLow = false; // one time flag
static char sStringBufferForVCC[7] = "xxxxmV";

if (millis() - sLastMillisOfVoltageCheck >= VOLTAGE_CHECK_PERIOD_MILLIS) {
if (millis() - sLastMillisOfVoltageCheck >= VCC_STOP_PERIOD_MILLIS) {
sLastMillisOfVoltageCheck = millis();
uint16_t tVCC = getVCCVoltageMillivoltSimple();
Serial.print(F("VCC="));
Expand All @@ -147,35 +175,26 @@ void loop() {
}

if (!sVoltageTooLow) {
if (tVCC < VOLTAGE_CHECK_THRESHOLD_MILLIVOLT) {
/*
* Voltage too low, wait VOLTAGE_CHECK_PERIOD_REPETITIONS (5) times and then shut down.
*/
sVoltageTooLowCounter++;
if (sVoltageTooLowCounter == VOLTAGE_CHECK_PERIOD_REPETITIONS) {
Serial.println(F("Voltage < 3.6 Volt detected, shut down NeoPixel"));
sVoltageTooLow = true;

initMultipleFallingStars(&bar16, COLOR32_WHITE_HALF, FALLING_STAR_DURATION, 1, NULL);
bar24.clear();
bar24.show();
ring12.clear();
ring12.show();
ring16.clear();
ring16.show();
ring24.clear();
ring24.show();
NeoPixelMatrix.clear();
NeoPixelMatrix.show();
return;
}
} else {
sVoltageTooLowCounter = 0;
if (checkVCC(tVCC)) {
sVoltageTooLow = true;

initMultipleFallingStars(&bar16, COLOR32_WHITE_HALF, FALLING_STAR_DURATION, 1, NULL);
initMultipleFallingStars(&bar24, COLOR32_WHITE_HALF, FALLING_STAR_DURATION, 1, NULL);
ring12.clear();
ring12.show();
ring16.clear();
ring16.show();
ring24.clear();
ring24.show();
NeoPixelMatrix.clear();
NeoPixelMatrix.show();
return;
}
}
}
if (sVoltageTooLow) {
bar16.Update();
bar24.Update();
delay(FALLING_STAR_DURATION);
return;
}
Expand Down
65 changes: 34 additions & 31 deletions examples/MatrixDemo/MatrixDemo.ino
Original file line number Diff line number Diff line change
Expand Up @@ -25,57 +25,60 @@
*
*/

#define VERSION_EXAMPLE "1.0"
#define VERSION_EXAMPLE "1.1"

#include <Arduino.h>
#include <MatrixSnake.h>

#define PIN_NEOPIXEL_MATRIX 8

#define NEOPIXEL_MATRIX_NUM_ROWS 8
#define NEOPIXEL_MATRIX_NUM_COLUMNS 8
#define NEOPIXEL_MATRIX_NUM_PIXELS (NEOPIXEL_MATRIX_NUM_COLUMNS * NEOPIXEL_MATRIX_NUM_ROWS)

/*
* Specify your matrix geometry as 4th parameter.
* ....BOTTOM ....RIGHT specify the position of the zeroth pixel.
* See MatrixNeoPatterns.h for further explanation.
*/
MatrixSnake NeoPixelMatrix = MatrixSnake(8, 8, PIN_NEOPIXEL_MATRIX,
NEO_MATRIX_BOTTOM | NEO_MATRIX_RIGHT | NEO_MATRIX_ROWS | NEO_MATRIX_PROGRESSIVE,
NEO_GRB + NEO_KHZ800, &MatrixAndSnakePatternsDemo);
MatrixSnake NeoPixelMatrix = MatrixSnake(NEOPIXEL_MATRIX_NUM_COLUMNS, NEOPIXEL_MATRIX_NUM_ROWS, PIN_NEOPIXEL_MATRIX,
NEO_MATRIX_BOTTOM | NEO_MATRIX_RIGHT | NEO_MATRIX_ROWS | NEO_MATRIX_PROGRESSIVE, NEO_GRB + NEO_KHZ800, &MatrixAndSnakePatternsDemo);

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);

Serial.begin(115200);
while (!Serial)
; //delay for Leonardo
// Just to know which program is running on my Arduino
Serial.println(F("START " __FILE__ "\r\nVersion " VERSION_EXAMPLE " from " __DATE__));
Serial.begin(115200);
while (!Serial)
; //delay for Leonardo
// Just to know which program is running on my Arduino
Serial.println(F("START " __FILE__ "\r\nVersion " VERSION_EXAMPLE " from " __DATE__));

// This initializes the NeoPixel library and checks if enough memory was available
if (!NeoPixelMatrix.begin(&Serial)) {
// Blink forever
while (true) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
}
// This initializes the NeoPixel library and checks if enough memory was available
if (!NeoPixelMatrix.begin(&Serial)) {
// Blink forever
while (true) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
}

extern void *__brkval;
Serial.print(F("Free Ram/Stack[bytes]="));
Serial.println(SP - (uint16_t) __brkval);
extern void *__brkval;
Serial.print(F("Free Ram/Stack[bytes]="));
Serial.println(SP - (uint16_t) __brkval);

MatrixAndSnakePatternsDemo(&NeoPixelMatrix);
MatrixAndSnakePatternsDemo(&NeoPixelMatrix);
}

uint8_t sWheelPosition = 0; // hold the color index for the changing ticker colors

void loop() {
if (NeoPixelMatrix.Update()) {
if (NeoPixelMatrix.ActivePattern == PATTERN_TICKER) {
// change color of ticker after each update
NeoPixelMatrix.Color1 = NeoPatterns::Wheel(sWheelPosition);
sWheelPosition += 4;
}
}
if (NeoPixelMatrix.Update()) {
if (NeoPixelMatrix.ActivePattern == PATTERN_TICKER) {
// change color of ticker after each update
NeoPixelMatrix.Color1 = NeoPatterns::Wheel(sWheelPosition);
sWheelPosition += 256 / NEOPIXEL_MATRIX_NUM_PIXELS;
}
}
}
3 changes: 2 additions & 1 deletion examples/SnakeAutorun/SnakeAutorun.ino
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ void setup() {

// This initializes the NeoPixel library and checks if enough memory was available
if (!NeoPixelMatrixSnake.begin(&Serial)) {
// Blink forever
Serial.println(F("Not enough memory for Snake matrix"));
// Blink forever as error indicator
while (true) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
Expand Down
36 changes: 31 additions & 5 deletions examples/SnakeGame/SnakeGame.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Simply runs the Snake game. It can be controlled by 2 or 4 buttons or by serial input (WASD).
* The experimental Python script in the extras folder converts key presses and game controller input to appropriate serial output for the game.
* After 7 seconds of inactivity it runs the Snake demo with a simple AI.
* If pin 10 is connected to ground, the game is in 2 button mode, i.e. one button for turn left and one for turn right.
*
* You need to install "Adafruit NeoPixel" library under "Tools -> Manage Libraries..." or "Ctrl+Shift+I" -> use "neoPixel" as filter string
*
Expand Down Expand Up @@ -45,6 +46,8 @@
#define UP_BUTTON_PIN 4
#define DOWN_BUTTON_PIN 5

#define TWO_BUTTON_MODE_SELECT_PIN 10 // if pulled low, then 2 button mode is activated

/*
* Specify your matrix geometry as 4th parameter.
* ....BOTTOM ....RIGHT specify the position of the zeroth pixel.
Expand All @@ -55,27 +58,50 @@ NEO_MATRIX_BOTTOM | NEO_MATRIX_RIGHT | NEO_MATRIX_PROGRESSIVE, NEO_GRB + NEO_KHZ

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(TWO_BUTTON_MODE_SELECT_PIN, INPUT_PULLUP);

Serial.begin(115200);
while (!Serial); //delay for Leonardo
while (!Serial)
; //delay for Leonardo
// Just to know which program is running on my Arduino
Serial.println(F("START " __FILE__ "\r\nVersion " VERSION_EXAMPLE " from " __DATE__));

// This initializes the NeoPixel library and checks if enough memory was available
if (!NeoPixelMatrixSnake.begin(&Serial)) {
// Blink forever
Serial.println(F("Not enough memory for Snake matrix"));
// Blink forever as error indicator
while (true) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
}
NeoPixelMatrixSnake.Snake(GAME_REFRESH_INTERVAL, COLOR32_BLUE, RIGHT_BUTTON_PIN, LEFT_BUTTON_PIN, UP_BUTTON_PIN,
DOWN_BUTTON_PIN);
if (digitalRead(TWO_BUTTON_MODE_SELECT_PIN)) {
// 4 button mode
NeoPixelMatrixSnake.Snake(GAME_REFRESH_INTERVAL, COLOR32_BLUE, RIGHT_BUTTON_PIN, LEFT_BUTTON_PIN, UP_BUTTON_PIN,
DOWN_BUTTON_PIN);
} else {
// 2 button mode
NeoPixelMatrixSnake.Snake(GAME_REFRESH_INTERVAL, COLOR32_BLUE, RIGHT_BUTTON_PIN, LEFT_BUTTON_PIN, 0, 0);
}
pinMode(TWO_BUTTON_MODE_SELECT_PIN, INPUT);
}

void loop() {
// this will start autorun mode if no input happens after booting
static bool sButtonWasPressed = false;
// Direction is DIRECTION_NONE after each game.
if ((!sButtonWasPressed) && NeoPixelMatrixSnake.Direction == DIRECTION_NONE) {
/*
* Just wait for TIME_TO_SWITCH_TO_AUTO_MODE_MILLIS and then start snake autorun mode.
*/
long tMillis = millis();
if (tMillis > TIME_TO_SWITCH_TO_AUTO_MODE_MILLIS) {
// switch to demo mode after switching delay if snake has not moved
initSnakeAutorun(&NeoPixelMatrixSnake, GAME_REFRESH_INTERVAL / 2, COLOR32_BLUE);
}
} else {
sButtonWasPressed = true;
}
NeoPixelMatrixSnake.Update();
}
4 changes: 2 additions & 2 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name=NeoPatterns
version=1.0.0
version=1.0.1
author=Armin Joachimsmeyer
maintainer=Armin Joachimsmeyer <[email protected]>
sentence=Patterns for NeoPixel strips and matrixes including the patterns of the NeoPattern Example by Adafruit.<br/>
paragraph=Patterns from Adafruit are: <ul><li>SCANNER</li><li>STRIPES</li><li>DELAY</li><li>PROCESS_SELECTIVE</li><li>FADE_SELECTIVE</li></ul>The original SCANNER pattern is extended and includes the CYLON as well as the ROCKET or FALLING_STAR pattern. The more versatile STRIPES pattern replaces the old THEATER_CHASE one.<br/><br/>NeoPixel-Matrix pattern are:<ul><li>MOVING_PICTURE</li><li>MOVE</li><li>TICKER</li><li>FIRE</li><li>SNAKE</li></ul><br/>The SNAKE pattern is an implementation of the Snake game and can be played with 2 or 4 buttons attached to the Arduino.<br/>The SnakeAutorun example will start your own code provided in the function getNextSnakeDirection() to solve the Snake game.<br/><br/>The extras folder contains sample breadboard pictures as well as a Python script, which enables Snake to be played by PC keyboard or game controller.<br/>Youtube demos are available under <a href="https://github.com/ArminJo/NeoPatterns">https://github.com/ArminJo/NeoPatterns</a>.<br/><br/>To test your own pattern, just add your pattern code to the functions UserPattern\[1,2]() and UserPattern\[1,2]Update() in NeoPatternsSimpleDemo.cpp to see the patterns. Enable TEST_USER_PATTERNS on line 39 to activate them.<br/>
paragraph=Patterns from Adafruit are: <ul><li>SCANNER</li><li>STRIPES</li><li>DELAY</li><li>PROCESS_SELECTIVE</li><li>FADE_SELECTIVE</li></ul>The original SCANNER pattern is extended and includes the CYLON as well as the ROCKET or FALLING_STAR pattern. The more versatile STRIPES pattern replaces the old THEATER_CHASE one.<br/><br/>NeoPixel-Matrix pattern are:<ul><li>MOVING_PICTURE</li><li>MOVE</li><li>TICKER</li><li>FIRE</li><li>SNAKE</li></ul><br/>The SNAKE pattern is an implementation of the Snake game and can be played with 2 or 4 buttons attached to the Arduino.<br/>The SnakeAutorun example will start your own code provided in the function getNextSnakeDirection() to solve the Snake game.<br/><br/>The extras folder contains sample breadboard pictures as well as a Python script, which enables Snake to be played by PC keyboard or game controller.<br/>YouTube demos are available under <a href="https://github.com/ArminJo/NeoPatterns">https://github.com/ArminJo/NeoPatterns</a>.<br/><br/>To test your own pattern, just add your pattern code to the functions UserPattern\[1,2]() and UserPattern\[1,2]Update() in NeoPatternsSimpleDemo.cpp to see the patterns. Enable TEST_USER_PATTERNS on line 39 to activate them.<br/>
category=Display
url=https://github.com/ArminJo/NeoPatterns
architectures=avr
Loading

0 comments on commit 8059f8a

Please sign in to comment.