//! LiquidCrystal_PCF8574 library by Matthias Hertel
// # https://wokwi.com/projects/418239231786728449
// # 와이파이 연결은 추후에 하니 나중에 코드 만지기로 할것
// # 링버퍼 방식 공부하기
// This example shows various featues of the library for LCD with 16 chars and 2 lines.
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
const int I2C_ADDR = 0x27;
const int LCD_COLUNMS = 20;
const int LCD_ROWS = 4;
LiquidCrystal_PCF8574 lcd(I2C_ADDR); // set the LCD address to 0x27 for a 16(20) chars and 2(4) line display
int analogCurrentValue = 0;
int analogMaxValue = 0;
int analogMinValue = 0;
int analogAvgValue = 0;
int analogResolution = 0;
long analogPeakGapTime = 0;
int currentAnalogValue = 0;
int wifiSignal = 0;
const int limitArrayCount = 500;
static int rawData[limitArrayCount];
static unsigned long rawTimes[limitArrayCount];
static int readIndex = 0;
const int highValueLimit = 100; // 500이상 값을 저장할 배열 크기
static int highData[highValueLimit];
static unsigned long highTimes[highValueLimit];
static int highIndex = 0;
static unsigned long previousMillis = 0;
//! 모의 데이타 시작
// 모의 데이터 관련 변수 추가
const int MOCK_DATA_SIZE = 200;
int mockData[MOCK_DATA_SIZE];
int mockDataIndex = 0;
void generateMockData()
{
// 기본값은 0~100 사이의 낮은 값
for (int i = 0; i < MOCK_DATA_SIZE; i++)
{
mockData[i] = random(0, 100);
}
// 10개의 높은 값(500~1000)을 랜덤한 위치에 삽입
for (int i = 0; i < 10; i++)
{
int randomPos = random(0, MOCK_DATA_SIZE);
mockData[randomPos] = random(500, 1000);
}
}
int getMockAnalogValue()
{
int value = mockData[mockDataIndex];
mockDataIndex = (mockDataIndex + 1) % MOCK_DATA_SIZE;
return value;
}
// # 모의 데이타 끝
void setup_20x4_LCD()
{
int error;
Serial.println("LCD...");
Serial.println("Probing for PCF8574 on address 0x27...");
// See http://playground.arduino.cc/Main/I2cScanner how to test for a I2C device.
Wire.begin();
Wire.beginTransmission(I2C_ADDR);
error = Wire.endTransmission();
Serial.print("Error: ");
Serial.print(error);
if (error == 0)
{
Serial.println(": LCD found.");
lcd.begin(LCD_COLUNMS, LCD_ROWS); // initialize the lcd
}
else
{
Serial.println(": LCD not found.");
}
}
void loop_mainPage_LCD()
{
int cValue = currentAnalogValue;
int maxValue = analogMaxValue;
int minValue = analogMinValue;
int avgValue = analogAvgValue;
int resolution = analogResolution;
long peakGapTime = analogPeakGapTime;
const int backLightness = 150;
// 현재값을 0,0에 출력
lcd.setBacklight(backLightness);
lcd.setCursor(0, 0);
lcd.print("C.V: ");
lcd.print(" "); // 이전 값을 지우기 위해 공백으로 덮어쓰기
lcd.setCursor(5, 0);
lcd.print(cValue);
// 최대값을 11,0에 출력
lcd.setCursor(11, 0);
lcd.print("MAX: ");
lcd.print(" ");
lcd.setCursor(16, 0);
lcd.print(maxValue);
// 최소값을 11,1에 출력
lcd.setCursor(11, 1);
lcd.print("MIN: ");
lcd.print(" ");
lcd.setCursor(16, 1);
lcd.print(minValue);
// 평균값을 0,1에 출력
lcd.setCursor(0, 1);
lcd.print("AVG: ");
lcd.print(" ");
lcd.setCursor(5, 1);
lcd.print(avgValue);
// 해상도를 0,3에 출력
lcd.setCursor(0, 3);
lcd.print("RES: ");
lcd.print(" ");
lcd.setCursor(5, 3);
lcd.print(resolution);
// 피크 갭 타임을 0,2에 출력
lcd.setCursor(0, 2);
lcd.print("PeakGap: ");
lcd.print(" ");
lcd.setCursor(9, 2);
lcd.print(peakGapTime);
// 와이파이 수신상태 출력
lcd.setCursor(13, 3);
lcd.print("WIFI:");
lcd.setCursor(19, 3);
lcd.print(wifiSignal);
}
void readRawAnalogValue()
{
// 링 버퍼 방식으로 rawData, rawTimes를 덮어씀
int pos = readIndex % limitArrayCount;
int val = getMockAnalogValue(); // analogRead(A0) 대신 모의 데이터 사용
rawData[pos] = val;
rawTimes[pos] = millis();
// 500 이상이면 별도 배열에 저장
if (val >= 500)
{
if (highIndex < highValueLimit)
{
highData[highIndex] = val;
highTimes[highIndex] = rawTimes[pos];
highIndex++;
}
else
{
Serial.println("High data array is full!");
}
}
readIndex++;
currentAnalogValue = val;
}
void readHighAnalogValue()
{
int maxVal = 0;
// 실제 기록된 데이터 개수를 구함
int count = (readIndex < limitArrayCount) ? readIndex : limitArrayCount;
for (int i = 0; i < count; i++)
{
int pos = i % limitArrayCount;
if (rawData[pos] > maxVal)
{
maxVal = rawData[pos];
}
}
analogMaxValue = maxVal;
}
void readLowAnalogValue()
{
int minVal = 1023;
int count = (readIndex < limitArrayCount) ? readIndex : limitArrayCount;
for (int i = 0; i < count; i++)
{
int pos = i % limitArrayCount;
if (rawData[pos] < minVal)
{
minVal = rawData[pos];
}
}
analogMinValue = minVal;
}
void averageAnalogValue() // 10회 측정한 값의 평균값 계산
{
const long interval = 10;
if (millis() - previousMillis >= interval)
{
previousMillis = millis();
int sum = 0;
for (int i = 0; i < 10; i++)
{
sum += getMockAnalogValue(); // analogRead(A0) 대신 모의 데이터 사용
}
analogAvgValue = sum / 10;
}
}
void printIntervals()
{
static int lastPrintedHighIndex = 0;
// 새로 추가된 고값들에 대해서만 간격 계산
for (int i = lastPrintedHighIndex + 1; i < highIndex; i++)
{
// 유효한 인덱스인지 확인
if (i > 0 && highTimes[i] > 0 && highTimes[i-1] > 0)
{
unsigned long interval = highTimes[i] - highTimes[i - 1];
// 비정상적으로 큰 간격은 무시
if (interval < 60000) // 1분 이내의 간격만 고려
{
Serial.print("High Interval: ");
Serial.print(interval);
Serial.println("ms");
analogPeakGapTime = interval; // LCD 표시용
}
}
}
if (highIndex > 0)
{
lastPrintedHighIndex = highIndex - 1;
}
}
void debugPrintAnalogValus()
{
// 기존 디버그 정보 출력
Serial.print("Cur: ");
Serial.print(currentAnalogValue);
Serial.print(" Max: ");
Serial.print(analogMaxValue);
Serial.print(" Min: ");
Serial.print(analogMinValue);
Serial.print(" Avg: ");
Serial.println(analogAvgValue);
// 고값 배열 정보 출력
if (highIndex > 1) // 최소 2개 이상의 값이 있을 때
{
Serial.print("High Values Time Gaps -> ");
for (int i = 1; i < highIndex; i++)
{
unsigned long gap = highTimes[i] - highTimes[i - 1];
Serial.print(gap);
Serial.print("ms ");
}
Serial.println();
}
}
// void readWifiRSSI() // 와이파이 신호세기 측정 , 테스트 완료
// {
// if (WiFi.status() == WL_CONNECTED)
// {
// wifiSignal = WiFi.RSSI();
// }
// else
// {
// wifiSignal = 0;
// }
// }
// # setup
void setup()
{
Serial.begin(9600);
// wait on Serial to be available on Leonardo , R4 MINIMA , WIFI
while (!Serial)
;
randomSeed(analogRead(A0)); // 실제 아날로그 값으로 난수 시드 설정
generateMockData(); // 모의 데이터 생성
setup_20x4_LCD();
} // end of setup()
// # loop
void loop()
{
loop_mainPage_LCD();
// readWifiRSSI();
readRawAnalogValue();
readHighAnalogValue();
readLowAnalogValue();
averageAnalogValue();
printIntervals();
debugPrintAnalogValus();
} // end of loop()
/*
if (show == 0)
{
lcd.setBacklight(255);
lcd.home();
lcd.clear();
lcd.print("Hello LCD");
delay(1000);
lcd.setBacklight(0);
delay(400);
lcd.setBacklight(255);
}
else if (show == 1)
{
lcd.clear();
lcd.print("Cursor On");
lcd.cursor();
}
else if (show == 2)
{
lcd.clear();
lcd.print("Cursor Blink");
lcd.blink();
}
else if (show == 3)
{
lcd.clear();
lcd.print("Cursor OFF");
lcd.noBlink();
lcd.noCursor();
}
else if (show == 4)
{
lcd.clear();
lcd.print("Display Off");
lcd.noDisplay();
}
else if (show == 5)
{
lcd.clear();
lcd.print("Display On");
lcd.display();
}
else if (show == 7)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("*** first line.");
lcd.setCursor(0, 1);
lcd.print("*** second line.");
}
else if (show == 8)
{
lcd.scrollDisplayLeft();
}
else if (show == 9)
{
lcd.scrollDisplayLeft();
}
else if (show == 10)
{
lcd.scrollDisplayLeft();
}
else if (show == 11)
{
lcd.scrollDisplayRight();
}
else if (show == 12)
{
lcd.clear();
lcd.print("write-");
}
else if (show == 13)
{
lcd.clear();
lcd.print("custom 1:<\01>");
lcd.setCursor(0, 1);
lcd.print("custom 2:<\02>");
}
else
{
lcd.print(show - 13);
} // if
delay(1400);
show = (show + 1) % 16;
*/