#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD I2C address and size
#define LCD_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_ROWS 2
// Pin definitions for inputs and outputs
const int ip1 = 2; // Input pin 1
const int ip2 = 3; // Input pin 2
const int ip3 = 4; // Input pin 3
const int ip4 = 5; // Input pin 4
const int ip5 = 6; // Input pin 5
const int ip6 = 7; // Input pin 6
const int ip7 = 8; // Input pin 7
const int ip8 = 9; // Input pin 8
const int op1 = A0; // Output pin 1 (Gate 1)
const int op2 = A1; // Output pin 2 (Gate 2)
const int op3 = A2; // Output pin 3 (Gate 3)
const int op4 = A3; // Output pin 4 (Gate 4)
const int toggleSwitch = 10; // Pin for the 7404 toggle switch
const int norSwitch = 13; // Pin for the 7402 toggle switch
const int redLED = 11; // Red LED pin for bad IC
const int greenLED = 12; // Green LED pin for good IC
const int IC_PINS[12] = {2, 3, 4, 5, 6, 7, 8, 9, A0, A1, A2, A3};
LiquidCrystal_I2C lcd(LCD_ADDR, LCD_COLUMNS, LCD_ROWS);
enum IcType { IC_UNKNOWN, IC_AND, IC_NAND, IC_OR, IC_XOR };
IcType detectedIC;
void setup() {
lcd.begin();
lcd.backlight();
Serial.begin(9600);
pinMode(redLED, OUTPUT);
pinMode(greenLED, OUTPUT);
// Set pin modes
pinMode(ip1, OUTPUT);
pinMode(ip2, OUTPUT);
pinMode(ip3, OUTPUT);
pinMode(ip4, OUTPUT);
pinMode(ip5, OUTPUT);
pinMode(ip6, OUTPUT);
pinMode(ip7, OUTPUT);
pinMode(ip8, OUTPUT);
pinMode(op1, INPUT);
pinMode(op2, INPUT);
pinMode(op3, INPUT);
pinMode(op4, INPUT);
pinMode(toggleSwitch, INPUT_PULLUP); // Setup the toggle switch pin with pull-up resistor
pinMode(norSwitch, INPUT_PULLUP); // Setup the NOR switch pin with pull-up resistor
// Initial LCD message
lcd.setCursor(0, 0);
lcd.print("IC Tester Ready");
delay(2000);
}
// LED blinking control variables
unsigned long previousLEDMillis = 0;
const long ledInterval = 500; // Time interval for LED blinking (500ms)
bool ledState = LOW;
void nonBlockingBlinkLEDs() {
unsigned long currentMillis = millis();
if (currentMillis - previousLEDMillis >= ledInterval) {
// Save the last time you blinked the LED
previousLEDMillis = currentMillis;
// If the LED is off turn it on and vice versa
ledState = !ledState;
// Set the LEDs
digitalWrite(greenLED, ledState);
digitalWrite(redLED, ledState);
}
}
// Debounce settings
const int debounceDelay = 20; // Reduced debounce delay for faster response
unsigned long lastDebounceTime7404 = 0;
unsigned long lastDebounceTime7402 = 0;
bool lastToggleState = HIGH;
bool lastNORState = HIGH;
// Timing control for avoiding delay(3000)
unsigned long previousMillis = 0;
const long interval = 1000; // 1 second delay between actions without blocking
String lastLCDMessageLine1 = ""; // Track the last message on line 1
String lastLCDMessageLine2 = ""; // Track the last message on line 2
void updateLCD(String messageLine1, String messageLine2) {
// Only update the LCD if the message changes
if (messageLine1 != lastLCDMessageLine1 || messageLine2 != lastLCDMessageLine2) {
lcd.clear(); // Clear the screen
lcd.setCursor(0, 0);
lcd.print(messageLine1); // Display the new message on line 1
lcd.setCursor(0, 1);
lcd.print(messageLine2); // Display the new message on line 2
// Update the last messages
lastLCDMessageLine1 = messageLine1;
lastLCDMessageLine2 = messageLine2;
}
}
void loop() {
unsigned long currentMillis = millis();
// Read current states
bool currentToggleState = digitalRead(toggleSwitch);
bool currentNORState = digitalRead(norSwitch);
// Debounce logic for 7404 mode (toggle switch)
if (currentToggleState != lastToggleState) {
lastDebounceTime7404 = millis(); // Reset the debounce timer
}
if ((millis() - lastDebounceTime7404) > debounceDelay) {
bool is7404Mode = currentToggleState == LOW;
// Debounce logic for 7402 mode (NOR switch)
if (currentNORState != lastNORState) {
lastDebounceTime7402 = millis(); // Reset the debounce timer
}
if ((millis() - lastDebounceTime7402) > debounceDelay) {
bool isNORMode = currentNORState == LOW;
// Check if enough time has passed since the last loop iteration
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis; // Save the current time
// Execute based on the current state of the buttons
if (is7404Mode && isNORMode) {
// Both switches pressed: Execute generic IC detection and checking gates
setPinModesForGenericIC();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Detecting IC...");
Serial.println("Detecting IC...");
detectICByMajority(); // Automatically detect IC type
testICGates(); // Perform gate testing on detected IC
}
else if (is7404Mode) {
// Only toggle switch pressed: Execute testing of 7404
setPinModesFor7404();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("7404 Test Mode");
Serial.println("Testing 7404 IC...");
test7404IC(); // Call the function to test the 7404 IC
}
else if (isNORMode) {
// Only NOR switch pressed: Execute testing of 7402
setPinModesFor7402();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("7402 Test Mode");
Serial.println("Testing 7402 IC...");
test7402IC(); // Call the function to test the 7402 IC
}
else {
// Neither switch pressed: Ask user to select mode
initializeICPins();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select Mode:");
lcd.setCursor(0, 1);
lcd.print("USE PUSH BUTTONS");
Serial.println("Waiting for user selection...");
nonBlockingBlinkLEDs(); // Provide non-blocking visual feedback with LEDs
}
}
}
}
// Update the last states
lastToggleState = currentToggleState;
lastNORState = currentNORState;
}
void setPinModesFor7402() {
pinMode(ip1, INPUT);
pinMode(ip2, OUTPUT);
pinMode(op1, OUTPUT);
pinMode(ip3, INPUT);
pinMode(ip4, OUTPUT);
pinMode(op2, OUTPUT);
pinMode(ip5, INPUT);
pinMode(ip6, OUTPUT);
pinMode(op3, OUTPUT);
pinMode(ip7, INPUT);
pinMode(ip8, OUTPUT);
pinMode(op4, OUTPUT);
}
bool icStatus = true; // Overall IC status
bool gateStatus[4] = {true, true, true, true}; // Status for each gate
bool allOutputsLow = true; // Flag to check if all outputs are LOW
// Function to initialize all IC pins to LOW
void initializeICPins() {
for (int i = 0; i < 12; i++) {
pinMode(IC_PINS[i], OUTPUT); // Set pin as output
digitalWrite(IC_PINS[i], LOW); // Set pin to LOW
}
}
void test7402IC() {
Serial.println("Testing 7402 IC...");
// Reset the status for all gates
icStatus = true;
allOutputsLow = true;
for (int i = 0; i < 4; i++) {
gateStatus[i] = true;
}
// Test each gate in the 7402 IC
Serial.println("TESTING GATE 1...");
gateStatus[0] = checkGate(ip2, op1, ip1); // Test Gate 1
Serial.println(gateStatus[0] ? "GATE 1 GOOD" : "GATE 1 BAD");
Serial.println("TESTING GATE 2...");
gateStatus[1] = checkGate(ip4, op2, ip3); // Test Gate 2
Serial.println(gateStatus[1] ? "GATE 2 GOOD" : "GATE 2 BAD");
Serial.println("TESTING GATE 3...");
gateStatus[2] = checkGate(ip6, op3, ip5); // Test Gate 3
Serial.println(gateStatus[2] ? "GATE 3 GOOD" : "GATE 3 BAD");
Serial.println("TESTING GATE 4...");
gateStatus[3] = checkGate(ip8, op4, ip7); // Test Gate 4
Serial.println(gateStatus[3] ? "GATE 4 GOOD" : "GATE 4 BAD");
// Check if all outputs are LOW
if (allOutputsLow) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("NO IC DETECTED");
Serial.println("NO IC DETECTED");
delay(5000); // Pause to allow the user to see the message
return;
}
// Evaluate overall IC status
bool allGood = true;
bool allBad = true;
for (int i = 0; i < 4; i++) {
if (gateStatus[i] == false) {
allGood = false;
} else {
allBad = false;
}
}
// Clear the screen and display the results
lcd.clear();
if (allGood) {
lcd.setCursor(0, 0);
lcd.print("ALL GATES GOOD");
Serial.println("ALL GATES GOOD");
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("IC IS GOOD");
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, LOW);
Serial.println("IC IS GOOD");
} else if (allBad) {
lcd.setCursor(0, 0);
lcd.print("ALL GATES BAD");
Serial.println("ALL GATES BAD");
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("IC IS BAD");
digitalWrite(redLED, HIGH);
digitalWrite(greenLED, LOW);
Serial.println("IC IS BAD");
} else {
lcd.setCursor(0, 0);
lcd.print("BAD GATES:");
lcd.setCursor(0, 1);
bool firstBadGate = true;
Serial.print("BAD GATES: ");
for (int i = 0; i < 4; i++) {
if (!gateStatus[i]) {
if (!firstBadGate) lcd.print(" ");
lcd.print("G");
lcd.print(i + 1);
Serial.print("G");
Serial.print(i + 1);
firstBadGate = false;
}
}
Serial.println();
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("IC NOT DAMAGED");
lcd.setCursor(0, 1);
lcd.print("USE GOOD GATES");
Serial.println("IC NOT DAMAGED. USE GOOD GATES.");
}
}
// Function to check the correctness of the gate output
bool checkGate(int inputA, int inputB, int output) {
bool gateIsGood = true; // Assume gate is GOOD initially
// Test Input: 00 (expected output = HIGH)
digitalWrite(inputA, LOW);
digitalWrite(inputB, LOW);
delay(100);
int result = digitalRead(output);
if (result != HIGH) {
gateIsGood = false; // Gate is bad if output doesn't match expected
}
if (result != HIGH) {
allOutputsLow = allOutputsLow && true;
} else {
allOutputsLow = false; // If any output is not LOW, IC is detected
}
// Test Input: 01 (expected output = LOW)
digitalWrite(inputA, LOW);
digitalWrite(inputB, HIGH);
delay(100);
result = digitalRead(output);
if (result != LOW) {
gateIsGood = false;
}
if (result != HIGH) {
allOutputsLow = allOutputsLow && true;
} else {
allOutputsLow = false;
}
// Test Input: 10 (expected output = LOW)
digitalWrite(inputA, HIGH);
digitalWrite(inputB, LOW);
delay(100);
result = digitalRead(output);
if (result != LOW) {
gateIsGood = false;
}
if (result != HIGH) {
allOutputsLow = allOutputsLow && true;
} else {
allOutputsLow = false;
}
// Test Input: 11 (expected output = LOW)
digitalWrite(inputA, HIGH);
digitalWrite(inputB, HIGH);
delay(100);
result = digitalRead(output);
if (result != LOW) {
gateIsGood = false;
}
if (result != HIGH) {
allOutputsLow = allOutputsLow && true;
} else {
allOutputsLow = false;
}
return gateIsGood;
}
void setPinModesForGenericIC() {
pinMode(ip1, OUTPUT);
pinMode(ip2, OUTPUT);
pinMode(ip3, OUTPUT);
pinMode(ip4, OUTPUT);
pinMode(ip5, OUTPUT);
pinMode(ip6, OUTPUT);
pinMode(ip7, OUTPUT);
pinMode(ip8, OUTPUT);
pinMode(op1, INPUT);
pinMode(op2, INPUT);
pinMode(op3, INPUT);
pinMode(op4, INPUT);
}
void setPinModesFor7404() {
pinMode(ip1, OUTPUT);
pinMode(ip2, INPUT);
pinMode(op1, OUTPUT);
pinMode(ip3, INPUT);
pinMode(ip4, OUTPUT);
pinMode(op2, INPUT);
pinMode(ip6, OUTPUT);
pinMode(op3, INPUT);
pinMode(op4, OUTPUT);
pinMode(ip5, INPUT);
pinMode(ip7, OUTPUT);
pinMode(ip8, INPUT);
}
void test7404IC() {
bool isICBad = false;
String badGates = "";
// Test each gate with both combinations (0 and 1)
for (int i = 0; i < 2; i++) {
// Output testing status to Serial Monitor
Serial.print("Testing input combination: ");
Serial.println(i);
// Test NOT gate 1
digitalWrite(ip1, i);
delay(10);
if (digitalRead(ip2) != !i) {
isICBad = true;
badGates += "G1 ";
Serial.println("Gate 1 is BAD.");
}
// Test NOT gate 2
digitalWrite(op1, i);
delay(10);
if (digitalRead(ip3) != !i) {
isICBad = true;
badGates += "G2 ";
Serial.println("Gate 2 is BAD.");
}
// Test NOT gate 3
digitalWrite(ip4, i);
delay(10);
if (digitalRead(op2) != !i) {
isICBad = true;
badGates += "G3 ";
Serial.println("Gate 3 is BAD.");
}
// Test NOT gate 4
digitalWrite(ip6, i);
delay(10);
if (digitalRead(op3) != !i) {
isICBad = true;
badGates += "G4 ";
Serial.println("Gate 4 is BAD.");
}
// Test NOT gate 5
digitalWrite(op4, i);
delay(10);
if (digitalRead(ip5) != !i) {
isICBad = true;
badGates += "G5 ";
Serial.println("Gate 5 is BAD.");
}
// Test NOT gate 6
digitalWrite(ip7, i);
delay(10);
if (digitalRead(ip8) != !i) {
isICBad = true;
badGates += "G6 ";
Serial.println("Gate 6 is BAD.");
}
}
lcd.clear();
if (badGates.length() > 0) {
lcd.setCursor(0, 0);
lcd.print("BAD Gates: ");
lcd.setCursor(0, 1);
lcd.print(badGates.substring(0, 16));
} else {
lcd.setCursor(0, 0);
lcd.print("ALL GATES GOOD");
}
delay(2000);
lcd.clear();
if (badGates.length() == 0) {
lcd.print("IC is GOOD");
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, LOW);
Serial.println("IC Status: GOOD");
} else if (badGates.length() > 0 && badGates.length() < 12) {
lcd.setCursor(0, 0);
lcd.print("IC NOT DAMAGED");
lcd.setCursor(0, 1);
lcd.print("USE GOOD GATES");
Serial.println("IC Status: NOT DAMAGED");
} else {
lcd.print("IC is BAD");
digitalWrite(redLED, HIGH);
digitalWrite(greenLED, LOW);
Serial.println("IC Status: BAD");
}
delay(3000);
}
void detectICByMajority() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Detecting IC...");
Serial.println("Starting IC detection by majority...");
delay(2000);
int andMatches = 0;
int nandMatches = 0;
int orMatches = 0;
int xorMatches = 0;
// Loop through each gate and test all combinations
for (int gate = 1; gate <= 4; gate++) {
Serial.print("Checking Gate ");
Serial.println(gate);
int a, b;
switch (gate) {
case 1:
a = ip1;
b = ip2;
break;
case 2:
a = ip3;
b = ip4;
break;
case 3:
a = ip5;
b = ip6;
break;
case 4:
a = ip7;
b = ip8;
break;
}
int andGateCorrect = 0;
int nandGateCorrect = 0;
int orGateCorrect = 0;
int xorGateCorrect = 0;
for (int i = 0; i <= 1; i++) {
for (int j = 0; j <= 1; j++) {
digitalWrite(a, i);
digitalWrite(b, j);
delay(30);
int output;
switch (gate) {
case 1:
output = digitalRead(op1);
break;
case 2:
output = digitalRead(op2);
break;
case 3:
output = digitalRead(op3);
break;
case 4:
output = digitalRead(op4);
break;
}
int expectedAndOutput = i & j; // AND gate logic
int expectedNandOutput = !(i & j); // NAND gate logic
int expectedOrOutput = i | j; // OR gate logic
int expectedXorOutput = i ^ j; // XOR gate logic
Serial.print("Input A: ");
Serial.print(i);
Serial.print(" | Input B: ");
Serial.print(j);
Serial.print(" | Output: ");
Serial.print(output);
Serial.print(" | AND Exp: ");
Serial.print(expectedAndOutput);
Serial.print(" | NAND Exp: ");
Serial.print(expectedNandOutput);
Serial.print(" | OR Exp: ");
Serial.print(expectedOrOutput);
Serial.print(" | XOR Exp: ");
Serial.println(expectedXorOutput);
// Check if the output matches AND, NAND, OR, and XOR logic
if (output == expectedAndOutput) {
andGateCorrect++;
}
if (output == expectedNandOutput) {
nandGateCorrect++;
}
if (output == expectedOrOutput) {
orGateCorrect++;
}
if (output == expectedXorOutput) {
xorGateCorrect++;
}
}
}
// Determine which gate has more matches for this particular gate
if (andGateCorrect > nandGateCorrect && andGateCorrect > orGateCorrect && andGateCorrect > xorGateCorrect) {
andMatches++;
} else if (nandGateCorrect > andGateCorrect && nandGateCorrect > orGateCorrect && nandGateCorrect > xorGateCorrect) {
nandMatches++;
} else if (orGateCorrect > andGateCorrect && orGateCorrect > nandGateCorrect && orGateCorrect > xorGateCorrect) {
orMatches++;
} else if (xorGateCorrect > andGateCorrect && xorGateCorrect > nandGateCorrect && xorGateCorrect > orMatches) {
xorMatches++;
}
}
// Check if all matches are zero
if (andMatches == 0 && nandMatches == 0 && orMatches == 0 && xorMatches == 0) {
lcd.clear();
lcd.print("No IC Detected");
Serial.println("Result: No IC Detected");
delay(3000); // Hold this display for 3 seconds
detectedIC = IC_UNKNOWN; // Set the detected IC to unknown
return; // Exit the function
}
// Determine IC type based on majority match count
lcd.clear();
if (andMatches > nandMatches && andMatches > orMatches && andMatches > xorMatches) {
detectedIC = IC_AND;
lcd.print("IC: 7408");
Serial.println("Detected IC: AND Gate (7408)");
} else if (nandMatches > andMatches && nandMatches > orMatches && nandMatches > xorMatches) {
detectedIC = IC_NAND;
lcd.print("IC: NAND Gate 7400");
Serial.println("Detected IC: NAND Gate (7400)");
} else if (orMatches > andMatches && orMatches > nandMatches && orMatches > xorMatches) {
detectedIC = IC_OR;
lcd.print("IC: OR Gate 7432");
Serial.println("Detected IC: OR Gate (7432)");
} else if (xorMatches > andMatches && xorMatches > nandMatches && xorMatches > orMatches) {
detectedIC = IC_XOR;
lcd.print("IC: XOR Gate 7486");
Serial.println("Detected IC: XOR Gate (7486)");
} else {
detectedIC = IC_UNKNOWN;
lcd.print("Unknown IC");
Serial.println("IC detection failed: Unknown IC");
}
delay(3000); // Hold the display for 3 seconds
}
// Function to test gates of detected IC (same as in your original code)
void testICGates() {
if (detectedIC == IC_UNKNOWN) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Unknown IC");
Serial.println("Unable to test: IC type unknown");
return;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" TESTING..! ");
lcd.setCursor(0, 1);
lcd.print(" Please wait ^_^ ");
delay(1000); // Hold the testing message for 1 second
bool gateStatus[4] = {true, true, true, true}; // Initialize all gates as good
for (int gate = 1; gate <= 4; gate++) {
Serial.print("Testing Gate ");
Serial.println(gate);
int a, b;
switch (gate) {
case 1:
a = ip1;
b = ip2;
break;
case 2:
a = ip3;
b = ip4;
break;
case 3:
a = ip5;
b = ip6;
break;
case 4:
a = ip7;
b = ip8;
break;
}
for (int i = 0; i <= 1; i++) {
for (int j = 0; j <= 1; j++) {
digitalWrite(a, i);
digitalWrite(b, j);
delay(30);
int output;
switch (gate) {
case 1:
output = digitalRead(op1);
break;
case 2:
output = digitalRead(op2);
break;
case 3:
output = digitalRead(op3);
break;
case 4:
output = digitalRead(op4);
break;
}
int expectedOutput;
if (detectedIC == IC_AND) {
expectedOutput = (i & j); // AND logic
} else if (detectedIC == IC_NAND) {
expectedOutput = !(i & j); // NAND logic
} else if (detectedIC == IC_OR) {
expectedOutput = (i | j); // OR logic
} else if (detectedIC == IC_XOR) {
expectedOutput = (i ^ j); // XOR logic
}
Serial.print("Input A: ");
Serial.print(i);
Serial.print(" | Input B: ");
Serial.print(j);
Serial.print(" | Expected: ");
Serial.print(expectedOutput);
Serial.print(" | Output: ");
Serial.println(output);
if (output != expectedOutput) {
gateStatus[gate - 1] = false;
}
}
}
}
// Check if all gate outputs are zero
bool allOutputsZero = true;
for (int gate = 0; gate < 4; gate++) {
if (gateStatus[gate]) {
allOutputsZero = false;
break;
}
}
if (allOutputsZero) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("No IC Detected");
Serial.println("Result: No IC Detected");
delay(5000); // Hold this display for 5 seconds
return; // Exit the function
}
displayGateResults(gateStatus); // Display final results for each gate
}
// Function to display gate results on the LCD
void displayGateResults(bool gateStatus[]) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("G1:");
lcd.print(gateStatus[0] ? "Good" : "Bad");
lcd.setCursor(8, 0);
lcd.print("G2:");
lcd.print(gateStatus[1] ? "Good" : "Bad");
lcd.setCursor(0, 1);
lcd.print("G3:");
lcd.print(gateStatus[2] ? "Good" : "Bad");
lcd.setCursor(8, 1);
lcd.print("G4:");
lcd.print(gateStatus[3] ? "Good" : "Bad");
Serial.print("G1: ");
Serial.println(gateStatus[0] ? "Good" : "Bad");
Serial.print("G2: ");
Serial.println(gateStatus[1] ? "Good" : "Bad");
Serial.print("G3: ");
Serial.println(gateStatus[2] ? "Good" : "Bad");
Serial.print("G4: ");
Serial.println(gateStatus[3] ? "Good" : "Bad");
delay(3000); // Hold this display for 3 seconds
bool allGood = true;
bool anyGood = false;
for (int i = 0; i < 4; i++) {
if (gateStatus[i]) {
anyGood = true;
} else {
allGood = false;
}
}
lcd.clear();
if (allGood) {
lcd.print("IC is Good");
digitalWrite(greenLED, HIGH);
Serial.println("Result: IC is Good");
} else if (anyGood) {
lcd.print("IC has some");
lcd.setCursor(0, 1);
lcd.print("Good gates");
Serial.println("Result: IC has some good gates");
} else {
lcd.print("IC is Bad");
digitalWrite(redLED, HIGH);
Serial.println("Result: IC is Bad");
}
delay(5000); // Hold this display for 5 seconds
}