#include <SD.h> // SD 라이브러리 추가
#include <SPI.h> // SPI 라이브러리 추가
#include <LiquidCrystal_I2C.h> // I2C LCD 라이브러리 추가
File dataFile; // 데이터 파일 객체
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C LCD 객체 생성 (주소 0x27, 16x2)
unsigned long btnOnTime[8] = {0}; // 각 버튼의 ON 시간을 기록하는 배열
unsigned long btnOffTime[8] = {0}; // 각 버튼의 OFF 시간을 기록하는 배열
int count[8] = {0}; // 각 버튼의 ON 상태를 기록하기 위한 배열
int totalPressCount = 0; // 모든 버튼의 총 누적 카운트를 저장하는 변수
const int buttonPins[8] = {2, 3, 5, 6, 14, 15, 16, 17}; // 각 버튼의 입력 핀
const int buttonPin8 = 8; // 뒤로
const int buttonPin9 = 9; // 앞으로
const int ledPin = 7; // LED 핀
const int chipSelect = 4; // SD 카드 모듈의 CS 핀
// 이전에 버튼이 눌렸는지 여부를 추적하기 위한 변수들
unsigned long previousButtonPressTime = 0;
bool buttonPressed = false; // 버튼이 눌렸는지 여부를 저장하는 변수
int currentDataIndex = 0; // 현재 데이터 인덱스
// 전역 변수로 현재 표시된 줄의 위치를 저장합니다.
int currentLinePosition;
int lineCount;
void setup() {
Serial.begin(115200);
// 각 버튼의 입력 핀 설정
for (int i = 0; i < 8; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(buttonPin8, INPUT_PULLUP);
pinMode(buttonPin9, INPUT_PULLUP);
// SD 카드 모듈 초기화
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
return;
}
// LCD 초기화
lcd.init(); // 16x2 LCD 사용
lcd.backlight();
lcd.setCursor(0, 0);
lcd.clear();
lcd.print("Test press");
Serial.println("SD Card read Ready!");
delay(3000); // 짧은 딜레이
}
bool fileChange = false; // 파일 변경 여부를 저장하는 변수 (정적 변수로 변경)
void loop() {
bool anyButtonPressed = false;
for (int i = 0; i < 8; i++) {
logButtonState(buttonPins[i], i, btnOnTime, btnOffTime, i);
if (count[i] > 0) {
anyButtonPressed = true;
fileChange = true; // Linecheck 호출 후 파일 변경 플래그를 재설정합니다.
}
}
// 하나라도 버튼이 눌렸다면 LED를 켭니다.
digitalWrite(ledPin, anyButtonPressed ? HIGH : LOW);
// 8번 버튼을 누를 때는 이전 데이터 표시
if (digitalRead(buttonPin8) == LOW) {
delay(300); // 디바운스를 위한 짧은 딜레이
// 파일 변경 이벤트를 감지하고 Linecheck 함수를 호출합니다.
if (fileChange) {
Linecheck();
fileChange = false; // Linecheck 호출 후 파일 변경 플래그를 재설정합니다.
}
reverseDump();
}
// 9번 버튼을 누를 때는 다음 데이터 표시
if (digitalRead(buttonPin9) == LOW) {
delay(300); // 디바운스를 위한 짧은 딜레이
forwardDump();
}
}
void logButtonState(int buttonPin, int buttonIndex, unsigned long* onTime, unsigned long* offTime, int index) {
bool currentState = digitalRead(buttonPin);
static bool prevState[8] = {false}; // 각 버튼의 이전 상태를 추적하는 배열
if (currentState != prevState[index]) {
if (!currentState) { // 버튼이 눌린 경우
delay(150); // 디바운스를 위한 짧은 딜레이
if (!digitalRead(buttonPin)) { // 디바운스된 신호를 확인
count[index]++;
totalPressCount++; // 총 누적 카운트 증가
onTime[index] = millis()/1000; // 버튼이 눌린 시간 기록
// 버튼이 눌렸음을 시리얼 모니터에 출력
Serial.print(buttonIndex + 1);
Serial.print("on");
Serial.print(totalPressCount);
Serial.print(" ");
Serial.print(onTime[index]);
Serial.println("sec");
// SD 카드에 데이터 기록
writeDataToFile(buttonIndex + 1, "on", totalPressCount, onTime[index]);
// LCD에 데이터 표시
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(buttonIndex + 1);
lcd.print("on");
lcd.print(totalPressCount);
lcd.print(" ");
lcd.print(onTime[index]); // 밀리초를 초로 변환하여 출력
lcd.print("sec");
}
} else { // 버튼이 떼진 경우
delay(150); // 디바운스를 위한 짧은 딜레이
if (digitalRead(buttonPin)) { // 디바운스된 신호를 확인
offTime[index] = millis()/1000; // 버튼이 떼진 시간 기록
totalPressCount++; // 총 누적 카운트 증가
// 버튼이 떼졌음을 시리얼 모니터에 출력
Serial.print(buttonIndex + 1);
Serial.print("off");
Serial.print(totalPressCount);
Serial.print(" ");
Serial.print(offTime[index]);
Serial.println("sec");
count[index] = 0; // 버튼이 떼어지면 count를 초기화합니다.
// SD 카드에 데이터 기록
writeDataToFile(buttonIndex + 1, "Off", totalPressCount, offTime[index]);
// LCD에 데이터 표시
lcd.setCursor(0, 1);
lcd.print(buttonIndex + 1);
lcd.print("off");
lcd.print(totalPressCount);
lcd.print(" ");
lcd.print(offTime[index]); // 밀리초를 초로 변환하여 출력
lcd.print("sec");
}
}
prevState[index] = currentState;
}
}
void writeDataToFile(int buttonIndex, String state, int totalPressCount, unsigned long time) {
dataFile = SD.open("sw_8log1.txt", FILE_WRITE);
if (dataFile) {
dataFile.print(buttonIndex);
dataFile.print(state);
dataFile.print(totalPressCount);
dataFile.print(" ");
dataFile.print(time); // 밀리초를 초로 변환하여 기록
dataFile.println("sec");
dataFile.close();
} else {
Serial.println("파일 열기 실패");
}
}
// 역방향 덤프 함수
void reverseDump() {
Serial.println("reverseDump");
File dataFile = SD.open("sw_8log1.txt");
if (dataFile) {
// 파일의 크기를 저장
long fileSize = dataFile.size();
// 줄 바꿈 문자를 만났는지 여부를 나타내는 플래그
bool lineEnd = false;
// 파일의 끝으로 이동하여 역순으로 읽기 시작
dataFile.seek(fileSize - 1);
// 파일의 끝에서부터 한 줄씩 역순으로 읽어오기
String line = "";
int linesToSkip = lineCount - currentLinePosition; // 건너뛸 줄 수 설정
for (long i = fileSize - 1; i >= 0 && linesToSkip >= 0; i--) {
// 파일 포인터를 현재 위치로 이동
dataFile.seek(i);
// 현재 위치의 문자 읽기
char c = dataFile.read();
// 줄 바꿈 문자인 경우에는 플래그를 설정하고 다음 문자로 넘어감
if (c == '\n') {
lineEnd = true;
} else {
// 줄 바꿈 문자를 만나지 않은 경우 문자열에 문자를 추가
line = c + line;
}
// 줄 바꿈 문자를 만나면 현재 줄의 데이터를 출력하고 다음 줄로 넘어감
if (lineEnd) {
lineEnd = false;
linesToSkip--;
if (linesToSkip < 0) {
Serial.println(line);
lcd.setCursor(0, 1); // LCD 두 번째
lcd.print(line);
}
line = ""; // 줄 비우기
}
}
// currentLinePosition이 0보다 작아지면 0으로 설정합니다.
currentLinePosition--;
if (currentLinePosition < 0) currentLinePosition = 0;
// Serial.print("Current line position: ");
// Serial.println(currentLinePosition); // 현재 표시된 줄의 위치를 출력합니다.
dataFile.close();
}
}
void forwardDump() {
Serial.println("forwardDump");
File dataFile = SD.open("sw_8log1.txt");
if (dataFile) {
// 파일 내용을 한 줄씩 읽어서 출력합니다.
char c;
String line = "";
bool hasContent = false; // 출력할 내용이 있는지 여부를 나타내는 변수
// currentLinePosition 값에 해당하는 줄까지 건너뛰기
for (int i = 0; i < currentLinePosition + 1; ++i) {
// 줄 바꿈 문자가 나올 때까지 읽기
while (dataFile.available() && dataFile.read() != '\n');
}
// 파일의 내용을 한 줄씩 읽어서 출력합니다.
while (dataFile.available() && (c = dataFile.read()) != '\n') {
line += c;
hasContent = true;
}
if (hasContent) {
Serial.println(line); // 출력할 내용이 있는 경우에만 출력
lcd.setCursor(0, 1); // LCD 두 번째
lcd.print(line);
}
// 다음에 호출될 때를 위해 현재 표시된 줄의 위치를 업데이트합니다.
currentLinePosition++;
if (currentLinePosition >= lineCount) currentLinePosition = lineCount-1;
dataFile.close();
}
}
void Linecheck() {
// 파일을 열어서 줄 바꿈 문자의 개수를 세어 lineCount 값을 설정합니다.
File dataFile = SD.open("sw_8log1.txt");
if (dataFile) {
char c;
lineCount = 0; // lineCount 초기화
while (dataFile.available()) {
c = dataFile.read();
if (c == '\n') {
lineCount++;
}
}
Serial.print("lineCount");
Serial.println(lineCount);
dataFile.close();
} else {
Serial.println("파일 열기 실패");
}
}