#include #include #include #include "pico/multicore.h" #include #define SAMPLEPERIODUS 200UL // Okres muTimer Decay = muTimer(); muTimer Decay2 = muTimer(); bool decay_2_in; bool decay_2_out; const unsigned long BPM_INTERVAL = 60000; // 1 minuta unsigned long beatCount = 0; unsigned long lastBeatTime = 0; float bpm = 0; const int HISTORY_SIZE = 5; // Liczba ostatnich uderzen do analizy unsigned long beatIntervals[HISTORY_SIZE] = {0}; int beatIndex = 0; bool stable = false; // Flaga czy sygnal ok //beat led clk const int LED_PIN = 2; unsigned long beatInterval; // Odstęp trig/trig w ms bool BPM_CLK_LED; muTimer LEDDecay = muTimer(); muTimer LEDBPM = muTimer(); //vu meter const int NUM_BARS = 10; // Liczba VU float peakLevel = 0; // Przechowuje (peak hold) unsigned long peakHoldTime = 500; // Podtrzymanie poziomu (ms) unsigned long lastPeakUpdate = 0; // Ostatni peak hold unsigned long lastUpdateTime = 0; // Ostatni czas VU Smoothed myBPM; muTimer co_250ms = muTimer(); bool trig_co_250ms; muTimer co_100ms = muTimer(); bool trig_co_100ms; muTimer co_1s = muTimer(); bool trig_co_1s; #define serial_debug #define RS232_RX 5 #define RS232_TX 4 /* DEBUG PINY: DEBUG POM(SWDIO) / CZAR(GND) / ZOL(SCLK) RS232 CZAR(GND) / POM(TX) / ZOL(RX) */ //VARIABLES unsigned int running_counter; unsigned int running_counter_c1; bool beat_x ; /// // // *20 - 200Hz Single Pole Bandpass IIR Filter // float bassFilter(float sample) { static float xv[3] = {0.0f, 0.0f, 0.0f}; static float yv[3] = {0.0f, 0.0f, 0.0f}; xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = sample / 3.0f; //* regulacja pod sile sygnalu yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = (xv[2] - xv[0]) + (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]); return yv[2]; } // //* 10Hz Single Pole Lowpass IIR Filter // float envelopeFilter(float sample) { static float xv[2] = {0.0f, 0.0f}; static float yv[2] = {0.0f, 0.0f}; xv[0] = xv[1]; xv[1] = sample / 50.0f; yv[0] = yv[1]; yv[1] = (xv[0] + xv[1]) + (0.9875119299f * yv[0]); return yv[1]; } // //* 1.7 - 3.0Hz Single Pole Bandpass IIR Filter // float beatFilter(float sample) { static float xv[3] = {0.0f, 0.0f, 0.0f}; static float yv[3] = {0.0f, 0.0f, 0.0f}; xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = sample / 2.7f; yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = (xv[2] - xv[0]) + (-0.7169861741f * yv[0]) + (1.4453653501f * yv[1]); return yv[2]; } /// // SETUP NA RDZENIU 1 void setup1() { #ifdef serial_debug Serial2.println("1: Port Szeregowy Gotowy!"); #endif delay(1000); } // PETLA LOOP NA RZENIU 1 void loop1() { delay(500); running_counter_c1 = running_counter_c1 + 1; } ///funkcje unsigned long getAverageInterval() { unsigned long sum = 0; for (int i = 0; i < HISTORY_SIZE; i++) { sum += beatIntervals[i]; } return sum / HISTORY_SIZE; } bool isStable() { unsigned long avg = getAverageInterval(); for (int i = 0; i < HISTORY_SIZE; i++) { if (beatIntervals[i] == 0) return false; // Nie mamy jeszcze.... if (abs((long)beatIntervals[i] - (long)avg) > 100) return false; // Maksymalne odchylenie... } return true; } //SETUP -- SETUP -- SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP void setup() { //pin i/o pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_PIN, OUTPUT); //adc res analogReadResolution(12); //Serial_DEBUG #ifdef serial_debug Serial2.setTX(RS232_TX); Serial2.setRX(RS232_RX); Serial2.begin(115200); Serial2.println("0: Port Szeregowy Gotowy!"); #endif //timery Decay.delayOffTrigger(1, 100); LEDDecay.delayOffTrigger(1, 50); co_100ms.cycleTrigger(100); co_250ms.cycleTrigger(250); co_1s.cycleTrigger(1000); //filtry myBPM.begin(SMOOTHED_AVERAGE, 50); //wdt watchdog_enable(8000, false); }//setup end. //SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP --SETUP -- SETUP //LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP void loop() { /// static unsigned int sampleCounter = 0; static unsigned long lastSampleTime = 0; unsigned long currentTime = micros(); // Co: 5000Hz (co 200 µs) if (currentTime - lastSampleTime < SAMPLEPERIODUS) return; lastSampleTime = currentTime; // Odczyt A0 // Offset: dla 12-bit ADC (0-4095) ~ 2048 float sample = (float)analogRead(A0) - 2048.0f; // Basofiltr float value = bassFilter(sample); if (value < 0) value = -value; // Obwiednia float envelope = envelopeFilter(value); sampleCounter++; // Co 200 (~25Hz) wykonujemy filtr beat <-> ustawiamy stan LED if (sampleCounter >= 200) { float beat = beatFilter(envelope); // Odczyt A1 do ustawienia progu float thresh = 0.02f * (float)analogRead(A1); // Jeżeli wykryty beat > prog, LED bool beat_detect; if (beat > thresh) beat_detect = true; //digitalWrite(LED_BUILTIN, HIGH); else //digitalWrite(LED_BUILTIN, LOW); beat_detect = false; sampleCounter = 0; beat_x = Decay.delayOff(beat_detect, 100); } digitalWrite(LED_BUILTIN, beat_x); /// static bool lastState = false; if (beat_x && !lastState) { // Wykrycie zbocza narastajacego unsigned long currentTime = millis(); if (lastBeatTime > 0) { unsigned long interval = currentTime - lastBeatTime; beatIntervals[beatIndex] = interval; beatIndex = (beatIndex + 1) % HISTORY_SIZE; if (isStable()) { bpm = 60000.0 / getAverageInterval(); stable = true; } else { stable = false; } } lastBeatTime = currentTime; } lastState = beat_x; /// /// /// beatInterval = 60000 / bpm; //LEDDecay.cycleTrigger(beatInterval); if(beat_x == true){ BPM_CLK_LED = LEDBPM.delayOff(LEDDecay.cycleTrigger(beatInterval), 10); } if(beat_x == false){ BPM_CLK_LED = false; } if (beat_x == true and BPM_CLK_LED == true){ decay_2_in = true; } else{ decay_2_in = false; } decay_2_out = Decay2.delayOff(decay_2_in, 100); if(beat_x == false){ decay_2_out = false; } digitalWrite(LED_PIN, decay_2_out); ///vu meter // Aktualizacja co 50ms bez delay() if (currentTime - lastUpdateTime >= 50) { lastUpdateTime = currentTime; // 1. Odczytaj int rawValue = analogRead(A0); // 2. Mapuj float level = map(rawValue, 2000, 2250, 0, NUM_BARS); // 3. Peak Hold if (level > peakLevel) { peakLevel = level; lastPeakUpdate = currentTime; // Zapisujemy czas aktualizacji } // 4. Sprawdzam > czas peak hold if (currentTime - lastPeakUpdate > peakHoldTime) { peakLevel -= 0.2; // Powolne opadanie peak hold if (peakLevel < 0) peakLevel = 0; // Antyminus } // 5. Wyświetlenie VU Serial.print("VU: ["); for (int i = 0; i < NUM_BARS; i++) { if (i < level) { Serial.print("#"); // Aktualny poziom } else { Serial.print(" "); // Puste miejsca } } // 6. Wyświetlenie Peak if (peakLevel >= 1) { int peakPos = min(NUM_BARS - 1, (int)peakLevel); if (peakPos >= (int)level) { Serial.print(" *"); // Jak poza tunning } } Serial.println("]"); // Japierdole z tym.... } //co 100ms if(co_100ms.cycleTrigger(100)){ trig_co_100ms = not(trig_co_100ms); // digitalWrite(LED_BUILTIN, trig_co_100ms); myBPM.add(bpm); }//co 100ms end. //co 1s if(co_1s.cycleTrigger(1000)){ trig_co_1s = not(trig_co_1s); running_counter = running_counter + 1; //SERIAL DEBUG SERIAL DEBUG SERIAL DEBUG SERIAL DEBUG #ifdef serial_debug //Serial2.print("0:running counter: "); //Serial2.print(running_counter); //Serial2.print("\n"); //Serial2.print("1:running counter: "); //Serial2.print(running_counter_c1); //Serial2.print("\n"); Serial2.print("Treshold: "); Serial2.print(analogRead(A1)); Serial2.print("\n"); Serial2.print("Signal: "); Serial2.print(analogRead(A0)); Serial2.print("\n"); Serial2.print("BPM: "); Serial2.print(myBPM.get()); Serial2.print(" STABLE: "); Serial2.print(stable); Serial2.print("\n"); Serial2.print("INTERVAL: "); Serial2.print(beatInterval); Serial2.print("\n"); #endif }//co 1s end. //WDT ! WDT ! WDT ! WDT ! WDT ! WDT ! WDT ! WDT ! watchdog_update(); }//loop end. //LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP