Danke erstmal für eure Hinweise ![]()
Ich habe mir ein paar Gedanken dazu gemacht.
Der Bereich, also ganz oben im Code, wo Einstellungen vorgenommen werden, wo ich jetzt auch demotime belasse, dient dazu Werte einzustellen. Wenn ich (oder jemand anders) nach ein paar Monaten dort etwas ändere, wo die Erinnerung an die damalige (jetzige) Zeit verblasst ist, kann ich den Wert von brightness, aus welchen Gründen auch immer auf über 50 setzen. Dies würde dann im Setup, was sich erst weiter unten im Code befindet, wieder korrigiert. Natürlich ohne irgendwelche Fehlermeldung. Daher denke ich, das es sinnvoll ist diese Zeile im Setup zu belassen.
würde ja auch nur etwas bringen, wenn brightness unveränderbar bliebe. Sobald ich aber in den globalen Einstellungen brightness höher setzte, läuft diese Abfrage ebenso in das sinnlose.
Der Ansatz von combie ist dann schon eher etwas in die Richtung, denke aber das dort auch wieder mehr Speicher verbraucht wird? Muss mich damit mal tiefer auseinander setzen.
Der Wert, der die LED-Programme ausbremsen soll, habe ich jetzt zur Struktur Control hinzugefügt:
const Control controlArray[] = { // Eigenschaften der Programme (faden, demoaktiv)
//{FadeInOut, Demoaktiv, Bremse}
{false, false, 55 }, //Cube
{false, false, 5 }, //Dice
{false, false, 5 }, //FadeOnSite
{true, true, 55 }, //Disco
{true, true, 35 }, //Rainbow
{false, true, 55 }, //Flash
{false, true, 300 }, //Snake
{false, true, 5 }, //Rain
{false, true, 5 } //HeartBeat
};
Und mache den millis() vergleich nur einmalig in der control Funktion:
void control(){
if (bitRead(intdata,2)){
freefallprog(); // Wenn Freier Fall erkannt, LED Muster für Freien Fall starten
intdata = read8(ADXL345_INT_SOURCE); // ADXL Interupt Speicher auslesen und damit leeren, verhindert doppeltes ausführen von freefallprog()
nextProgram(); // Erhöhe den Programzähler oder setzt auf Null Wenn Programmanzahl überschritten
}
if (inaktiv && !controlArray[program].demoaktiv){ // Wenn inaktiv und aktuelles Programm nicht für DemoModus
nextProgram(); // Erhöhe den Programzähler oder setzt auf Null Wenn Programmanzahl überschritten
}
else if(millis()-millis_merker_prog>controlArray[program].bremse){
millis_merker_prog = millis();
switch (program) { // Programm nach Programmzähler wählen
case Cube:
cube(readADXLtop()); // Sechs immer oben
break;
case Dice:
dice(); // WürfelModus
break;
case FadeOnSite:
fadeonsite(); // Farbwechsel abhängig der oben liegenden Seite
break;
case Disco:
disco(); // Disco, zufällige Farbwiedergabe
break;
case Rainbow:
rainbow(); // Farbwechsel nach Regenbogen
break;
case Flash:
flash(); // Zufälliges Aufblitzen
break;
case Snake:
snake(); // Schlange
break;
case Rain:
rain(readADXLtop()); // Simuliert Regen, Farbe abhängig der oben liegenden Seite
break;
case HeartBeat:
heartbeat(); // Simuliert Herzklopfen
break;
default:
break;
}
fadeInOut(); // Funktion zum gemütlichen Übergang, wenn im Programm hinterlegt
}
}
Das reduziert den Code auf immerhin:
Der Sketch verwendet 6860 Bytes (83%) des Programmspeicherplatzes. Das Maximum sind 8192 Bytes.
Globale Variablen verwenden 334 Bytes (65%) des dynamischen Speichers, 178 Bytes für lokale Variablen verbleiben. Das Maximum sind 512 Bytes.
Treibt den Arbeitsspeicher etwas hoch, aber noch ok. Hatte schon mehr verbrauch in früherern Versionen und das Programm lief stabil.
Etwas stört mich aber daran. Ich habe LED-Programme, die die "bremse" beeinflussen wöllten. Da die Struktur Control aber eine Konstante ist, geht dies nicht mehr. Also müsste ich sie variabel machen.
constexpr weist dem Kompiler an, alle Variblen vor dem Kompilieren durch diesen Wert schon zu ersetzen, ähnlich dem define, nur das nach eine Typ abfrage stattfindet, ob der Wert überhaupt passt. Soweit richtig verstanden?
Ist constexpr generell const vorzuziehen? Also einfach alle const durch constexpr ersetzen? Oder gibt es bestimmte Fälle wo const dem constexpr vorzuziehen ist?
Hier noch der aktuelle Stand des Codes:
// +----------+ +---------+
// Pixel | 51 52 53 | Fläche | ^ |
// | 48 49 50 | | 5 |
// | 45 46 47 | | |
// +----------+----------+----------+----------+ +---------+---------+---------+---------+
// | 33 34 35 | 36 39 42 | 06 07 08 | 09 12 15 | | ^ | | ^ | |
// | 30 31 32 | 37 40 43 | 03 04 05 | 10 13 16 | | 3 | 4 > | 0 | 1 > |
// | 27 28 29 | 38 41 44 | 00 01 02 | 11 14 17 | | | | | |
// +----------+----------+----------+----------+ +---------+---------+---------+---------+
// | 18 21 24 | | |
// | 19 22 25 | | 2 > |
// | 20 23 26 | | |
// +----------+ +---------+
#if (F_CPU>7370000) //neopixel library required 7.37MHz minimum clock speed; this line is used to skip this sketch in internal testing. It is not needed in your sketches.
#include <tinyNeoPixel_Static.h> // ATTiny WS2812b Bibliothek
#include <TinyWireM.h> // ATTiny I2C Bibliothek
#include <avr/power.h>
// ATTiny WS2812b Initialisierung
const uint8_t datenPin = 4; // WS2812b DatenPin
const uint8_t ledAnzahl = 54; // WS2812b LED Anzahl
uint8_t pixels[ledAnzahl * 3]; // Array für jede LED und dessen Farbe
tinyNeoPixel strip = tinyNeoPixel(ledAnzahl, datenPin, NEO_GRB, pixels);
uint8_t brightness = 50; // Variable für die Helligkeit; 0 bis 50, Aus bis Volle Heligkeit
const uint32_t demotime = 100000; // Zeitschwelle zum wechseln zum nächsten Programm im Demo-Modus (Millisekunden)
uint8_t intdata; // Variable für Interupts vom ADXL345b
uint16_t mem = 0; // Zwischenspeicher
uint8_t program = 0; // Welches Programm ist aktiv
bool inaktiv = false; // Inaktivität erkannt
uint8_t red = 255, green = 255, blue = 255; // Farbvariablen für den Strip
uint32_t millis_merker_demo; // Zwischenspeicher für Millis zum Programmwechsel im Demomodus
uint32_t millis_merker_prog; // Zwischenspeicher für Millis um die Programme etwas zu bremsen
const uint64_t Sequenz[] PROGMEM { // Bitmuster der Zahlen die gezeigt werden entsprechend wie der Würfel sich dreht, verwendung im Programm cube() //bitRead von rechts nach links^^
0b101010101101000101000010000100000001100010001111000111, // µC-PCP zeigt 6 //top=0
0b101000101000010000100000001100010001111000111101010101, // µC-PCP zeigt 5 //top=1
0b000010000100000001100010001111000111101010101101000101, // µC-PCP zeigt 4 //top=2
0b100000001100010001111000111101010101101000101000010000, // µC-PCP zeigt 1 //top=3
0b100010001111000111101010101101000101000010000100000001, // µC-PCP zeigt 2 //top=4
0b111000111101010101101000101000010000100000001100010001, // µC-PCP zeigt 3 //top=5
};
enum : uint8_t{ // Oben, Rechts, Links, Unten durchnummeriert
Oben, // = 0b00 = 0
Rechts, // = 0b01 = 1
Links, // = 0b10 = 2
Unten // = 0b11 = 3
};
const uint8_t partner[6][4] PROGMEM { // Erstellt ein FlächenArray (0-5) wo von jede anliegende Fläche (oben, rechts, links, unten) (0-3) die Fläche und welche Kante (oben, rechts, links, unten) anliegt Bitweise (0bKKFFF) hinterlegt ist
// Oben liegt // Rechts liegt // Links liegt // Unten liegt
{5 + (Rechts << 3), 1 + (Unten << 3), 4 + (Oben << 3), 2 + (Unten << 3)}, // Fläche 0 // Bsp: An Fläche 0 liegt oben Fläche 5 an mit seiner rechten Kante
{3 + (Links << 3), 2 + (Links << 3), 5 + (Oben << 3), 0 + (Rechts << 3)}, // Fläche 1 // Bsp: An Fläche 1 liegt rechts Fläche 2 an mit seiner linken Kante
{3 + (Unten << 3), 4 + (Rechts << 3), 1 + (Rechts << 3), 0 + (Unten << 3)}, // Fläche 2
{5 + (Links << 3), 4 + (Unten << 3), 1 + (Oben << 3), 2 + (Oben << 3)}, // Fläche 3
{0 + (Links << 3), 2 + (Rechts << 3), 5 + (Unten << 3), 3 + (Rechts << 3)}, // Fläche 4
{1 + (Links << 3), 0 + (Oben << 3), 3 + (Oben << 3), 4 + (Links << 3)} // Fläche 5
};
enum : uint8_t{ // Programme in der Reihenfolge Nummeriert, gleichzeitig die Reihenfolge der Programme
Cube, // Programm 0
Dice, // Programm 1
FadeOnSite, // Programm 2
Disco, // Programm 3
Rainbow, // Programm 4
Flash, // Programm 5
Snake, // Programm 6
Rain, // Programm 7
HeartBeat // Programm 8
};
struct Control{ // Struktur zum kontrolliern der Programme
bool fadeinout; // Soll im Demomodus ein Faden beim Programmwechsel stattfinden, weicher Programwechsel
bool demoaktiv; // Soll das Programm im Demo-Modus wiedergegeben werden
uint16_t bremse; // Bremst das LED-Program aus, gibt an aller wieviel Millisekunden es aufgerufen werden soll
};
const Control controlArray[] = { // Eigenschaften der Programme (faden, demoaktiv)
//{FadeInOut, Demoaktiv, Bremse}
{false, false, 100 }, //Cube
{false, false, 15 }, //Dice
{false, false, 15 }, //FadeOnSite
{true, true, 70 }, //Disco
{true, true, 40 }, //Rainbow
{false, true, 10 }, //Flash
{false, true, 300 }, //Snake
{false, true, 15 }, //Rain
{false, true, 10 } //HeartBeat
};
// I²C Register am ADXL
/* registers */
#define ADXL345_ADDRESS 0x53
#define ADXL345_DEVID 0x00
#define ADXL345_THRESH_TAP 0x1D
#define ADXL345_OFSX 0x1E
#define ADXL345_OFSY 0x1F
#define ADXL345_OFSZ 0x20
#define ADXL345_DUR 0x21
#define ADXL345_LATENT 0x22
#define ADXL345_WINDOW 0x23
#define ADXL345_THRESH_ACT 0x24
#define ADXL345_THRESH_INACT 0x25
#define ADXL345_TIME_INACT 0x26
#define ADXL345_ACT_INACT_CTL 0x27
#define ADXL345_THRESH_FF 0x28
#define ADXL345_TIME_FF 0x29
#define ADXL345_TAP_AXES 0x2A
#define ADXL345_ACT_TAP_STATUS 0x2B
#define ADXL345_BW_RATE 0x2C
#define ADXL345_POWER_CTL 0x2D
#define ADXL345_INT_ENABLE 0x2E
#define ADXL345_INT_MAP 0x2F
#define ADXL345_INT_SOURCE 0x30
#define ADXL345_DATA_FORMAT 0x31
#define ADXL345_DATAX0 0x32
#define ADXL345_DATAX1 0x33
#define ADXL345_DATAY0 0x34
#define ADXL345_DATAY1 0x35
#define ADXL345_DATAZ0 0x36
#define ADXL345_DATAZ1 0x37
#define ADXL345_FIFO_CTL 0x38
#define ADXL345_FIFO_STATUS 0x39
/* Register bits */
#define ADXL345_FULL_RES 0x03
#define ADXL345_SUPPRESS 0x03
#define ADXL345_LOW_POWER 0x04
void setup(){
pinMode(datenPin,OUTPUT);
pinMode(A3,INPUT);
randomSeed(analogRead(A3));
TinyWireM.begin(); // Beginnt eine I²C Verbindung als Master
if (brightness > 50) brightness = 50; // Helligkeit auf 50 begrenzen, Hardwarebedingt, sonnst zu großer Strom
strip.setBrightness(brightness); // Helligkeit setzen
strip.clear(); // Alle LEDs auschalten
strip.show(); // geänderte Werte der LEDs anzeigen
/* Register setzen. Mehr information im Datenblatt*/
writeTo(ADXL345_DATA_FORMAT, B00001000); // B3 == Volle Auflösung = 1, 10-Bit Auflösung = 0 | B1B0 == Sensibilität, siehe Datenblatt
writeTo(ADXL345_BW_RATE, B00001101); // Setzt 800Hz Ausgangs Datenrate (nicht I²C), B4B3B2B1, siehe Datenblatt Tabelle 7 und 8, Seite 14
writeTo(ADXL345_POWER_CTL, 0); // Always be sure to zero out register, don't asume it's zero
writeTo(ADXL345_POWER_CTL, B00001000); // 0 | 0 | Verknüpfen von In-/Aktivität | Automatisch schlafen | Messen Aktiv | Sleep | Wake Up | Wake Up
writeTo(ADXL345_INT_ENABLE, B01111100); // Interupts aktivieren DATA_READY | SINGLE_TAP | DOUBLE_TAP | Activity | Inactivity | FREE_FALL | Watermark | Overrun
writeTo(ADXL345_THRESH_TAP, 50); // Klopf Schwelle (guter Wert ist 200)
writeTo(ADXL345_DUR, 0x30); // Klopf Dauer einstellen, 0 = Klopfen deaktiviert
writeTo(ADXL345_LATENT, 0x30); // Latenz - Zeit bis zum erwarten des zweiten Klopfens, davor wird ignoriert, 0 = Doppelklopfen deaktiviert
writeTo(ADXL345_WINDOW, 0xFF); // Zeit Spanne wo ein zweites Klopfen passieren muss, damit es ein Doppelklopfen wird, 0 = Doppelklopfen deaktiviert
writeTo(ADXL345_TAP_AXES, B00001111); // Achsen zum (Klopfen) aktivieren: 0 | 0 | 0 | 0 | Unterdrückung bei Bewegung An/Aus | X-Achse Tap An/Aus | Y-Achse Tap An/Aus | Z-Achse Tap An/Aus
/* Freier Fall wird erkannt wenn Z, X und Y gleichzeitig den Wert nahe 0 haben, dazu müssen X, Y und Z im ADXL ein Offset haben damit der Free Fall Detektor das korrekt an den Interupt gibt */
writeTo(ADXL345_THRESH_FF, 4); // Freier Fall Schwelle (0-255), 5-9 wird empfohlen laut Datenblatt
writeTo(ADXL345_TIME_FF, 50); // Freier Fall Mindestzeit (0-255), 20 für 100mSec - 70 für 350mSec wird empfohlen laut Datenblatt
writeTo(ADXL345_OFSX, 255); // internen Offset setzen, 0 Aus, 1-123 = +, 255-124 = - // im 2g Modus ~4Einheiten pro Bit
writeTo(ADXL345_OFSY, 42); // internen Offset setzen, 0 Aus, 1-123 = +, 255-124 = - // im 2g Modus ~4Einheiten pro Bit
writeTo(ADXL345_OFSZ, 187); // internen Offset setzen, 0 Aus, 1-123 = +, 255-124 = - // im 2g Modus ~4Einheiten pro Bit
writeTo(ADXL345_THRESH_ACT, 30); // Schwellwert zum erkennen einer Aktivität
writeTo(ADXL345_THRESH_INACT, 30); // Schwellwert zum erkennen einer Inaktivität
writeTo(ADXL345_TIME_INACT, 255); // Zeit die der Schwellwert der Inaktivität überschritten werden muss 0-255 Sekunden
writeTo(ADXL345_ACT_INACT_CTL, B11111111); // Einstellungen ACT 0=DC 1=AC | ACT (erkennen) X 0=Aus 1=An | ACT Y | ACT Z | INACT 0=DC 1=AC | INACT (erkennen) X 0=Aus 1=An | INACT Y | INACT Z
}
void loop(){
readADXLint(); // Funktion ADXL Interupts auswerten
control(); // Funktion zum Programmablauf steuern
strip.show();
}
void control(){
if (bitRead(intdata,2)){
freefallprog(); // Wenn Freier Fall erkannt, LED Muster für Freien Fall starten
intdata = read8(ADXL345_INT_SOURCE); // ADXL Interupt Speicher auslesen und damit leeren, verhindert doppeltes ausführen von freefallprog()
nextProgram(); // Erhöhe den Programzähler oder setzt auf Null Wenn Programmanzahl überschritten
}
if (inaktiv && !controlArray[program].demoaktiv){ // Wenn inaktiv und aktuelles Programm nicht für DemoModus
nextProgram(); // Erhöhe den Programzähler oder setzt auf Null Wenn Programmanzahl überschritten
}
else if(millis()-millis_merker_prog>controlArray[program].bremse){
millis_merker_prog = millis();
switch (program){ // Programm nach Programmzähler wählen
case Cube:
cube(readADXLtop()); // Sechs immer oben
break;
case Dice:
dice(); // WürfelModus
break;
case FadeOnSite:
fadeonsite(); // Farbwechsel abhängig der oben liegenden Seite
break;
case Disco:
disco(); // Disco, zufällige Farbwiedergabe
break;
case Rainbow:
rainbow(); // Farbwechsel nach Regenbogen
break;
case Flash:
flash(); // Zufälliges Aufblitzen
break;
case Snake:
snake(); // Schlange
break;
case Rain:
rain(readADXLtop()); // Simuliert Regen, Farbe abhängig der oben liegenden Seite
break;
case HeartBeat:
heartbeat(); // Simuliert Herzklopfen
break;
default:
break;
}
fadeInOut(); // Funktion zum gemütlichen Übergang, wenn im Programm hinterlegt
}
}
void fadeInOut(){
static uint8_t fadebrightness = brightness;
if(controlArray[program].fadeinout){
if(millis() - millis_merker_demo > demotime && inaktiv){
if (--fadebrightness == 0){
millis_merker_demo = millis();
nextProgram();
}
}
else if(fadebrightness < brightness) fadebrightness++;
}
else{
fadebrightness = brightness;
if(millis() - millis_merker_demo > demotime && inaktiv){
millis_merker_demo = millis();
nextProgram();
fadebrightness = 0;
}
}
if(fadebrightness>brightness)fadebrightness=brightness;
}
void nextProgram(){
if (++program >= (sizeof(controlArray)/sizeof(controlArray[0]))) program = 0;
}
uint8_t readNachbarPixel(uint8_t pixel, uint8_t orientation){
uint8_t side = pixel / 9; // vom übergebenen Pixel die Flächennummer 0-5
uint8_t index = pixel % 9; // vom übergebenen Pixel die Indexnummer auf seiner Fläche 0-8
uint8_t result = 0; // Rückgabewertvariable
switch (orientation){ // an welcher Kante liegt die abfragende Seite
case Oben: // 0
switch (index){ // welches obere Pixel auf der Fläche sucht den oberen Nachbar
case 6: // Ecke oben links
result = callPixel(side, Oben, 0); // callPixel(Fläche des Fragenden Pixels, Kannte des Fragenden Pixels, Position im Bezug zur Kante wenn man von der Mitte schaut (0=Rechts, 1=Mitte, 2=Links));
break;
case 7: // Seite oben mitte
result = callPixel(side, Oben, 1);
break;
case 8: // Ecke oben rechts
result = callPixel(side, Oben, 2);
break;
default:
result = pixel + 3;
break;
}
break;
case Rechts: // 1
switch (index){
case 8: // Ecke oben rechts
result = callPixel(side, Rechts, 0);
break;
case 5: // Seite rechts mitte
result = callPixel(side, Rechts, 1);
break;
case 2: // Ecke unten rechts
result = callPixel(side, Rechts, 2);
break;
default:
result = pixel + 1;
break;
}
break;
case Links: // 2
switch (index){
case 0: // Ecke unten links
result = callPixel(side, Links, 0); //ori-2+ori/3+ori/3
break;
case 3: // Seite links mitte
result = callPixel(side, Links, 1); //1
break;
case 6: // Ecke oben links
result = callPixel(side, Links, 2); //
break;
default:
result = pixel - 1;
break;
}
break;
case Unten: // 3
switch (index){
case 2: // Ecke unten rechts
result = callPixel(side, Unten, 0);
break;
case 1: // Seite unten mitte
result = callPixel(side, Unten, 1);
break;
case 0: // Ecke unten links
result = callPixel(side, Unten, 2);
break;
default:
result = pixel - 3;
break;
}
break;
}
return result;
}
uint8_t callPixel(uint8_t aufruferFlaeche, uint8_t aufruferKante, uint8_t index){
uint8_t pgm = pgm_read_byte(&partner[aufruferFlaeche][aufruferKante]); // Holt Daten über anliegende Fläche mit ihrer anliegenden Kante aus dem PROGMEM
uint8_t flaeche = pgm & 0b111; // Beispiel [0][1] (Fläche rechts von 0) // 0b00001 + 0b11000 = 0b11001 // 0b11001 & 0b111 = 0b1 = 1 // Fläche 1
uint8_t kante = pgm >> 3; // schiebt Bits des Arrays partner [Fläche] [Kante] um 3 Bits nach rechts, Es bleibt die anliegende Kante übrig // 0b11001 >> 3 = 0b11 = 3 = Unten
uint8_t result = 0; // Rückgabewertvariable
switch (kante){ // abhängig davon, welche Kante an der Aufruferfläche liegt
case Oben: //0
result = 8 - index; // errechnet anhand des index, das Pixel auf der Fläche. Möglich 6, 7 oder 8
break;
case Unten: //3
result = 0 + index; // errechnet anhand des index, das Pixel auf der Fläche. Möglich 0, 1 oder 2
break;
case Rechts: //1
result = 2 + index * 3; // errechnet anhand des index, das Pixel auf der Fläche. Möglich 2, 5 oder 8
break;
case Links: //2
result = 6 - index * 3; // errechnet anhand des index, das Pixel auf der Fläche. Möglich 0, 3 oder 6
break;
}
result = result + flaeche * 9; // errechnet nahand der Fläche die Pixelnummer
return result;
}
/*ADXL345 Komunikation*/
void readADXLint(){
static uint8_t last_program = 0; // Programmspeicher welches vor Demo aktiv war
intdata = read8(ADXL345_INT_SOURCE); // Interups Auslesen und im ADXL leeren
if(bitRead(intdata,3)&&!inaktiv){ // Wenn Inaktivität erkannt (keine Änderung über ADXL345_TIME_INACT eigestellte Sekunden)
inaktiv = true;
millis_merker_demo = millis();
last_program = program; // Aktives Program im ProgramMerker hinterlegen
}
if(bitRead(intdata,4)&&inaktiv){ // Wenn Aktivität erkannt
inaktiv = false;
program = last_program; // Letztes aktives Program aus dem ProgramMerker holen
}
}
uint8_t readADXLtop(){ // Welche Seite liegt oben
int16_t x = read16(ADXL345_DATAX0); // X Achsenwert auslesen
int16_t y = read16(ADXL345_DATAY0); // Y Achsenwert auslesen
int16_t z = read16(ADXL345_DATAZ0); // Z Achsenwert auslesen
uint8_t top = 0;
if(x>200) top=1; //Fläche 1 oben
if(y>200) top=2; //Fläche 2 oben
if(z>200) top=3; //Fläche 3 oben
if(x<-200) top=4; //Fläche 4 oben
if(y<-200) top=5; //Fläche 5 oben
if(z<-200) top=0; //Fläche 0 oben
return top;
}
uint16_t read16(uint8_t address){
uint8_t MSByte = 0, LSByte = 0;
int16_t regValue = 0;
TinyWireM.beginTransmission(ADXL345_ADDRESS);
TinyWireM.write(address);
TinyWireM.endTransmission();
TinyWireM.requestFrom(ADXL345_ADDRESS, 2);
if(TinyWireM.available()){
LSByte = TinyWireM.read();
MSByte = TinyWireM.read();
}
regValue = (MSByte<<8) + LSByte;
return regValue;
}
uint8_t read8(uint8_t address){
uint8_t regValue = 0;
TinyWireM.beginTransmission(ADXL345_ADDRESS);
TinyWireM.write(address);
TinyWireM.endTransmission();
TinyWireM.requestFrom(ADXL345_ADDRESS, 1);
if(TinyWireM.available()){
regValue = TinyWireM.read();
}
return regValue;
}
void writeTo(uint8_t address, uint8_t val){
TinyWireM.beginTransmission(ADXL345_ADDRESS);
TinyWireM.write(address);
TinyWireM.write(val);
TinyWireM.endTransmission();
}
/*LED Programme*/
void heartbeat(){
if(red>55) red=0; // Wenn der RotWert über 55 dann RotWert auf 0 setzen
if(red==55) mem++; // Wenn RotWert 55 erreicht hat, Merker um eins erhöhen (damit später Rot reduziert wird bei mem gleich 1 oder 3)
if(red==0) mem++; // Wenn RotWert 0 erreicht hat, Merker um eins erhöhen (damit später Rot erhöht wird bei mem gleich 0 oder 2) und damit der Merker für die Pause erhöht wird
if(mem>=4) delay(100); // Wenn Merker über 4, eine Pause einlegen (Also 50-4= 46mal 0,1s Pause)
if(mem>=50) mem=0; // Wenn Merker über 50, dann Merker wieder auf 0, was die Pause beendet, und Rot wieder erhöht
if(mem == 0 || mem == 2) red++; // Wenn Merker 0 oder 2 Rot erhöhen
else if(mem == 1 || mem == 3) red--; // Wenn Merker 1 oder 3 Rot verringern
else red=0; // Sicherstellen das Rot 0 ist wenn Merker einen anderen Wert hat (Kann durch andere Funktionen (LED-Programme) geändert werden
strip.clear();
for(uint8_t site=0; site<6; site++){ // Auf jeder Würfelseite ausführen
if(red>=40) for(uint8_t i=0; i<9; i+=2) strip.setPixelColor(i+9*site, red-40, 0, 0); // Wenn rot größer 40 (verspäteter start) schreibe jedes gerade pixel auf der Würfelseite (Ecken und Mitte (Mitte wird später überschrieben)
if(red>=20) for(uint8_t i=1; i<8; i+=2) strip.setPixelColor(i+9*site, red-20, 0, 0); // Wenn rot größer 20 (verspäteter start) schreibe jedes ungerade pixel auf der Würfelseite (oben, unten, links, rechts)
strip.setPixelColor(4+9*site, red, 0, 0); // schreibe auf die mitte (Pixel 4) der Seite
}
}
void freefallprog(){ // lässt jedes zweite Pixel 6mal rot blinken // diese Funktion soll bewusst blockieren
for(uint8_t j=0; j<6; j++){
strip.clear();
for(uint8_t i=0; i<ledAnzahl; i+=2){
strip.setPixelColor(i,255,0,0);
}
strip.show();
delay(100);
strip.clear();
strip.show();
delay(100);
}
}
void rain(uint8_t side){
static uint8_t raincolor[12][4]; // Zwischenpeicher der Farbwerte für Regenmuster
uint8_t rainPixel[12]; // Speichert die 12 obenliegenden Regenpixel
int8_t changer[4]; // Speichert die Verechenoberratoren für die nach unten folgenden Pixel
for(uint8_t i=0; i<4; i++){ // Für alle 4 anliegenden Seiten (oben = 0, rechts = 1, links = 2, unten = 3)
for(uint8_t j=0; j<3; j++){ // Für alle 3 anliegenden Pixel der Seite (Index 0, 1, 2)
rainPixel[i*3+j] = callPixel(side, i, j); // Übergebe die 12 Pixel in das rainPixelArray // i*3+j ergibt die Nummerierung für das Array(0-11)
}
uint8_t upsite = pgm_read_byte(&partner[side][i]); // Liest die Information von der anliegenden Fläche (BitArray)
upsite = upsite >> 3; // gibt von der anliegenden Fläche die obere Kante wieder (schiebt die FlächenInfo Bits raus)
changer[i] = upsite *2 -3; // Seite 5, index 852 -1 // Seite 1, 012 +3 // Seite 4, 678 -3 // Seite 2, 012 +3 // gibt gibt anhand der oben liegenden Kante, den verrechen operator für die darunter folgenden Pixel aus (0*2-3=-3, 1*2-3=-1, 2*2-3=1, 3*2-3=3)
} // bei "oben" liegenden Pixel darunter liegende Pixel 3 kleiner, bei "rechts" liegenden Pixel, darunter liegende 1 kleiner, etc
switch (side){ // Farbwahl nach Seite
case 0: red=255; green=0; blue=0; break;
case 1: red=0; green=255; blue=255; break;
case 2: red=255; green=0; blue=255; break;
case 3: red=255; green=255; blue=0; break;
case 4: red=0; green=0; blue=255; break;
case 5: red=0; green=255; blue=0; break;
}
mem=random(0,150); // erstellt merker zum zufälligen Starten
strip.clear();
for(uint8_t row=0; row<12; row++){ // row steht für eine der 12 möglichen senkrechten Reihen
if (raincolor[row][3]>49){ // wenn Zähler über 49
strip.setPixelColor(rainPixel[row]+changer[row/3]+changer[row/3],raincolor[row][0],raincolor[row][1],raincolor[row][2]); // setze Farbe aufs untere pixel
strip.setPixelColor(rainPixel[row]+changer[row/3],raincolor[row][0]/1.1,raincolor[row][1]/1.1,raincolor[row][2]/1.1); // setze Farbe aufs zweite Pixel von oben mit 90% Leuchtkraft
strip.setPixelColor(rainPixel[row],raincolor[row][0]/1.1/1.1,raincolor[row][1]/1.1/1.1,raincolor[row][2]/1.1/1.1); // setze Farbe aufs obere Pixel mit 90% von 90% Leuichtkraft
for(uint8_t i=0; i<3; i++){
raincolor[row][i] = raincolor[row][i]/1.1; // reduziere die Leuchtkraft um 90%
}
if(raincolor[row][0]<1&&raincolor[row][1]<1&&raincolor[row][2]<1){ // wenn alle Farbwerte unter 1
for(uint8_t i=0; i<4; i++){
raincolor[row][i] = 0; // Zähler zurücksetzen und sicherstellen das Farbwerte gleich 0
}
}
}
if (raincolor[row][3]<50&&raincolor[row][3]>24){ // wenn Zähler 25 bis 49
strip.setPixelColor(rainPixel[row]+changer[row/3],raincolor[row][0],raincolor[row][1],raincolor[row][2]); // setze Farbe aufs zweite pixel von oben
strip.setPixelColor(rainPixel[row],raincolor[row][0]/1.1,raincolor[row][1]/1.1,raincolor[row][2]/1.1); // setzt Farbe aufs obere pixel mit 90% Leuichtkraft
++raincolor[row][3];
}
if (raincolor[row][3]<25&&raincolor[row][3]>0){ // wenn Zähler 1 bis 24
strip.setPixelColor(rainPixel[row],raincolor[row][0],raincolor[row][1],raincolor[row][2]); // setze Farbe aufs obere Pixel der Reihe
++raincolor[row][3]; // Zähler um 1 erhöhen
}
if (mem==row&&raincolor[row][3]==0){ // wenn Zufalsmerker gleich j, und Zähler der Reihe gleich 0
raincolor[row][0]=red; raincolor[row][1]=green; raincolor[row][2]=blue; // setze übergebe Farbewerte, gesetzt nach Seite die oben liegt
++raincolor[row][3]; // Zähler für Reihe auf 1 setzen (Zählen ist füpr Zeitverzögerung zuständig)
}
}
}
void snake(){
static uint8_t viper[] = {4,54,54,54,54,54}; // Schlangen Position Array
uint8_t nachbarPixel[4];
mem = 0;
for(uint8_t i=0; i<4; i++){ // für alle 4 Nachbarpixel überprüfen
bool crash = false;
for(uint8_t k=1; k<sizeof(viper); k++){ // für alle Pixel die die Schlange belegt überprüfen
if(readNachbarPixel(viper[0],i) == viper[k]){ // wenn das Nachbarpixel gleich eines Pixels der Schlange
crash = true;
}
}
if (!crash) { // wenn das Nachbarpixel keine besetzte Position ist
nachbarPixel[mem] = readNachbarPixel(viper[0],i); // dann schiebe den PixelIndex über eventuelle mögliche Pixel
mem++; // Zähler für mögliche Pixel erhöhen
}
}
strip.clear();
for(uint8_t j = sizeof(viper)-1; j>0; j--){ // Über die Länge der Schlange
viper[j] = viper[j-1]; // Übergib das gespeicherte Pixel im Viper Array eine Position Richtung Ende, das letzte fällt weg
strip.setPixelColor(viper[j],255-(j*40),0+(j*40),0); // setze Farbewerte ändernd Richtung Schanzende (Von Rot Kopf, über gelb Richtung grün
}
viper[0] = nachbarPixel[random(0,mem)]; // übergibt dem Kopf, eine zufällige auswahl aus den möglichen Nachbarpixeln
strip.setPixelColor(viper[0],255,0,0); // Farbwert Kopf
}
void flash(){
if(!random(100)){ // nur in einem von 100 Fällen ausführen
strip.setPixelColor(random(ledAnzahl-1),random(255),random(255),random(255));
strip.show();
delay(7); // länge des aufblitzen in Millisekunden
strip.clear();
}
}
void rainbow(){
if(red > 250 || green > 250 || blue > 250){
red=250; blue=0; green=0;
}
uint8_t newred = red;
uint8_t newgreen = green;
uint8_t newblue = blue;
for(uint8_t i=0; i<ledAnzahl; i++){
if(newred == 250 && newblue == 0 && newgreen < 250) newgreen += 10;
else if(newred > 0 && newblue == 0 && newgreen == 250) newred -= 10;
else if(newred == 0 && newblue < 250 && newgreen == 250) newblue += 10;
else if(newred == 0 && newblue == 250 && newgreen > 0) newgreen -= 10;
else if(newred < 250 && newblue == 250 && newgreen == 0) newred += 10;
else if(newred == 250 && newblue > 0 && newgreen == 0) newblue -= 10;
strip.setPixelColor(i,newred,newgreen,newblue);
}
if(red == 250 && blue == 0 && green < 250) green += 10;
else if(red > 0 && blue == 0 && green == 250) red -= 10;
else if(red == 0 && blue < 250 && green == 250) blue += 10;
else if(red == 0 && blue == 250 && green > 0) green -= 10;
else if(red < 250 && blue == 250 && green == 0) red += 10;
else if(red == 250 && blue > 0 && green == 0) blue -= 10;
else{
red=250; blue=0; green=0;
}
}
void disco(){
for(uint8_t i=0; i<=ledAnzahl; i++){
strip.setPixelColor(i,random(255),random(255),random(255));
}
}
void fadeonsite(){
uint8_t newred = map(read16(ADXL345_DATAX0), -280, 280, 0, 255);
uint8_t newgreen = map(read16(ADXL345_DATAY0), -280, 280, 0, 255);
uint8_t newblue = map(read16(ADXL345_DATAZ0), -280, 280, 0, 255);
if(newred+10 < red) red -= 2;
if(newred-10 > red) red += 2;
if(newgreen+10 < green) green -= 2;
if(newgreen-10 > green) green += 2;
if(newblue+10 < blue) blue -= 2;
if(newblue-10 > blue) blue += 2;
for(uint8_t i=0; i<=ledAnzahl; i++){
strip.setPixelColor(i,red,green,blue);
}
}
void dice(){
if (bitRead(intdata,6)) mem=2; // Wenn Erschütterung erkannt
if (mem < 520){ // Solange Zeitspanne unter 520 mS
cube(random(0,6)); // Wähle eine zufällige Seite oben
delay(mem); // Warte die zwischengespeicherte Zeit
mem = (mem * random(10,21)) / 10; // Erhöhe die wartezeit etwas im zufälligen Bereich (simuliert ein langsames auslaufen der Zeit
}
}
void cube(byte side){
uint64_t pgm = 0; // Zwischenspeicher für das aus dem PROGMEM geholten Bitmuster
memcpy_P(&pgm, &Sequenz[side], sizeof(pgm)); // memcpy_P holt aus dem PROGMEM Daten (Ziel, Quelle, Größe in Byte von Quelle und Ziel)
for (uint8_t index = 0; index<54; index++){
if (bitRead(pgm,index)) strip.setPixelColor(index, 255, 255, 255);
else strip.setPixelColor(index, 0, 0, 0);
}
}
#else //neopixel library required 7.37MHz minimum clock speed; these and following lines are used to skip this sketch in internal testing. It is not needed in your sketches.
#warning "Neopixel control requires F_CPU > 7.37MHz"
void setup(){}
void loop(){}
#endif