#include #include TFT_eSPI tft = TFT_eSPI(); TFT_eSprite ds = TFT_eSprite(&tft); #define SAMPLES 1024 #define SAMPLE_RATE 200000 uint16_t buffer[SAMPLES]; uint32_t delays[] = {1, 2, 4, 8, 16, 32}; const char* labels[] = {"MAX", "x2", "x4", "x8", "x16", "x32"}; int mode = 0; uint32_t lastUpdate = 0; float smooth_f = 0; void setup_i2s() { i2s_driver_uninstall(I2S_NUM_0); i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), .sample_rate = SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, .communication_format = I2S_COMM_FORMAT_I2S_MSB, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, .dma_buf_len = 512, .use_apll = false }; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_7); i2s_adc_enable(I2S_NUM_0); } void touch_calibrate() { uint16_t calData[5]; tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE); tft.drawCentreString("TOUCH CORNERS", 160, 100, 2); tft.calibrateTouch(calData, TFT_GREEN, TFT_BLACK, 15); tft.setTouch(calData); tft.fillScreen(TFT_BLACK); } void setup() { pinMode(27, OUTPUT); digitalWrite(27, HIGH); pinMode(21, OUTPUT); digitalWrite(21, HIGH); tft.init(); tft.setRotation(1); tft.invertDisplay(false); touch_calibrate(); ds.setColorDepth(8); ds.createSprite(320, 160); setup_i2s(); } void loop() { uint16_t tx, ty; if (tft.getTouch(&tx, &ty)) { if (ty > 190) { mode = tx / 53; if (mode > 5) mode = 5; delay(150); } } size_t bytes_read = 0; uint16_t raw_buf[SAMPLES * 2]; i2s_read(I2S_NUM_0, (void*)raw_buf, SAMPLES * 4, &bytes_read, portMAX_DELAY); int v_max = 0, v_min = 4096; for (int i = 0; i < SAMPLES; i++) { buffer[i] = raw_buf[i * 2] & 0x0FFF; if (buffer[i] > v_max) v_max = buffer[i]; if (buffer[i] < v_min) v_min = buffer[i]; } int amp = v_max - v_min; float mid = (v_max + v_min) / 2.0; int hyst = amp / 6; if (hyst < 60) hyst = 60; int first = -1, last = -1, p_count = 0; bool state = false; if (amp > 100) { for (int i = 1; i < SAMPLES; i++) { if (!state && buffer[i-1] < mid && buffer[i] >= mid) { if (first == -1) first = i; last = i; p_count++; state = true; } else if (state && buffer[i] < mid - hyst) state = false; } } float inst_f = 0; if (p_count > 1 && (last - first) > 0) { inst_f = (((float)(p_count - 1) * SAMPLE_RATE) / (float)(last - first) / 2.0); // --- ТОЧЕЧНАЯ КОРРЕКЦИЯ ПО ЗАПРОСУ --- if (inst_f < 500) inst_f -= 1.0; // До 500 Гц убираем 1 Гц else if (inst_f < 1000) inst_f -= 2.0; // После 500 Гц убираем 2 Гц else inst_f -= 20.0; // У Килогерц отнимаем 0.02 кГц (20 Гц) if (inst_f < 0) inst_f = 0; } if (inst_f > 0) { float k = (inst_f > 5000) ? 0.3 : 0.1; smooth_f = smooth_f * (1.0 - k) + inst_f * k; } else smooth_f = 0; int trig = 0; for (int i = 1; i < SAMPLES / 2; i++) { if (buffer[i-1] < mid && buffer[i] >= mid) { trig = i; break; } } ds.fillSprite(TFT_BLACK); for(int x=0; x<=320; x+=40) ds.drawFastVLine(x, 0, 160, 0x2104); for(int y=0; y<=160; y+=40) ds.drawFastHLine(0, y, 320, 0x2104); int window = (SAMPLES / 2) / delays[mode]; int py = map(buffer[trig], v_min, v_max, 155, 5); for (int i = 1; i < 320; i++) { int idx = trig + (i * window / 320); if (idx >= SAMPLES) break; int cy = map(buffer[idx], v_min, v_max, 155, 5); ds.drawLine(i - 1, py, i, cy, TFT_GREEN); py = cy; } ds.pushSprite(0, 30); if (millis() - lastUpdate > 300) { tft.fillRect(0, 0, 320, 30, TFT_BLACK); tft.setTextColor(TFT_YELLOW, TFT_BLACK); tft.setTextSize(2); tft.setCursor(5, 5); float vpp = amp * 3.3 / 4095.0; if (amp > 80) { if (smooth_f >= 1000) tft.printf("%.2fV %.2fkHz", vpp, smooth_f/1000.0); else tft.printf("%.2fV %.0fHz", vpp, smooth_f); } else tft.print("0.00V 0.0Hz"); tft.setTextSize(1); for (int i = 0; i < 6; i++) { tft.drawRect(i * 53, 195, 52, 44, (i == mode) ? TFT_YELLOW : 0x7BEF); tft.setTextColor((i == mode) ? TFT_YELLOW : 0x7BEF); tft.drawCentreString(labels[i], i * 53 + 26, 210, 1); } lastUpdate = millis(); } }