#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <neotimer.h>
#define WAITING 0
#define STARTING 1
#define STARTED 2
#define RAMP_UP 3
#define RUNNING 4
#define FAIL 5
#define FAILED_START 1
#define OVERVOLTAGE 2
#define FAILED_RPM 3
#define FAILED_VIBSENSOR 4
const int currentPin = A0;
const int voltagePin = A3;
const int motorPin = 2;
const int pwmPin = 9;
const int relayPin = 4;
const int rpmPin = 11;
const int overPin = 12;
const int starterPin = 3;
Neotimer motorTime = Neotimer(10000);
Neotimer stepTime = Neotimer(1000);
Neotimer shutTime = Neotimer(15000);
Neotimer crankTime = Neotimer(4000);
Neotimer crankWait = Neotimer(5000);
Neotimer voltageWait = Neotimer(10000);
Neotimer sensorTime = Neotimer(5000);
Neotimer buttonTime = Neotimer(2000);
LiquidCrystal_I2C lcd(0x27, 16, 2);
int motorStatus = WAITING;
int startTry = 0;
int startInterval = 0;
int currentPwmStep = 0;
int pwmValues[] = { 15, 53, 91, 129 };
int lcdFail = 0;
float voltageFactor = 5.00 / 1023.00;
float x1 = 0.500;
float y1 = 0;
float x2 = 4.300;
float y2 = 150;
float m = (y2 - y1) / (x2 - x1);
float b = y1 - m * x1;
float currentCal = 1;
float sensVfactor = 20.00 / 4.9197;
const int N = 25;
const int Y = 25;
int readings[N];
int readingsV[Y];
float sensVoltage = 12.0;
float current = 0.0;
unsigned long rpm = 0;
unsigned long duration;
void setup() {
Serial.begin(250000);
TCCR1A = 0b00000001;
TCCR1B = 0b00000100;
Wire.begin();
Wire.beginTransmission(0x27);
if (Wire.endTransmission() == 0) {
lcd.begin(16, 2);
lcd.backlight();
lcd.clear();
} else {
Serial.println("LCD not connected. Skipping.");
}
pinMode(currentPin, INPUT);
pinMode(voltagePin, INPUT);
pinMode(motorPin, INPUT_PULLUP);
pinMode(pwmPin, OUTPUT);
pinMode(relayPin, OUTPUT);
pinMode(rpmPin, INPUT_PULLUP);
pinMode(overPin, INPUT_PULLUP);
pinMode(starterPin, OUTPUT);
analogWrite(pwmPin, 255);
}
void startCharge() {
if (digitalRead(overPin == LOW)) {
if (!buttonTime.started()) {
buttonTime.start();
}
if (buttonTime.done()) {
motorStatus = STARTING;
digitalWrite(relayPin, HIGH);
buttonTime.stop();
buttonTime.reset();
}
} else {
buttonTime.stop();
buttonTime.reset();
}
}
void motorCrankState() {
if (sensVoltage < 1.9) {
if (!voltageWait.started()) {
voltageWait.start();
}
if (voltageWait.done()) {
motorStatus = STARTING;
digitalWrite(relayPin, HIGH);
voltageWait.stop();
voltageWait.reset();
}
} else {
voltageWait.stop();
voltageWait.reset();
}
}
void crank() {
if (startTry < 5 && startInterval == 0) {
if (rpm <= 300) {
digitalWrite(starterPin, HIGH);
if (!crankTime.started()) {
crankTime.start();
}
if (crankTime.done()) {
digitalWrite(starterPin, LOW);
crankTime.stop();
crankTime.reset();
startTry++;
startInterval = 1;
}
} else if (rpm > 300) {
digitalWrite(starterPin, LOW);
startTry = 0;
motorStatus = STARTED;
crankTime.stop();
crankTime.reset();
}
}
}
void Waiter() {
if (startInterval == 1) {
if (!crankWait.started()) {
crankWait.start();
}
if (crankWait.done()) {
startInterval = 0;
crankWait.stop();
crankWait.reset();
}
}
}
void motorRunning() {
if (rpm > 1800 || digitalRead(motorPin) == HIGH) {
if (!motorTime.started()) {
motorTime.start();
}
if (motorTime.done()) {
motorStatus = RAMP_UP;
motorTime.stop();
motorTime.reset();
}
}
}
void rampUp() {
if (stepTime.repeat()) {
analogWrite(pwmPin, pwmValues[currentPwmStep]);
currentPwmStep++;
if (currentPwmStep >= sizeof(pwmValues) / sizeof(pwmValues[0])) {
motorStatus = RUNNING;
stepTime.stop();
stepTime.reset();
}
}
}
void shutDown() {
if (current < 5) {
digitalWrite(relayPin, LOW);
analogWrite(pwmPin, 15);
if (!shutTime.started()) {
shutTime.start();
}
if (shutTime.done()) {
analogWrite(pwmPin, 255);
motorStatus = WAITING;
shutTime.stop();
shutTime.reset();
}
}
}
void failState() {
if (startTry == 5) {
motorStatus = FAIL;
digitalWrite(starterPin, LOW);
digitalWrite(relayPin, LOW);
lcdFail = FAILED_START;
} else if (sensVoltage >= 15) {
motorStatus = FAIL;
digitalWrite(relayPin, LOW);
lcdFail = OVERVOLTAGE;
if (!shutTime.started()) {
shutTime.start();
}
if (shutTime.done()) {
analogWrite(pwmPin, 255);
shutTime.stop();
shutTime.reset();
}
} else if ((rpm <= 900 || rpm >= 3700) && motorStatus == RUNNING) {
motorStatus = FAIL;
digitalWrite(relayPin, LOW);
lcdFail = FAILED_RPM;
if (!shutTime.started()) {
shutTime.start();
}
if (shutTime.done()) {
analogWrite(pwmPin, 255);
shutTime.stop();
shutTime.reset();
}
}
}
void lcdDisplay() {
if (motorStatus == RUNNING || motorStatus == RAMP_UP) {
lcd.setCursor(0, 0);
lcd.print("Virta: ");
lcd.print(current);
lcd.print(" A ");
lcd.setCursor(0, 1);
lcd.print("J");
lcd.print((char)0xe1);
lcd.print("nnite: ");
lcd.print(sensVoltage);
lcd.print(" V ");
} else if (motorStatus == WAITING) {
lcd.setCursor(0, 0);
lcd.print("Odottaa... ");
lcd.setCursor(0, 1);
lcd.print("J");
lcd.print((char)0xe1);
lcd.print("nnite: ");
lcd.print(sensVoltage);
lcd.print(" V ");
} else if (motorStatus == STARTING || motorStatus == STARTED) {
lcd.setCursor(0, 0);
lcd.print("K");
lcd.print((char)0xe1);
lcd.print("ynnistet");
lcd.print((char)0xe1);
lcd.print((char)0xe1);
lcd.print("n");
lcd.setCursor(0, 1);
lcd.print("................");
} else if (lcdFail == FAILED_START) {
lcd.setCursor(0, 0);
lcd.print("K");
lcd.print((char)0xe1);
lcd.print("ynnistys ");
lcd.setCursor(0, 1);
lcd.print("ep");
lcd.print((char)0xe1);
lcd.print("onnistui ");
} else if (lcdFail == OVERVOLTAGE) {
lcd.setCursor(0, 0);
lcd.print("Ylij");
lcd.print((char)0xe1);
lcd.print("nnite ");
lcd.setCursor(0, 1);
lcd.print(" ");
} else if (lcdFail == FAILED_RPM) {
lcd.setCursor(0, 0);
lcd.print("Kierrosluku ");
lcd.setCursor(0, 1);
lcd.print("virheellinen ");
}
}
void loop() {
for (int i = 0; i < N; i++) {
readings[i] = analogRead(currentPin);
delay(1);
}
float sum = 0;
for (int i = 0; i < N; i++) {
sum += readings[i];
}
float average = sum / N;
float voltage = average * voltageFactor;
current = (m * voltage + b) * currentCal;
for (int j = 0; j < Y; j++) {
readingsV[j] = analogRead(voltagePin);
delay(1);
}
float sumV = 0;
for (int j = 0; j < Y; j++) {
sumV += readingsV[j];
}
float averageV = sumV / Y;
float voltageV = averageV * voltageFactor;
sensVoltage = voltageV * sensVfactor;
if (Serial.available() > 0) {
char input = Serial.read();
switch (input) {
case '1':
rpm = 0;
break;
case '2':
rpm = 500;
break;
case '3':
rpm = 2000;
break;
case 'a':
current = 2;
break;
case 'b':
current = 20;
break;
case 'c':
current = 80;
break;
case 'z':
sensVoltage = 11;
break;
case 'x':
sensVoltage = 14;
break;
case 'y':
sensVoltage = 16;
break;
default:
Serial.println("Invalid input.");
return;
}
}
switch (motorStatus) {
case WAITING:
motorCrankState();
startCharge();
break;
case STARTING:
crank();
Waiter();
break;
case STARTED:
motorRunning();
break;
case RAMP_UP:
rampUp();
break;
case RUNNING:
shutDown();
break;
}
lcdDisplay();
failState();
Serial.print("Voltage: ");
Serial.print(sensVoltage);
Serial.print(" V, Current: ");
Serial.print(current);
Serial.print(" A, RPM: ");
Serial.print(rpm);
Serial.print(", Status: ");
Serial.print(motorStatus);
Serial.print(", Start try: ");
Serial.print(startTry);
Serial.print(", Start wait: ");
Serial.println(startInterval);
}