/* * LM: October 2017 - Idea: Test something for which I don't have a tester already! * January 2021 - First implementation of this idea * - Selected 14-pin DIP devices * * * * License: Creative Commons: https://creativecommons.org/licenses/by/3.0/us/ */ #include #include #define ENCODER_A 3 // Encoder pin A (labeled CLK on rotary encoder) #define ENCODER_B 2 // Encoder pin B (labeled DATA on rotary encoder) // Note: Reversing A & B inverts CW and CCW direction #define ENCODER_BTN A0 // Encoder pushbutton Rotary r = Rotary(ENCODER_A, ENCODER_B); // Instantiate rotary encoder // Display is designed for 16 x 2 LCD but 20 x 4 can be used if 16 x 2 is not available const int ROWS = 2; // If 20x4 change ROWS to 4 const int COLS = 16; // If 20x4 change COLS to 20 LiquidCrystal_I2C lcd(0x27, COLS, ROWS); // Instantiate LCD const unsigned long ONESEC = 1000L; const unsigned long TWOSEC = 2000L; const int NUMBER_OF_ZIF_PINS = 16; const int NUMBER_OF_PWR_PINS = 2; const int NUMBER_OF_IO_PINS = NUMBER_OF_ZIF_PINS - NUMBER_OF_PWR_PINS; // The following ZIF socket pin to Arduino pin mapping may be modified as convenient // ZIF PIN # 1 2 3 4 5 6 7 9 10 11 12 13 14 15 const int ZIF2DIO[NUMBER_OF_IO_PINS] = {1, 0, 4, 5, 6, 7, A1, A2, 8, 9, 10, 11, 12, 13}; // DIO pin # const int NUMBER_OF_ICS = 12; // Start with one chip and add // IC_NAME is shorthand for the IC name and pkgPinmode subscript (pointer to TTL layout type) const unsigned long IC_NAME[NUMBER_OF_ICS][2] = { {7400, 0}, {7402, 4}, {7404, 1}, {7405, 2}, {7407, 2}, {7408, 0}, {7409, 5}, {7410, 6}, {7420, 3}, {7427, 6}, {7432, 0}, {7486, 0} }; // For 14-pin ICs, designate unused ZIF pin as INPUT // Note that Arduino I/O direction is opposite to TTL designation. // TTL input is Arduino output, etc. const int NUMBER_OF_LAYOUTS = 7; // Distinct input-output pin mappings. // Different ICs share the same pinMode layout. int pkgPinmode[NUMBER_OF_LAYOUTS][NUMBER_OF_IO_PINS] = { // ZIF Pin # // 1 2 3 4 5 6 (7) (9) 10 11 12 13 14 15 // [0] Quad 2-input logic gate like 7400, normal output {OUTPUT, OUTPUT, INPUT, OUTPUT, OUTPUT, INPUT, INPUT, INPUT, INPUT, OUTPUT, OUTPUT, INPUT, OUTPUT, OUTPUT}, // [1] Hex driver or inverter, normal output {OUTPUT, INPUT, OUTPUT, INPUT, OUTPUT, INPUT, INPUT, INPUT, INPUT, OUTPUT, INPUT, OUTPUT, INPUT, OUTPUT}, // [2] Hex driver or inverter, open output {OUTPUT, INPUT_PULLUP, OUTPUT, INPUT_PULLUP, OUTPUT, INPUT_PULLUP, INPUT, INPUT, INPUT_PULLUP, OUTPUT, INPUT_PULLUP, OUTPUT, INPUT_PULLUP, OUTPUT}, // [3] Dual 4-input logic gate, normal output - Pins 3 and 11 are NC, so layout is the same as Quad 2-input gate {OUTPUT, OUTPUT, INPUT, OUTPUT, OUTPUT, INPUT, INPUT, INPUT, INPUT, OUTPUT, OUTPUT, INPUT, OUTPUT, OUTPUT}, // [4] Quad 2-input logic gate with pinouts like 7402, normal output {INPUT, OUTPUT, OUTPUT, INPUT, OUTPUT, OUTPUT, INPUT, INPUT, OUTPUT, OUTPUT, INPUT, OUTPUT, OUTPUT, INPUT}, // [5] Quad 2-input logic gate with pinouts like 7400, open output {OUTPUT, OUTPUT, INPUT_PULLUP, OUTPUT, OUTPUT, INPUT_PULLUP, INPUT, INPUT, INPUT_PULLUP, OUTPUT, OUTPUT, INPUT_PULLUP, OUTPUT, OUTPUT}, // [6] Triple 3-input logic gate like 7410, normal output {OUTPUT, OUTPUT, OUTPUT, OUTPUT, OUTPUT, INPUT, INPUT, INPUT, INPUT, OUTPUT, OUTPUT, OUTPUT, INPUT, OUTPUT} }; String ver = "1.0"; String s = ""; // Scratch char failedAt = (char) 0; // Label of first gate or IC section that failed, e.g. 'A', 'B', etc. int selectedIC = 0; // 0 = 7400, 1 = IC_NAME[1][0], etc. int lastSelectedIC = selectedIC; void setup() { pinMode(ENCODER_BTN, INPUT_PULLUP); initPinMode(); // IC test pins connected to ZIF socket lcd.init(); if (ROWS == 2) myDisplayLCD(" TTL Tester " + ver.substring(0,4), " www.lloydm.net"); else if (ROWS == 4) myDisplayLCD(" TTL Tester " + ver.substring(0,4), " www.lloydm.net"); delay(TWOSEC); displaySelectedIC(); // First in IC_NAME list // Next from si5351 iq VFO by OH2BTG // See also: https://forum.arduino.cc/index.php?topic=268200.0 PCICR |= (1 << PCIE2); // Enable pin change interrupt for the encoder PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); } void loop() { if (selectedIC != lastSelectedIC) { displaySelectedIC(); lastSelectedIC = selectedIC; initPinMode(); // All I/O pins to INPUT, except when testing } if (myGetButton()) { // Request to test the selected IC failedAt = (char) 0; // Clear icPinMode(lastSelectedIC); displayTestingIC(); boolean notImplemented = false, passed = false; if (lastSelectedIC == icIEN(7400)) passed = test7400(); else if (lastSelectedIC == icIEN(7402)) passed = test7402(); else if (lastSelectedIC == icIEN(7404)) passed = test7404(); else if (lastSelectedIC == icIEN(7405)) passed = test7405(); else if (lastSelectedIC == icIEN(7407)) passed = test7407(); else if (lastSelectedIC == icIEN(7408)) passed = test7408(); else if (lastSelectedIC == icIEN(7409)) passed = test7409(); else if (lastSelectedIC == icIEN(7410)) passed = test7410(); else if (lastSelectedIC == icIEN(7420)) passed = test7420(); else if (lastSelectedIC == icIEN(7427)) passed = test7427(); else if (lastSelectedIC == icIEN(7432)) passed = test7432(); else if (lastSelectedIC == icIEN(7486)) passed = test7486(); else notImplemented = true; delay(ONESEC); if (notImplemented) myDisplayLCD("","Not implemented!"); else if (passed) myNoEraseDisplay(1, 6, "... passed"); else { s = "Section "; s.concat(failedAt); s.concat(" failed"); myNoEraseDisplay(1, 0, s); } } } void next_74xx() { selectedIC++; if (selectedIC >= NUMBER_OF_ICS) selectedIC = 0; } void prev_74xx() { selectedIC--; if (selectedIC < 0) selectedIC = NUMBER_OF_ICS - 1; } void displaySelectedIC() { // Revise if IC name is > 4 digits in length s = "IC "; s.concat(String(IC_NAME[selectedIC][0])); s.concat(" selected"); myDisplayLCD(s,""); } void displayTestingIC() { s = "Testing IC "; s.concat(String(IC_NAME[selectedIC][0])); myDisplayLCD(s,""); } /****************************************/ /* Interrupt service routine for */ /* rotary encoder TTL 74xx selection */ /* Adapted from si5351 iq VFO by OH2BTG */ /****************************************/ ISR(PCINT2_vect) { unsigned char result = r.process(); if (result == DIR_CW) next_74xx(); else if (result == DIR_CCW) prev_74xx(); } // LM: Adapted from previous projects - boolean myGetButton() { // Encoder (step) button is not excessively noisy if (!digitalRead(ENCODER_BTN)) { while (!digitalRead(ENCODER_BTN)); ; return true; } return false; } void myDisplayLCD(String line1, String line2) { int row = ROWS/2 - 1; // Same as if..else lcd.clear(); lcd.setCursor(0, row); lcd.print(line1); lcd.setCursor(0, row+1); lcd.print(line2); lcd.backlight(); } void myNoEraseDisplay(int row, int col, String s) { row += (ROWS/2 - 1); // Same as if..else lcd.setCursor(col, row); lcd.print(s); } // LM: New void initPinMode() { // Set all test pins to INPUT when not testing for (int j=0; j