• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Płytka dźwiękowa - Arduino Nano Every
#1
Cześć,
Znalazłem kod płytki dźwiękowej miecza świetlnego, trochę go poprawiłem, uprościłem i przerobiłem pod siebie, i wszystko działa jak powinno, ale tylko przy obsłudze max 50 led aRGB WS2815. Po prostu obsługa większej ilości pożera za dużo pamięci dynamicznej i program się resetuje lub zaczyna przerywać. Chcę docelowo użyć 288 diod. Dlatego wymieniłem Arduino Nano na Nano Every, i tu pojawił się problem, brak obsługi biblioteki <TMRpcm.h>. 
Ma ktoś pomysł jak zaimplementować odtwarzanie dźwięków z karty SD? W oryginale odtwarzanie dźwięków było sprzężone z żyroskopem MPU6050 i chcę aby tak zostało.
Myślę, że dołożenie modułu MAX98357 będzie niezbędne, ale co jeszcze jakie biblioteki?
A może jeszcze prościej i użyć DFR0954?
 
Odpowiedź
#2
Pokaż skąd masz ten projekt, jak zmieniłeś go istotnie i nie spodziewasz się za niego Nobla to możesz pokazać swój.
Nie musisz kupować płytek Arduino by sprawdzić, czy program będzie kompatybilny, instalujesz core do danego wynalazku - ESP8266, ESP32, MegaCoreX (tu jest obsługa uC 4809).
Można na tym etapie zrobić kompilację z wybraną płytką, przed jej zakupem i przekonać się, czy taki ruch w ogóle ma sens.
Akurat ta biblioteka sama zajmuje się generowaniem dźwięków używając timera sprzętowego, bardzo głęboko wchodzi w konkretny sprzęt. Jeśli autor nie doda obsługi konkretnego modelu uC to nie będzie się jej dało używać.
Jak nie chcesz bardzo przerabiać tego kodu to zainstaluj core MightyCoe gdzie masz Atmega644 (4kb RAM) lub Atmega1284 (16kb RAM), sprawdzić czy się kompiluje (TMRpcm się skompiluje, nie wiem jak reszta), znaleźć uC i zrobić na jego bazie własną płytkę. Ceny DIP40 są niestety absurdalne, na Aliexpress da się znaleźć 1284 w okolicy 11$ , lutowanie SMD z 48 nóżkami dość kłopotliwe. Tu jest ostatnia sztuka w ludzkiej cenie: https://allegro.pl/oferta/atmega1284p-pu...5162082676 . Mam kilka tych procków, potrzymam jeszcze z rok to może dzieciom mieszkania kupię czy co.
Dużo projektów z odtwarzaniem dźwięków znajdziesz dla ESP32, ma I2S, dużo RAM, 3.3V zasilanie nieco komplikuje, ale sumarycznie to on jest 100x wydajniejszy niż Atmega328.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
(16-02-2024, 16:34)kaczakat napisał(a): Pokaż skąd masz ten projekt, jak zmieniłeś go istotnie i nie spodziewasz się za niego Nobla to możesz pokazać swój.
Nie musisz kupować płytek Arduino by sprawdzić, czy program będzie kompatybilny, instalujesz core do danego wynalazku  - ESP8266, ESP32, MegaCoreX (tu jest obsługa uC 4809).
Można na tym etapie zrobić kompilację z wybraną płytką, przed jej zakupem i przekonać się, czy taki ruch w ogóle ma sens.
Akurat ta biblioteka sama zajmuje się generowaniem dźwięków używając timera sprzętowego, bardzo głęboko wchodzi w konkretny sprzęt. Jeśli autor nie doda obsługi konkretnego modelu uC to nie będzie się jej dało używać.
Jak nie chcesz bardzo przerabiać tego kodu to zainstaluj core MightyCoe gdzie masz Atmega644 (4kb RAM) lub Atmega1284 (16kb RAM), sprawdzić czy się kompiluje (TMRpcm się skompiluje, nie wiem jak reszta), znaleźć uC i zrobić na jego bazie własną płytkę. Ceny DIP40 są niestety absurdalne, na Aliexpress da się znaleźć 1284 w okolicy 11$ , lutowanie SMD z 48 nóżkami dość kłopotliwe. Tu jest ostatnia sztuka w ludzkiej cenie: https://allegro.pl/oferta/atmega1284p-pu...5162082676 . Mam kilka tych procków, potrzymam jeszcze z rok to może dzieciom mieszkania kupię czy co.
Dużo projektów z odtwarzaniem dźwięków znajdziesz dla ESP32, ma I2S, dużo RAM, 3.3V zasilanie nieco komplikuje, ale sumarycznie to on jest 100x wydajniejszy niż Atmega328.
 Nie no kod to żaden wynalazek, trochę tylko uprościłem i usunąłem nie potrzebne funkcje. O to kod:

Kod:
/*
     SUPER-DUPER COOL ARDUINO BASED MULTICOLOR SOUND PLAYING LIGHTSABER!
   HARDWARE:
     Addressable LED strip (WS2811) to get any blade color and smooth turn on effect
     MicroSD card module to play some sounds
     IMU MPU6050 (accel + gyro) to generate hum. Frequency depends on angle velocity of blade
     OR measure angle speed and play some hum sounds from SD
   CAPABILITIES:
     Smooth turning on/off with lightsaber-like sound effect
     Randomly pulsing color (you can turn it off)
     Sounds:
       MODE 1: generated hum. Frequency depends on angle velocity of blade
       MODE 2: hum sound from SD card
         Slow swing - long hum sound (randomly from 4 sounds)
         Fast swing - short hum sound (randomly from 5 sounds)
     Bright white flash when hitting
     Play one of 16 hit sounds, when hit
       Weak hit - short sound
       Hard hit - long "bzzzghghhdh" sound
     After power on blade shows current battery level from 0 to 100 percent
   CONTROL BUTTON:
     HOLD - turn on / turn off GyverSaber
     TRIPLE CLICK - change color (red - green - blue - yellow - pink - ice blue)
     QUINARY CLICK - change sound mode (hum generation - hum playing)
     Selected color and sound mode stored in EEPROM (non-volatile memory)
*/

// ---------------------------- SETTINGS -------------------------------
#define NUM_LEDS  144       // number of microcircuits WS2811 on LED strip (note: one WS2811 controls 3 LEDs!)
#define BTN_TIMEOUT 800     // button hold delay, ms
#define BRIGHTNESS 255      // max LED brightness (0 - 255)

#define SWING_TIMEOUT 500   // timeout between swings
#define SWING_L_THR 150     // swing angle speed threshold
#define SWING_THR 300       // fast swing angle speed threshold
#define STRIKE_THR 150      // hit acceleration threshold
#define STRIKE_S_THR 320    // hard hit acceleration threshold
#define FLASH_DELAY 80      // flash time while hit

#define Blink_ALLOW 1       // blade pulsation (1 - allow, 0 - disallow)
#define Blink_AMPL 20       // Blink amplitude
#define Blink_DELAY 30      // delay between Blinks

#define DEBUG 0             // debug information in Serial (1 - allow, 0 - disallow)
// ---------------------------- SETTINGS -------------------------------

#define LED_PIN 6
#define BTN 3
#define IMU_GND A1
#define SD_GND A0
#define BTN_LED 4

// -------------------------- LIBS ---------------------------
#include <avr/pgmspace.h>   // PROGMEM library
#include <SD.h>
#include <TMRpcm.h>         // audio from SD library
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include <toneAC.h>         // hum generation library
#include "FastLED.h"        // addressable LED library
#include <EEPROM.h>

CRGB leds[NUM_LEDS];
#define SD_ChipSelectPin 10
TMRpcm tmrpcm;
MPU6050 accelgyro;
// -------------------------- LIBS ---------------------------


// ------------------------------ VARIABLES ---------------------------------
int16_t ax, ay, az;
int16_t gx, gy, gz;
unsigned long ACC, GYR, COMPL;
int gyroX, gyroY, gyroZ, accelX, accelY, accelZ, freq, freq_f = 20;
float k = 0.2;
unsigned long humTimer = -9000, mpuTimer, nowTimer;
int stopTimer;
boolean bzzz_flag, ls_chg_state, ls_state;
boolean btnState, btn_flag, hold_flag;
byte btn_counter;
unsigned long btn_timer, Blink_timer, swing_timer, swing_timeout, bzzTimer;
byte nowNumber;
byte LEDcolor;  // 0 - red, 1 - green, 2 - blue, 3 - pink, 4 - yellow, 5 - ice blue
byte nowColor, red, green, blue, redOffset, greenOffset, blueOffset;
boolean eeprom_flag, swing_flag, swing_allow, strike_flag, HUMmode;
int blinkOffset;
// ------------------------------ VARIABLES ---------------------------------

// --------------------------------- SOUNDS ----------------------------------
// Sounds arrays and other sound-related variables
const char strike1[] PROGMEM = "SK1.wav";
const char strike2[] PROGMEM = "SK2.wav";
const char strike3[] PROGMEM = "SK3.wav";
const char strike4[] PROGMEM = "SK4.wav";
const char strike5[] PROGMEM = "SK5.wav";
const char strike6[] PROGMEM = "SK6.wav";
const char strike7[] PROGMEM = "SK7.wav";
const char strike8[] PROGMEM = "SK8.wav";

const char* const strikes[] PROGMEM  = {
  strike1, strike2, strike3, strike4, strike5, strike6, strike7, strike8
};

int strike_time[8] = {779, 563, 687, 702, 673, 661, 666, 635};

const char strike_s1[] PROGMEM = "SKS1.wav";
const char strike_s2[] PROGMEM = "SKS2.wav";
const char strike_s3[] PROGMEM = "SKS3.wav";
const char strike_s4[] PROGMEM = "SKS4.wav";
const char strike_s5[] PROGMEM = "SKS5.wav";
const char strike_s6[] PROGMEM = "SKS6.wav";
const char strike_s7[] PROGMEM = "SKS7.wav";
const char strike_s8[] PROGMEM = "SKS8.wav";

const char* const strikes_short[] PROGMEM = {
  strike_s1, strike_s2, strike_s3, strike_s4,
  strike_s5, strike_s6, strike_s7, strike_s8
};
int strike_s_time[8] = {270, 167, 186, 250, 252, 255, 250, 238};

const char swing1[] PROGMEM = "SWS1.wav";
const char swing2[] PROGMEM = "SWS2.wav";
const char swing3[] PROGMEM = "SWS3.wav";
const char swing4[] PROGMEM = "SWS4.wav";
const char swing5[] PROGMEM = "SWS5.wav";

const char* const swings[] PROGMEM  = {
  swing1, swing2, swing3, swing4, swing5
};
int swing_time[8] = {389, 372, 360, 366, 337};

const char swingL1[] PROGMEM = "SWL1.wav";
const char swingL2[] PROGMEM = "SWL2.wav";
const char swingL3[] PROGMEM = "SWL3.wav";
const char swingL4[] PROGMEM = "SWL4.wav";

const char* const swings_L[] PROGMEM  = {
  swingL1, swingL2, swingL3, swingL4
};
int swing_time_L[8] = {636, 441, 772, 702};

char BUFFER[10];
// --------------------------------- SOUNDS ---------------------------------

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(100);  // set brightness
  setAll(0, 0, 0);  // turn off all LEDs

  Wire.begin();
  Serial.begin(9600);

  pinMode(BTN, INPUT_PULLUP);
  pinMode(IMU_GND, OUTPUT);
  pinMode(SD_GND, OUTPUT);
  pinMode(BTN_LED, OUTPUT);
  digitalWrite(IMU_GND, LOW);
  digitalWrite(SD_GND, LOW);
  digitalWrite(BTN_LED, HIGH);

  randomSeed(analogRead(2));  // random seed for random number generation

  accelgyro.initialize();  // IMU initialization
  accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_16);
  accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_250);

  if (DEBUG) {
    Serial.begin(115200);
    if (accelgyro.testConnection()) {
      Serial.println(F("MPU6050 connection successful"));
    } else {
      Serial.println(F("MPU6050 connection failed"));
    }
  }

  tmrpcm.speakerPin = 9;
  tmrpcm.setVolume(5);
  tmrpcm.quality(1);
if (DEBUG) {
    if (SD.begin(8)) Serial.println(F("SD OK"));
    else Serial.println(F("SD fail"));
  } else {
    SD.begin(8);
  }

  if ((EEPROM.read(0) >= 0) && (EEPROM.read(0) <= 5)) {
    nowColor = EEPROM.read(0);
    HUMmode = EEPROM.read(1);
  } else {
    EEPROM.write(0, 0);
    EEPROM.write(1, 0);
    nowColor = 0;
  }

  setColor(nowColor);
   FastLED.setBrightness(BRIGHTNESS); // Set initial color based on EEPROM or default
}

void loop() {
  randomBlink();
  getFreq();
  on_off_sound();
  btnTick();
  strikeTick();
  swingTick();
}

void btnTick() {
  btnState = !digitalRead(BTN);
  if (btnState && !btn_flag) {
    btn_flag = true;
    btn_counter++;
    btn_timer = millis();
  }

  if (!btnState && btn_flag) {
    btn_flag = false;
    hold_flag = false;
  }

  if (btn_flag && btnState && (millis() - btn_timer > BTN_TIMEOUT) && !hold_flag) {
    ls_chg_state = true;
    hold_flag = true;
    btn_counter = 0;
  }

  if ((millis() - btn_timer > BTN_TIMEOUT) && (btn_counter != 0)) {
    if (ls_state) {
      if (btn_counter == 3) {
        nowColor++;
        if (nowColor >= 6) nowColor = 0;
        setColor(nowColor);
        setAll(red, green, blue);
        eeprom_flag = true;
      }
      if (btn_counter == 5) {
        HUMmode = !HUMmode;
         if (HUMmode) {
          noToneAC();                       // вырубить трещалку
          tmrpcm.play("HUM.wav");           // грать гудение
        } else {
          tmrpcm.disable();                 // выключаем звук
          toneAC(freq_f);                   // трещать
        }
        eeprom_flag = true;
      }
    }
    btn_counter = 0;
  }

  if (eeprom_flag) {       //$$$$$$$$$$$$$$$$$$$$$$$$
    EEPROM.write(0, nowColor);
    EEPROM.write(1, HUMmode);
    eeprom_flag = false;
  }
}

void on_off_sound() {
  if (ls_chg_state) {
    if (!ls_state) {
      tmrpcm.play("ON.wav");
      delay(200);
      light_up();
      delay(200);   
      bzzz_flag = true;
      ls_state = true;
      if (HUMmode) {
     noToneAC();                  // вырубить трещалку
          tmrpcm.play("HUM.wav");      // гудеть
        } else {
          tmrpcm.disable();            // выключаем звук
          toneAC(freq_f);              // трещать
        }
      } else {
        noToneAC();                    // вырубить трещалку
      bzzz_flag = 0;                 // запретить включение трещалки
      tmrpcm.play("OFF.wav");        // воспроизвести звук выключения
      delay(300);                    // ждём воспроизведение
      light_down();                  // лента выключается
      delay(300);                    // ждём воспроизведение
      tmrpcm.disable();              // выключаем звук
      if (DEBUG) Serial.println(F("SABER OFF"));
      ls_state = false;              // запомнить, что меч выключен
      if (eeprom_flag) {             // если была смена цвета
        eeprom_flag = 0;
        EEPROM.write(0, nowColor);   // записать выбранный цвет в память
        EEPROM.write(1, HUMmode);
    }
      }
    ls_chg_state = false;
  }
   if (((millis() - humTimer) > 9000) && bzzz_flag && HUMmode) {   // если настало время трещать и разрешено трещать
    tmrpcm.play("HUM.wav");
    humTimer = millis();                                          // сбросить таймер
    swing_flag = 1;
    strike_flag = 0;

   }
  long delta = millis() - bzzTimer;
  if ((delta > 3) && bzzz_flag && !HUMmode) {   // если настало время трещать и разрешено трещать
    if (strike_flag) {
      tmrpcm.disable();                             // выключить звук
      strike_flag = 0;
    }
    toneAC(freq_f);                                 // трещать
    bzzTimer = millis(); 
  }
}

void randomBlink() {
  if (Blink_ALLOW && ls_state && (millis() - Blink_timer > Blink_DELAY)) {
    Blink_timer = millis();
    blinkOffset = blinkOffset * k + random(-Blink_AMPL, Blink_AMPL) * (1 - k);
    if (nowColor == 0) blinkOffset = constrain(blinkOffset, -15, 5);
    redOffset = constrain(red + blinkOffset, 0, 255);
    greenOffset = constrain(green + blinkOffset, 0, 255);
    blueOffset = constrain(blue + blinkOffset, 0, 255);
    setAll(redOffset, greenOffset, blueOffset);
  }
}
void strikeTick() {
  if ((ACC > STRIKE_THR) && (ACC < STRIKE_S_THR)) {      // если ускорение превысило порог
    if (!HUMmode) noToneAC();                        // выключить трещалку
    nowNumber = random(8);             // взять случайное число
    // читаем название трека из PROGMEM
    strcpy_P(BUFFER, (char*)pgm_read_word(&(strikes_short[nowNumber])));
    tmrpcm.play(BUFFER);               // воспроизвести звук удара
    strike_flash();
    if (!HUMmode)
      bzzTimer = millis() + strike_s_time[nowNumber] - FLASH_DELAY;
    else
      humTimer = millis() - 9000 + strike_s_time[nowNumber] - FLASH_DELAY;
    strike_flag = 1;
  }
  if (ACC >= STRIKE_S_THR) {           // если ускорение превысило порог
    if (!HUMmode) noToneAC();                        // выключить трещалку
    nowNumber = random(8);             // взять случайное число
    // читаем название трека из PROGMEM
    strcpy_P(BUFFER, (char*)pgm_read_word(&(strikes[nowNumber])));
    tmrpcm.play(BUFFER);               // воспроизвести звук удара
    strike_flash();
    if (!HUMmode)
      bzzTimer = millis() + strike_time[nowNumber] - FLASH_DELAY;
    else
      humTimer = millis() - 9000 + strike_time[nowNumber] - FLASH_DELAY;
    strike_flag = 1;
  }
}
void swingTick() {
    if (GYR > 80 && (millis() - swing_timeout > 100) && HUMmode) {
    swing_timeout = millis();
    if (((millis() - swing_timer) > SWING_TIMEOUT) && swing_flag && !strike_flag) {
      if (GYR >= SWING_THR) {      // если ускорение превысило порог
        nowNumber = random(5);             // взять случайное число
        // читаем название трека из PROGMEM
        strcpy_P(BUFFER, (char*)pgm_read_word(&(swings[nowNumber])));
        tmrpcm.play(BUFFER);               // воспроизвести звук взмаха
        humTimer = millis() - 9000 + swing_time[nowNumber];
        swing_flag = 0;
        swing_timer = millis();
        swing_allow = 0;
      }
      if ((GYR > SWING_L_THR) && (GYR < SWING_THR)) {
        nowNumber = random(5);             // взять случайное число
        // читаем название трека из PROGMEM
        strcpy_P(BUFFER, (char*)pgm_read_word(&(swings_L[nowNumber])));
        tmrpcm.play(BUFFER);               // воспроизвести звук взмаха
        humTimer = millis() - 9000 + swing_time_L[nowNumber];
        swing_flag = 0;
        swing_timer = millis();
        swing_allow = 0;
      }
    }
  }
}


void getFreq() {
  if (ls_state && (millis() - mpuTimer > 500)) {
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    gyroX = abs(gx / 100);
    gyroY = abs(gy / 100);
    gyroZ = abs(gz / 100);
    accelX = abs(ax / 100);
    accelY = abs(ay / 100);
    accelZ = abs(az / 100);

    ACC = sq((long)accelX) + sq((long)accelY) + sq((long)accelZ);
    ACC = sqrt(ACC);
    GYR = sq((long)gyroX) + sq((long)gyroY) + sq((long)gyroZ);
    GYR = sqrt((long)GYR); //$$$$$$$
    COMPL = ACC + GYR;

    freq = (long)COMPL * COMPL / 1500;
    freq = constrain(freq, 18, 300);
    freq_f = freq * k + freq_f * (1 - k);

    mpuTimer = micros();
  }
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
  leds[Pixel].r = red;
  leds[Pixel].g = green;
  leds[Pixel].b = blue;
}

void setAll(byte red, byte green, byte blue) {
  for (int i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
  }
  FastLED.show();
}

void light_up() {
  for (char i = 0; i <= (NUM_LEDS / 2 - 1); i++) {
    setPixel(i, red, green, blue);
    setPixel((NUM_LEDS - 1 - i), red, green, blue);
    FastLED.show();
    delay(25);
  }
}

void light_down() {
  for (char i = (NUM_LEDS / 2 - 1); i >= 0; i--) {
    setPixel(i, 0, 0, 0);
    setPixel((NUM_LEDS - 1 - i), 0, 0, 0);
    FastLED.show();
    delay(25);
  }
}



void strike_flash() {
  setAll(255, 255, 255);
  delay(FLASH_DELAY);
  setAll(red, green, blue);
}

void setColor(byte color) {
  switch (color) {
    case 0: red = 255; green = 0; blue = 0; break;
    case 1: red = 0; green = 255; blue = 0; break;
    case 2: red = 0; green = 0; blue = 255; break;
    case 3: red = 255; green = 0; blue = 255; break;
    case 4: red = 255; green = 255; blue = 0; break;
    case 5: red = 0; green = 255; blue = 255; break;
  }
}

Kupiłem już moduł DFRobot MAX98357A, i chce go zaadoptować zamiast  porzedniego
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości