#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#define hallSensorPin 2
#define buttonMenuPin 3
#define buttonCountUp 4
#define buttonCountDown 5
#define ledPin 6
#define buzzerPin 7
LiquidCrystal_I2C lcd(0x27, 20, 4); // Alamat I2C LCD 20x4
volatile unsigned int pulseCount = 0;
volatile unsigned long lastTime = 0;
float rpm = 0;
int rpmToDisplay = 0;
int teethCount = 1;
float calibration = 0.98;
unsigned long currentTime = 0;
unsigned int menuSelect = 0;
bool alarmState = false;
String alarmName[4] = {"OFF ","ON ","LED ","BUZZ"};
char buffer[10];
struct Settings {
int rpmLimit = 0;
int alarmSelect = 0;
};
Settings settings;
byte LT[8] = {
B00111, B01111, B11111, B11111, B11111, B11111, B11111, B11111
};
byte UB[8] = {
B11111, B11111, B11111, B00000, B00000, B00000, B00000, B00000
};
byte RT[8] = {
B11100, B11110, B11111, B11111, B11111, B11111, B11111, B11111
};
byte LL[8] = {
B11111, B11111, B11111, B11111, B11111, B11111, B01111, B00111
};
byte LB[8] = {
B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111
};
byte LR[8] = {
B11111, B11111, B11111, B11111, B11111, B11111, B11110, B11100
};
byte MB[8] = {
B11111, B11111, B11111, B00000, B00000, B00000, B11111, B11111
};
byte block[8] = {
B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111
};
// Fungsi untuk karakter besar
void custom0(int x){
lcd.setCursor(x,0); lcd.write(0); lcd.write(1); lcd.write(2);
lcd.setCursor(x,1); lcd.write(3); lcd.write(4); lcd.write(5);
}
void custom1(int x){
lcd.setCursor(x,0); lcd.write(1); lcd.write(2); lcd.print(" ");
lcd.setCursor(x,1); lcd.write(4); lcd.write(7); lcd.write(4);
}
void custom2(int x){
lcd.setCursor(x,0); lcd.write(6); lcd.write(6); lcd.write(2);
lcd.setCursor(x,1); lcd.write(3); lcd.write(4); lcd.write(4);
}
void custom3(int x){
lcd.setCursor(x,0); lcd.write(6); lcd.write(6); lcd.write(2);
lcd.setCursor(x,1); lcd.write(4); lcd.write(4); lcd.write(5);
}
void custom4(int x){
lcd.setCursor(x,0);lcd.write(3);lcd.write(4);lcd.write(7);
lcd.setCursor(x, 1);lcd.print(" ");lcd.print(" ");lcd.write(7);
}
void custom5(int x){
lcd.setCursor(x,0);lcd.write(3);lcd.write(6);lcd.write(6);
lcd.setCursor(x, 1);lcd.write(4);lcd.write(4);lcd.write(5);
}
void custom6(int x){
lcd.setCursor(x,0);lcd.write(0);lcd.write(6);lcd.write(6);
lcd.setCursor(x, 1);lcd.write(3);lcd.write(4);lcd.write(5);
}
void custom7(int x){
lcd.setCursor(x,0);lcd.write(1);lcd.write(1);lcd.write(2);
lcd.setCursor(x, 1);lcd.print(" ");lcd.print(" ");lcd.write(7);
}
void custom8(int x){
lcd.setCursor(x,0);lcd.write(0);lcd.write(6);lcd.write(2);
lcd.setCursor(x, 1);lcd.write(3);lcd.write(4);lcd.write(5);
}
void custom9(int x){
lcd.setCursor(x,0);lcd.write(0);lcd.write(6);lcd.write(2);
lcd.setCursor(x, 1);lcd.print(" ");lcd.print(" ");lcd.write(7);
}
void setup() {
Serial.begin(115200);
pinMode(hallSensorPin, INPUT);
pinMode(buttonMenuPin, INPUT_PULLUP);
pinMode(buttonCountUp, INPUT_PULLUP);
pinMode(buttonCountDown, INPUT_PULLUP);
pinMode(buzzerPin, OUTPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(buzzerPin, LOW);
digitalWrite(ledPin, LOW);
attachInterrupt(digitalPinToInterrupt(hallSensorPin), rpmCounter, FALLING);
lcd.init();
lcd.backlight();
lcd.createChar(0,LT);
lcd.createChar(1,UB);
lcd.createChar(2,RT);
lcd.createChar(3,LL);
lcd.createChar(4,LB);
lcd.createChar(5,LR);
lcd.createChar(6,MB);
lcd.createChar(7,block);
EEPROM.get(0, settings);
if (settings.rpmLimit > 15000) {settings.rpmLimit = 0;}
else if (settings.rpmLimit < 0) {settings.rpmLimit = 0;}
settings.alarmSelect = constrain(settings.alarmSelect, 0, 3);
lcd.setCursor(0,0);lcd.print(" WELCOME ");
lcd.setCursor(0,1);lcd.print(" TACHOMETER ");
for (byte x = 0; x < 20; x++ ){
lcd.setCursor(x,3);lcd.print(".");
delay(50);
}
delay(1000);
lcd.clear();
}
void loop() {
currentTime = millis();
if (currentTime - lastTime >= 1000) {
rpm = ((pulseCount / (float)teethCount) * 60.0) * calibration;
rpmToDisplay = rpm;
Serial.println(rpmToDisplay);
if (rpm < 0) {rpm = 0;}
pulseCount = 0;
lastTime = currentTime;
}
rpmToDisplay = rpm;
printDigits(rpmToDisplay / 10000, 0);
printDigits((rpmToDisplay / 1000) % 10, 4);
printDigits((rpmToDisplay / 100) % 10, 8);
printDigits((rpmToDisplay / 10) % 10, 12);
printDigits(rpmToDisplay % 10, 16);
if (rpm > settings.rpmLimit) {
if(settings.alarmSelect==1){digitalWrite(ledPin, HIGH);digitalWrite(buzzerPin, HIGH);}
if(settings.alarmSelect==2){digitalWrite(ledPin, HIGH);}
if(settings.alarmSelect==3){digitalWrite(buzzerPin, HIGH);}
alarmState = true;
}
else {
digitalWrite(ledPin, LOW);
digitalWrite(buzzerPin, LOW);
alarmState = false;
}
if(!digitalRead(buttonMenuPin)){menuSelect++;if(menuSelect>2)menuSelect=0;delay(100);}
if(menuSelect==0){
sprintf(buffer, "Lim:%05d", settings.rpmLimit);
lcd.setCursor(0, 3);lcd.print(" ");lcd.print(buffer);
lcd.setCursor(10, 3);lcd.print(" ");lcd.print("Out:"+alarmName[settings.alarmSelect]+" ");
}
else if(menuSelect==1){
if(!digitalRead(buttonCountUp)){settings.rpmLimit=settings.rpmLimit+10;if(settings.rpmLimit>15000)settings.rpmLimit=0;EEPROM.put(0, settings);delay(100);}
if(!digitalRead(buttonCountDown)){settings.rpmLimit=settings.rpmLimit-10;if(settings.rpmLimit<0)settings.rpmLimit=15000;EEPROM.put(0, settings);delay(100);}
sprintf(buffer, "Lim:%05d", settings.rpmLimit);
lcd.setCursor(0, 3);lcd.print("[");lcd.print(buffer);
lcd.setCursor(10, 3);lcd.print("]");lcd.print("Out:"+alarmName[settings.alarmSelect]);
}
else if(menuSelect==2){
if(!digitalRead(buttonCountUp)){settings.alarmSelect++;if(settings.alarmSelect>3)settings.alarmSelect=0;EEPROM.put(0, settings);delay(100);}
if(!digitalRead(buttonCountDown)){settings.alarmSelect--;if(settings.alarmSelect<0)settings.alarmSelect=3;EEPROM.put(0, settings);delay(100);}
sprintf(buffer, "Lim:%05d", settings.rpmLimit);
lcd.setCursor(0, 3);lcd.print(" ");lcd.print(buffer);
lcd.setCursor(10, 3);lcd.print("[");lcd.print("Out:"+alarmName[settings.alarmSelect]);lcd.print("]");
}
}
void printDigits(int digits, int x) {
switch (digits) {
case 0: custom0(x); break;
case 1: custom1(x); break;
case 2: custom2(x); break;
case 3: custom3(x); break;
case 4: custom4(x); break;
case 5: custom5(x); break;
case 6: custom6(x); break;
case 7: custom7(x); break;
case 8: custom8(x); break;
case 9: custom9(x); break;
}
}
void rpmCounter() {
pulseCount++; // Tambah jumlah RPM tiap sensor terpicu
}