Arduino Polska Forum

Pełna wersja: ws2812 - przyciski przełączające animacje(jak ?)
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Stron: 1 2
Witam
Od dłuższego czasu próbuję zrobić przyciski które będą włączały animację na poszczególnym przycisku daną animację. Problem jest taki że nigdzie coś takiego nie znajdę. Mam jakieś gotowy program poniżej, może pomoże to w modyfikacji tak aby działało.

1. Ten program polega na tym, że jak nacisnę przycisk to zmienia się w kolejność animacji jak się napisało, czyli w tym przypadku tak:
Kod:
void loop() {
 colorWipe(strip.Color(0, 0, 0), 50);    // Black/off
 debounce();
 rainbow(20);
 debounce();
 rainbowCycle(20);
debounce();
 colorWave(20);
 debounce();
}

To jest cały kod:

Kod:
#include <Adafruit_NeoPixel.h>
float  czas;
#define PIN 6
#define STRIPSIZE 25

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(STRIPSIZE, PIN, NEO_GRB + NEO_KHZ800);

#define switch_0 A0
int tim = 60;
bool oldState = HIGH;
int stan = 0;

void setup() {
 strip.begin();
 strip.show(); // Initialize all pixels to 'off'
 pinMode(switch_0, INPUT_PULLUP);
}

void debounce() {
 unsigned long sta = millis();
 while (millis() - sta < 20UL) {
   if (digitalRead(switch_0) == LOW) {
     sta = millis();
   }
 }
}


// Main activity.
void loop() {
 colorWipe(strip.Color(0, 0, 0), 50);    // Black/off
 debounce();
 rainbow(20);
 debounce();
 rainbowCycle(20);
debounce();
 colorWave(20);
 debounce();
}

void rainbow(uint8_t wait) {
 for (;;) {
   uint16_t i, j;

   for (j = 0; j < 256; j++) {
     for (i = 0; i < strip.numPixels(); i++) {
       strip.setPixelColor(i, Wheel((i + j) & 255));
     }
     strip.show();
     delay(wait);
     if (digitalRead(switch_0) == LOW) {
       return;
     }
   }
 }
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
 for (;;) {
   for (uint16_t i = 0; i < strip.numPixels(); i++) {
     strip.setPixelColor(i, c);
     strip.show();
     delay(wait);
     if (digitalRead(switch_0) == LOW) {
       return;
     }
   }
 }
}


// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
 for (;;) {
 uint16_t i, j;

 for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
   for (i = 0; i < strip.numPixels(); i++) {
     strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
   }
   strip.show();

   delay(wait);
   if(digitalRead(switch_0) == LOW) {
               break;
           }
 }
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
 if (WheelPos < 85) {
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
 } else if (WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
 } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
 }
}

/**
       ^   ^   ^
  ~~~~~ ColorWave ~~~~~
         V   V   V
*/
void colorWave(uint8_t wait) {
 for (;;){
 int i, j, stripsize, cycle;
 float ang, rsin, gsin, bsin, offset;

 static int tick = 0;

 stripsize = strip.numPixels();
 cycle = stripsize * 25; // times around the circle...

 while (++tick % cycle) {
   offset = map2PI(tick);

   for (i = 0; i < stripsize; i++) {
     ang = map2PI(i) - offset;
     rsin = sin(ang);
     gsin = sin(2.0 * ang / 3.0 + map2PI(int(stripsize / 6)));
     bsin = sin(4.0 * ang / 5.0 + map2PI(int(stripsize / 3)));
     strip.setPixelColor(i, strip.Color(trigScale(rsin), trigScale(gsin), trigScale(bsin)));
   }

   strip.show();
   delay(wait);
   if(digitalRead(switch_0) == LOW) {
               return;
           }
 }

}
}
/**
  Scale a value returned from a trig function to a byte value.
  [-1, +1] -> [0, 254]
  Note that we ignore the possible value of 255, for efficiency,
  and because nobody will be able to differentiate between the
  brightness levels of 254 and 255.
*/
byte trigScale(float val) {
 val += 1.0; // move range to [0.0, 2.0]
 val *= 127.0; // move range to [0.0, 254.0]

 return int(val) & 255;
}

/**
  Map an integer so that [0, striplength] -> [0, 2PI]
*/
float map2PI(int i) {
 return PI * 2.0 * float(i) / float(strip.numPixels());
}


Do każdej animacji został dodany funkcja która przerywa animację, czyli pętla się zatrzymuje:

Kod:
void rainbow(uint8_t wait) {
 for (;;) {
   uint16_t i, j;

   for (j = 0; j < 256; j++) {
     for (i = 0; i < strip.numPixels(); i++) {
       strip.setPixelColor(i, Wheel((i + j) & 255));
     }
     strip.show();
     delay(wait);
     if (digitalRead(switch_0) == LOW) {      // to przerywa animację
       return;                                //
     }
   }
 }
}


Pracuję teraz na płytce genuino 101 więc na dość mocnej płytce
Użyj przerwań zewnętrznych od przycisków.
(16-06-2019, 14:25)kaczakat napisał(a): [ -> ]Użyj przerwań zewnętrznych od przycisków.

Można wskazać gdzie bo nie rozumiem, napisz jaki kod, linijka kodu
To nie jest linijka kodu, nie mam Twojej płytki więc i żadnego gotowca Ci tu nie wrzucę. Twoje debonce coś tam nie zadziała, bo funkcja migająca ledami musi się zakończyć by przejść do weryfikacji stanu przycisków. W funkcji wywołanej przez przerwanie ustaw sobie zmienną volatile cośtam by przyjmowała stan 1, w miejscu gdzie możesz opuścić funkcję sprawdzaj czy jest 1, zeruj i przerywaj działanie.
Wpisz w google arduino external interrupt, znajdziesz opis pinów do swojej płytki z tą funkcjonalnością, przykład funkcji, a także na innych stronach tutoriale. Musisz zdecydować, czy ma wykrywać zbocze narastające, opadające, zmianę w zależności jak masz podpięte przyciski.
(16-06-2019, 13:31)Jakub428 napisał(a): [ -> ]Pracuję teraz na płytce genuino 101 więc na dość mocnej płytce
Co z tego, że płytka mocna jak w kodzie masz:
(16-06-2019, 13:31)Jakub428 napisał(a): [ -> ]
Kod:
     delay(wait);
i para idzie w gwizdek.

Jak używasz delay (bez RTOS, w którym delay nie "zawiesza" CPU i inne zadania działają) to czy masz 8MHz 8-bit, czy 2GHz 64-bit, przyrostu prędkości nie zobaczysz. Aby zrozumieć mój przekaz obejrzyj filmy:
Adruino UNO - AVR (8-bit) 16MHz
ARM (32-bit) STM32F411 60MHz
Jak widać różnica jest niewielka. Powód? Nie skorzystano z możliwości sprzętowych ARM, natomiast tu:
ARM (32-bit) STM32F411 60MHz
wykorzystano DMA, różnica jest znaczna (10..13 razy szybciej).

Na koniec małe porównanie obu uC:
Szescian_3D_ARM_vs_AVR
Na AVR widać operację kasowania ekranu, na ARM dzieje się to na tyle szybko (ok 23ms), że oko tego nie zauważa.

Na poniższym filmie, AVR zmienia rozmiar prostokąta co 10 a nie co 1 piksel przy każdym odświeżeniu ekranu, bo trzeba by dłuuuugo czekać na wykonanie animacji.
Szescian_3D_i_animowane_tlo
a i tak wygląda żałośnie. Tak samo żałośnie by wyglądała na ARM gdyby nie wykorzystać jego potencjału. Ty nie wykorzystujesz potencjału uC, bo używasz delay.
A co jeżeli muszę podpiąć 20 przycisków? Bo będę używał z konwerter który ma więcej pinów analogowych a raczej nie mają tego interrup. I jak to na pisać żeby np. przycisk 1 włączył rainbow przycisk 2 kolor czerwony itd.
(16-06-2019, 21:37)Jakub428 napisał(a): [ -> ]A co jeżeli muszę podpiąć 20 przycisków?
Włącz przyciski w matrycę 5x4.
Przez ten czas coś tam próbowałem ale nie wyszło. Usunąłem delay z kodu dodałem  - interrupte - Ale to nie działa jak powinno. Przycisk nie działają, nie włącza animację albo kolor czerwony.

Nie wiem co miał na myśli kaczakat z tym:
"W funkcji wywołanej przez przerwanie ustaw sobie zmienną volatile cośtam by przyjmowała stan 1, w miejscu gdzie możesz opuścić funkcję sprawdzaj czy jest 1, zeruj i przerywaj działanie."


Problem jest teraz taki że nie wiem jak dać przerwanie, bo może dla tego nie działają przyciski
kod do przerwania animacji:
Kod:
void rainbow(uint8_t wait) {
 for (;;) {
   uint16_t i, j;

   for (j = 0; j < 256; j++) {
     for (i = 0; i < strip.numPixels(); i++) {
       strip.setPixelColor(i, Wheel((i + j) & 255));
     }
     strip.show();
     delay(wait);

// jak teraz to dodać poniżej jeżeli mam więcej przycisków(czyli 20 przycisków)
     if (digitalRead(switch_0) == LOW) {
       return;
       showType = 0;
     }
   }
 }
}

Jak ktoś ma pomysł pisać jaka linijka kodu albo np. -  przed uint16_t i, j; dodaj delay  - bo to lepiej w tedy rozumiem.

kod cały:
Kod:
/*
 Modified by combining these tutorials
   Blink without Delay  http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
   State change detection (edge detection) http://arduino.cc/en/Tutorial/ButtonStateChange
   Adafruit Strandtest https://github.com/adafruit/Adafruit_NeoPixel
   http://www.arduino.cc/en/Tutorial/Debounce
   https://github.com/EternalCore/NeoPixel_Cylon_Scrolling_Eye
*/
#include <Adafruit_NeoPixel.h>

// constants won't change.
const int buttonPin = 0; // the number of the pushbutton pin
const int buttonPin1 = 1;
#define PIN 6 //the number of the neopixel pic
#define numPixelsInStrip 25
Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPixelsInStrip, PIN, NEO_GRB + NEO_KHZ800);


// przycisk 1 //
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 50; // the debounce time; increase if the output flickers
int programState = 0; // current program seleted -- buttonpresses rotate between programs
int numOfPrograms = 7; // how many programs are there total, not including the off state


// przycisk 2 //
int ledState1 = HIGH; // the current state of the output pin
int buttonState1; // the current reading from the input pin
int lastButtonState1 = LOW; // the previous reading from the input pin
long lastDebounceTime1 = 0; // the last time the output pin was toggled
long debounceDelay1 = 50; // the debounce time; increase if the output flickers
int programState1 = 0; // current program seleted -- buttonpresses rotate between programs
int numOfPrograms1 = 7; // how many programs are there total, not including the off state



//unsigned long currentMillis = 0;  //for programs
long previousMillis = 0;        // will store last time LED was updated
int neoPixelToChange = 0; //track which neoPixel to change
int neoPixel_j = 0; //stores values for program cycles
int defaultBrightness = 64;

//cylon variables
int fadeDirection = -1;//change sigen to fade up or down
boolean cylonDirection = true; //keeps track of the direction the pixels should swipe
boolean cylonPause = false; //keeps track of the pause inbetween swipes
long delayMillis = 0; // will store the last time the cylon swipe was paused

void setup() {
 pinMode(buttonPin, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(buttonPin), StartShow, FALLING);
 pinMode(buttonPin1, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(buttonPin1), StartShow, FALLING);
 strip.begin();
 strip.show(); // Initialize all pixels to 'off'
 strip.setBrightness(defaultBrightness); // initialize brightness
}

void loop() {

 // przycisk 1 //
 int reading = digitalRead(buttonPin);
 if (reading != lastButtonState) {
   lastDebounceTime = millis();
 }
 if ((millis() - lastDebounceTime) > debounceDelay) {
   if (reading != buttonState) {
     buttonState = reading;
     if (buttonState == HIGH) {
       programState = 0;
       StartShow(programState);
     }
   }
 }

 lastButtonState = reading;
 // przycisk 2 //
 int reading1 = digitalRead(buttonPin1);
 if (reading1 != lastButtonState1) {
   lastDebounceTime1 = millis();
 }
 if ((millis() - lastDebounceTime1) > debounceDelay1) {
   if (reading1 != buttonState1) {
     buttonState1 = reading1;
     if (buttonState1 == HIGH) {
       programState = 1;
       StartShow(programState);
     }
   }
 }

 lastButtonState = reading;
}


// Co dany przycisk ma wykonać(jaką animację) //
void StartShow(int i) {
 switch (i) {
   case 0:
     colorWipe(strip.Color(0, 255, 0), 500); // green
     break;
   case 1:
     strip.setBrightness(defaultBrightness); // initialize brightness
     rainbow(5);
     break;
 }
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {

 unsigned long currentMillis = millis();
 if (neoPixelToChange <= strip.numPixels()) {
   if (currentMillis - previousMillis > wait) {
     previousMillis = currentMillis;
     strip.setPixelColor(neoPixelToChange, c);
     strip.show();
     neoPixelToChange++;
   }
 }
}

// Fill the dots one after the other with a color


void rainbow(uint8_t wait) {

 unsigned long currentMillis = millis();

 if (currentMillis - previousMillis > wait) {

   // save the last time you changed a NeoPixel
   previousMillis = currentMillis;

   //change the colors of the pixels
   uint16_t i;

   for (i = 0; i < strip.numPixels(); i++) {
     strip.setPixelColor(i, Wheel((i + neoPixel_j) & 255));
   }
   strip.show();
   neoPixel_j = (neoPixel_j + 1) % 255; //increment j until all colors are used, then start over
 }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {

 unsigned long currentMillis = millis();

 if (currentMillis - previousMillis > wait) {

   // save the last time you changed a NeoPixel
   previousMillis = currentMillis;

   //change the colors of the pixels
   uint16_t i;

   for (i = 0; i < strip.numPixels(); i++) {
     strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + neoPixel_j) & 255));
   }
   strip.show();
   neoPixel_j = (neoPixel_j + 1) % 1279; // 5 cycles of all colors on wheel, then start over
 }

}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
 if (WheelPos < 85) {
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
 } else if (WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
 } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
 }
}

void cylonEye(uint8_t swipeSpeed, uint8_t pauseTime) {

 if (cylonPause) { //we are on a pause break from swipes

   unsigned long currentPauseMillis = millis();

   //check to see if we've waited long enough
   if ((currentPauseMillis - delayMillis) > pauseTime) { /////////////////////////////// this is not getting called. Why????????????????z
     // save the last time you checked the pause
     delayMillis = currentPauseMillis;
     cylonPause = false; //end the pause
   }

 } else {

   //if needed, change directions
   if (neoPixelToChange > numPixelsInStrip) {
     cylonDirection = false;
   }
   if (neoPixelToChange < 0) {
     cylonDirection = true;
     cylonPause = true; //take a break from the swipe
     //turn all pixels off
     for (uint16_t i = 0; i < strip.numPixels(); i++) {
       strip.setPixelColor(i, strip.Color(0, 0, 0));
     }
     strip.show();
     delayMillis = millis();
   }

   //run the swipe
   if (cylonDirection) {
     cylonUp(strip.Color(255, 0, 0), strip.Color(72, 0, 0), swipeSpeed); // red
   } else {
     cylonDown(strip.Color(255, 0, 0), strip.Color(72, 0, 0), swipeSpeed); // red
   }
 }
}

void cylonUp(uint32_t c0, uint32_t c1, uint8_t wait) {

 unsigned long currentMillis = millis();

 //neoPixelToChange * wait
 if (currentMillis - previousMillis > wait) {

   //turn all pixels off
   for (uint16_t i = 0; i < strip.numPixels(); i++) {
     strip.setPixelColor(i, strip.Color(0, 0, 0));
   }

   // save the last time you changed a NeoPixel
   previousMillis = currentMillis;

   //change a pixel
   strip.setPixelColor(neoPixelToChange, c0); //primary color
   strip.setPixelColor(neoPixelToChange - 1, c1); //secondary color
   strip.setPixelColor(neoPixelToChange + 1, c1); //secondary color
   strip.show();
   neoPixelToChange++;
 }
}

void cylonDown(uint32_t c0, uint32_t c1, uint8_t wait) {

 unsigned long currentMillis = millis();

 //neoPixelToChange * wait
 if (currentMillis - previousMillis > wait) {

   //turn all pixels off
   for (uint16_t i = 0; i < strip.numPixels(); i++) {
     strip.setPixelColor(i, strip.Color(0, 0, 0));
   }

   // save the last time you changed a NeoPixel
   previousMillis = currentMillis;

   //change a pixel
   strip.setPixelColor(neoPixelToChange, c0); //primary color
   strip.setPixelColor(neoPixelToChange - 1, c1); //secondary color
   strip.setPixelColor(neoPixelToChange + 1, c1); //secondary color
   strip.show();
   neoPixelToChange--; //is there any way to combine this with cylonUp, since this is the only line that is different?
 }
}
(18-06-2019, 14:46)Jakub428 napisał(a): [ -> ]Nie wiem co miał na myśli kaczakat z tym:
"W funkcji wywołanej przez przerwanie ustaw sobie zmienną volatile cośtam by przyjmowała stan 1, w miejscu gdzie możesz opuścić funkcję sprawdzaj czy jest 1, zeruj i przerywaj działanie."
Bo nie znasz C/C++!

Kod (modyfikacje), który pokazałeś, to strzelanie na ślepo!

Zacznij więc od nauki C, następnie poznaj architekturę używanego uC a dopiero po tym zabierz się za pisanie programów, bo teraz to wygląda tak, jak znając 10 słów, chciałbyś napisać powieść w języku, którego nie znasz.

Obawiam się, ze nikt nie będzie w stanie Ci pomóc, dopóki nie poznasz języka, którego używasz, chyba, że znajdzie się ktoś, kto przeprowadzi indywidualny kurs. Pytanie po co? Darmowych kursów w internecie jest dużo i szkoda czasu, aby robić kolejny, dla jednej osoby.
Na początek otwórz nowy szkic i naucz się używać przerwań zewnętrznych. Chcesz zrobić nieco bardziej skomplikowany program to więcej musisz w niego włożyć od siebie. Przy takim programie wystarczy jedno przerwanie, wewnątrz jego obsługi możesz sprawdzić stan przycisków, ustawić zmienną "przerwij"=1 i np. "efekt" =15, wyłączasz przerwanie.
Wszystkie efekty (ich funkcje) możesz wrzucić do switch case, gdy wewnątrz efektu zauważysz przerwij=1 to ustawiasz przerwij=0, opuszczasz efekt i potem switch case, przy ponownym wejściu w switch case kasujesz ewentualne flagi przerwania, włączasz przerwanie i wchodzisz w efekt 15.
Dzięki temu nawet jeśli przycisk wcisnąłeś w czasie jakiegoś delay czy trwania innych zadań informacja o tym będzie na Ciebie czekać w zmiennej przerwij. Zmienna przerwij powinna mieć dodatkowo specyfikator volatile, bo jest zmieniana w przerwaniu i poza nim.
Stron: 1 2