#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// Определение пинов для TFT дисплея ILI9341
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
#define TFT_MOSI 11
#define TFT_SCLK 13
#define TFT_MISO 12
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// Константы
const int BUTTON_PIN = 2;
const int JOYSTICK_X_PIN = A0;
const int JOYSTICK_Y_PIN = A1;
const int SIGNAL_PIN = A5;
const int BUFFER_SIZE = 500; // Размер буфера для хранения 5 секунд при частоте 100 Гц
const int DISPLAY_WIDTH = 320;
const int DISPLAY_HEIGHT = 240;
// Переменные
volatile boolean recording = false;
boolean buttonPressed = false;
unsigned int dataBuffer[BUFFER_SIZE];
unsigned int bufferIndex = 0;
unsigned long lastSampleTime = 0;
unsigned int sampleInterval = 10; // 10 мс = 100 Гц
float timeScale = 2.0; // Масштаб времени (мс/пиксель)
int timeOffset = 0; // Смещение по времени
int prevX = 0, prevY = 0;
void setup() {
// Инициализация дисплея
tft.begin();
tft.setRotation(3); // Альбомная ориентация
tft.fillScreen(ILI9341_BLACK);
// Настройка пинов
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);
// Начальный экран
drawUI();
}
void loop() {
if (recording) {
// Запись данных
if (millis() - lastSampleTime >= sampleInterval) {
lastSampleTime = millis();
if (bufferIndex < BUFFER_SIZE) {
dataBuffer[bufferIndex] = analogRead(SIGNAL_PIN);
bufferIndex++;
} else {
// Буфер заполнен, сдвигаем данные
for (int i = 0; i < BUFFER_SIZE - 1; i++) {
dataBuffer[i] = dataBuffer[i + 1];
}
dataBuffer[BUFFER_SIZE - 1] = analogRead(SIGNAL_PIN);
}
}
}
// Обработка джойстика
handleJoystick();
// Отрисовка сигнала
drawSignal();
// Обработка нажатия кнопки
if (buttonPressed) {
buttonPressed = false;
if (!recording) {
// Начинаем новую запись
bufferIndex = 0;
recording = true;
timeOffset = 0;
} else {
// Останавливаем запись
recording = false;
}
drawUI();
}
}
void buttonISR() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > 200) {
buttonPressed = true;
}
lastInterruptTime = interruptTime;
}
void handleJoystick() {
int xValue = analogRead(JOYSTICK_X_PIN);
int yValue = analogRead(JOYSTICK_Y_PIN);
// Изменение масштаба по оси X
if (xValue < 300) {
timeScale *= 0.98; // Уменьшаем масштаб
} else if (xValue > 700) {
timeScale *= 1.02; // Увеличиваем масштаб
}
// Ограничение масштаба
timeScale = constrain(timeScale, 0.5, 50.0);
// Изменение смещения по оси Y
if (yValue < 300) {
timeOffset -= 5;
} else if (yValue > 700) {
timeOffset += 5;
}
// Ограничение смещения
timeOffset = constrain(timeOffset, 0, max(0, (int)(bufferIndex - DISPLAY_WIDTH / timeScale)));
}
void drawSignal() {
if (bufferIndex == 0) return;
tft.fillRect(0, 20, DISPLAY_WIDTH, DISPLAY_HEIGHT - 40, ILI9341_BLACK);
int startIndex = timeOffset;
int endIndex = min(startIndex + (int)(DISPLAY_WIDTH * timeScale), bufferIndex);
prevX = 0;
prevY = map(dataBuffer[startIndex], 0, 1023, DISPLAY_HEIGHT - 21, 21);
for (int x = 0; x < DISPLAY_WIDTH; x++) {
int bufferPos = startIndex + (int)(x * timeScale);
if (bufferPos >= endIndex) break;
int y = map(dataBuffer[bufferPos], 0, 1023, DISPLAY_HEIGHT - 21, 21);
// Рисуем линию от предыдущей точки к текущей
if (x > 0) {
tft.drawLine(x - 1, prevY, x, y, ILI9341_GREEN);
}
prevX = x;
prevY = y;
}
// Обновление информации о масштабе
tft.fillRect(0, 0, DISPLAY_WIDTH, 20, ILI9341_BLACK);
tft.fillRect(0, DISPLAY_HEIGHT - 20, DISPLAY_WIDTH, 20, ILI9341_BLACK);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
if (recording) {
tft.print("REC ");
} else {
tft.print("STOP");
}
tft.print(" Scale: ");
tft.print(timeScale * DISPLAY_WIDTH / 10.0, 1);
tft.print(" ms");
// Отображение положения прокрутки
if (bufferIndex > DISPLAY_WIDTH / timeScale) {
float scrollPos = (float)timeOffset / (bufferIndex - DISPLAY_WIDTH / timeScale);
tft.setCursor(0, DISPLAY_HEIGHT - 20);
tft.print("Pos: ");
tft.print(scrollPos * 100, 0);
tft.print("%");
}
}
void drawUI() {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
if (recording) {
tft.println("Recording...");
} else {
tft.println("Press button to start");
}
// Рамка для графика
tft.drawRect(0, 20, DISPLAY_WIDTH, DISPLAY_HEIGHT - 40, ILI9341_WHITE);
// Горизонтальные линии для масштаба
for (int y = 20; y < DISPLAY_HEIGHT - 20; y += (DISPLAY_HEIGHT - 60) / 4) {
tft.drawFastHLine(0, y, 10, ILI9341_WHITE);
}
}