#include <LiquidCrystal.h>
// Pin Definitions
const int startButtonPin = A0; // START button input from A0
const int upButtonPin = A2; // UP button input from A2
const int downButtonPin = A3; // DOWN button input from A3
const int stopButtonPin = A4; // STOP button input from A4
const int potPin = A1; // Potentiometer input from A1
const int crankPin = 2; // Crank signal output
const int camPin = 3; // Cam signal output
const int ecuPin = 10; // ECU input pin (changed to pin 10)
// Pin setup for the LCD (4-bit mode)
const int rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7); // Initialize LCD using the pins defined
// Variables
int currentRPM = 0;
bool systemRunning = false; // Flag to control system state (running or not)
int vehicleIndex = 0; // Index of the selected vehicle
// Button state variables
bool lastUpButtonState = LOW;
bool lastDownButtonState = LOW;
bool lastStartButtonState = LOW;
bool lastStopButtonState = LOW;
unsigned long lastButtonPressTimeUp = 0; // Debounce for UP button
unsigned long lastButtonPressTimeDown = 0; // Debounce for DOWN button
unsigned long lastButtonPressTimeStart = 0; // Debounce for START button
unsigned long lastButtonPressTimeStop = 0; // Debounce for STOP button
const unsigned long debounceDelay = 50; // Debounce delay in milliseconds
// List of vehicles and their crank/cam signal properties (pulses per revolution and max RPM)
struct Vehicle {
String name;
int pulsesPerRevolution; // Crank pulses per revolution
int maxRPM; // Max RPM (for calculating pulse frequencies)
bool hasCamSignal; // Whether the vehicle has a cam signal or not
};
Vehicle vehicles[] = {
{"4 cylinder distributor", 2, 6000, true}, // 200 Hz at 6000 RPM
{"6 cylinder distributor", 3, 6000, true}, // 300 Hz at 6000 RPM
{"8 cylinder distributor", 4, 6000, true}, // 400 Hz at 6000 RPM
{"60-2 crank wheel", 60, 6000, false}, // 6000 Hz at 6000 RPM
{"36-1 crank wheel", 36, 6000, true}, // 3600 Hz at 6000 RPM
{"4-1 crank wheel", 4, 6000, true}, // 400 Hz at 6000 RPM
{"8-1 crank wheel", 8, 6000, true}, // 800 Hz at 6000 RPM
{"12-1 crank wheel", 12, 6000, true}, // 1200 Hz at 6000 RPM
{"Optispark", 180, 15000, true}, // 18000 Hz at 15000 RPM
{"Nissan 360", 360, 15000, true}, // 18000 Hz at 15000 RPM
{"Weber Marelli 8 crank 2 cam pulses", 8, 6000, true}, // 800 Hz at 6000 RPM
{"Mazda 24-2 Caz", 12, 6000, true} // 1200 Hz at 6000 RPM
};
// Variables to store the previous time for the signals
unsigned long lastCrankToggleTime = 0;
unsigned long lastCamToggleTime = 0;
int crankState = LOW; // Initial state of the crank pin
int camState = LOW; // Initial state of the cam pin
// Setup
void setup() {
lcd.begin(16, 2);
lcd.print("Md Alamgir");
lcd.setCursor(0, 1);
lcd.print("Mob. 8641951536");
delay(3000);
lcd.clear();
// Set output pins for crank and cam to LOW initially
pinMode(crankPin, OUTPUT);
pinMode(camPin, OUTPUT);
digitalWrite(crankPin, LOW); // Ensure crank is LOW at start
digitalWrite(camPin, LOW); // Ensure cam is LOW at start
// Set button input pins
pinMode(startButtonPin, INPUT);
pinMode(upButtonPin, INPUT);
pinMode(downButtonPin, INPUT);
pinMode(stopButtonPin, INPUT);
// Set the ECU pin as input
pinMode(ecuPin, INPUT);
displayVehicleInfo();
}
// Main loop
void loop() {
// Read button states using digitalRead (high or low)
bool upButtonState = digitalRead(upButtonPin) == HIGH;
bool downButtonState = digitalRead(downButtonPin) == HIGH;
bool startButtonState = digitalRead(startButtonPin) == HIGH;
bool stopButtonState = digitalRead(stopButtonPin) == HIGH;
// Handle UP button press (only change if rising edge is detected)
if (upButtonState && lastUpButtonState == LOW && (millis() - lastButtonPressTimeUp) > debounceDelay) {
increaseVehicleIndex();
lastButtonPressTimeUp = millis(); // Update last press time
}
// Handle DOWN button press (only change if rising edge is detected)
if (downButtonState && lastDownButtonState == LOW && (millis() - lastButtonPressTimeDown) > debounceDelay) {
decreaseVehicleIndex();
lastButtonPressTimeDown = millis(); // Update last press time
}
// Handle START button press
if (startButtonState && lastStartButtonState == LOW && (millis() - lastButtonPressTimeStart) > debounceDelay) {
startSystem();
lastButtonPressTimeStart = millis(); // Update last press time
}
// Handle STOP button press
if (stopButtonState && lastStopButtonState == LOW && (millis() - lastButtonPressTimeStop) > debounceDelay) {
stopSystem();
lastButtonPressTimeStop = millis(); // Update last press time
}
// Update button states for the next iteration
lastUpButtonState = upButtonState;
lastDownButtonState = downButtonState;
lastStartButtonState = startButtonState;
lastStopButtonState = stopButtonState;
// Read potentiometer for RPM control
currentRPM = map(analogRead(potPin), 0, 1023, 50, vehicles[vehicleIndex].maxRPM); // Adjust RPM range from 50 to vehicle's max RPM
// Update display based on system status
if (systemRunning) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("RPM: ");
lcd.print(currentRPM);
lcd.setCursor(0, 1);
lcd.print("Vehicle: ");
lcd.print(vehicles[vehicleIndex].name);
} else {
displayVehicleInfo();
}
// Generate crank and cam signals only when the system is running
if (systemRunning) {
if (digitalRead(ecuPin) == HIGH) { // ECU signal received
generateSensorSignals();
}
} else {
// Ensure LEDs are off when system is stopped
digitalWrite(crankPin, LOW);
digitalWrite(camPin, LOW);
}
delay(100); // Update every 100ms (faster than the 500ms before)
}
// Function to display vehicle info
void displayVehicleInfo() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select Vehicle");
lcd.setCursor(0, 1);
lcd.print(vehicles[vehicleIndex].name);
}
// Function to start the system
void startSystem() {
if (!systemRunning) {
systemRunning = true;
lcd.clear();
lcd.print("System Started");
}
}
// Function to stop the system
void stopSystem() {
systemRunning = false;
lcd.clear();
lcd.print("System Stopped");
}
// Function to increase vehicle index
void increaseVehicleIndex() {
if (vehicleIndex < (sizeof(vehicles) / sizeof(vehicles[0])) - 1) {
vehicleIndex++;
} else {
vehicleIndex = 0;
}
displayVehicleInfo();
}
// Function to decrease vehicle index
void decreaseVehicleIndex() {
if (vehicleIndex > 0) {
vehicleIndex--;
} else {
vehicleIndex = sizeof(vehicles) / sizeof(vehicles[0]) - 1;
}
displayVehicleInfo();
}
// Function to generate crank and cam sensor signals
void generateSensorSignals() {
int pulsesPerRevolution = vehicles[vehicleIndex].pulsesPerRevolution;
int maxRPM = vehicles[vehicleIndex].maxRPM;
// Calculate crank frequency (Hz)
int crankFrequency = map(currentRPM, 50, maxRPM, pulsesPerRevolution / 2, pulsesPerRevolution * 2);
// Calculate period for crank signal (in milliseconds)
int crankPeriod = 1000 / crankFrequency;
// Generate crank signal (square wave)
if (millis() - lastCrankToggleTime >= crankPeriod / 2) {
crankState = (crankState == LOW) ? HIGH : LOW; // Toggle the state
digitalWrite(crankPin, crankState); // Output the crank signal
lastCrankToggleTime = millis(); // Update the last toggle time
}
// Check if we need to generate a cam signal, including custom logic for "60-2 crank wheel"
if (vehicles[vehicleIndex].hasCamSignal || vehicleIndex == 3) { // Check if the vehicle has a cam signal or if it's a "60-2 crank wheel"
// Custom logic for "60-2 crank wheel" (vehicleIndex == 3)
if (vehicleIndex == 3) { // "60-2 crank wheel" has a special case
// For a "60-2" crank wheel, generate cam signal every 2 crank rotations (every 720°)
int camFrequency = crankFrequency / 2; // Generate at half the frequency of the crank signal
// Calculate period for cam signal (in milliseconds)
int camPeriod = 1000 / camFrequency;
// Generate cam signal (square wave)
if (millis() - lastCamToggleTime >= camPeriod / 2) {
camState = (camState == LOW) ? HIGH : LOW; // Toggle the state
digitalWrite(camPin, camState); // Output the cam signal
lastCamToggleTime = millis(); // Update the last toggle time
}
}
else {
// For other vehicles with a cam signal, generate the signal normally
int camFrequency = crankFrequency / 2; // Typically, cam signal is half the crank frequency
// Calculate period for cam signal (in milliseconds)
int camPeriod = 1000 / camFrequency;
// Generate cam signal (square wave)
if (millis() - lastCamToggleTime >= camPeriod / 2) {
camState = (camState == LOW) ? HIGH : LOW; // Toggle the state
digitalWrite(camPin, camState); // Output the cam signal
lastCamToggleTime = millis(); // Update the last toggle time
}
}
}
}