This program is stateless. Each key and switch has a defined action.
The information on the display is limited to 4 rows and 10 columns in order to use the better-looking Adafruit 9-point font.
On boot the display on the photograph appears.
The keys with letters and all the other keys each have defined functions:
The UP switch selects the entry lower in alphabetical order.
The DOWN switch selects the entry higher in alphabetical order.
Any change in the site selection triggers a display of site name and password.
Power also times out, with the countdown reset on any selection change.
/*PassworShow
Operation:
Switch UP = Power On Key * = power OFF
Key # = display battery voltage
Keys 2 - 9 = load corresponding files K02.txt - K09.txt into memory
Switch DOWN = show next record syte name
Switch UP = show preious record syte name
Key 0 = go to first record
Key 1 = show username and password
John aunders 2/9/2025
*/
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "Fonts/FreeMono9pt7b.h"
#include “masterTables.h”
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define COL_1_PIN 2 //connections to the 4x3 matrixed keypad
#define COL_2_PIN 3
#define COL_3_PIN 5
#define ROW_1_PIN 6
#define ROW_2_PIN 7
#define ROW_3_PIN 8
#define ROW_4_PIN 9
#define swUp_PIN A0
#define TEST_PIN A1
#define swDown_PIN A2
#define SDCARD_SS_PIN 10
#define POWER_PIN 4
#define LOOP_DELAY 100
#define SHUTDOWN_LOOPS 150
const int numFiles = 8;
char SD_ID = ' ';
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
File myFile;
char fileContent[15][35];
String filenames[numFiles] = {
// 0 1 2 3 4 5 6 7
"K02.txt", "K03.txt", "K04.txt", "K05.txt", "K06.txt", "K07.txt", "K08.txt", "K09.txt"
};
const float refVolt = 4.975;
const int colPins[3] = {COL_1_PIN, COL_2_PIN, COL_3_PIN};
const int rowPins[4] = {ROW_1_PIN, ROW_2_PIN, ROW_3_PIN, ROW_4_PIN};
int row0 = 10;
int row3 = 43;
struct keys {
int col_inx;
int row_inx;
char keyChar;
};
const keys keyVals[12] = { //The index of this table is the result
{0, 0, '1'}, {1, 0, '2'}, {2, 0, '3'},
{0, 1, '4'}, {1, 1, '5'}, {2, 1, '6'},
{0, 2, '7'}, {1, 2, '8'}, {2, 2, '9'},
{0, 3, '*'}, {1, 3, '0'}, {2, 3, '#'}
};
void setup() {
// Open serial communications and wait for port to open:
for (int l = 0; l < 4; l++) {
pinMode(rowPins[l], INPUT_PULLUP); //Stop polling is a key is depressed
}
for (int m = 0; m < 3; m++) {
pinMode(colPins[m], OUTPUT); //Stop polling is a key is depressed
}
pinMode(swUp_PIN, INPUT_PULLUP);
pinMode(swDown_PIN, INPUT_PULLUP);
pinMode(POWER_PIN, OUTPUT);
digitalWrite(POWER_PIN, HIGH);
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.setRotation(2);
display.setFont(&FreeMono9pt7b);
display.setTextColor(WHITE);
display.clearDisplay();
display.setCursor(0, row0);
if (!SD.begin(SDCARD_SS_PIN)) {
display.println("No SD Card");
display.display();
delay(3000);
digitalWrite(POWER_PIN, LOW);
while (1);
}
myFile = SD.open("ID.TXT", FILE_READ);
if (myFile) {
SD_ID = myFile.read();
myFile.close();
if (SD_ID == 'F') {
display.print("SD card ID is ");
display.println(SD_ID);
display.setCursor(0, row3);
display.println("Press a lettter key");
display.display();
}
else {
display.print("Wrong SD card:");
display.println(SD_ID);
display.display();
delay(9000);
digitalWrite(POWER_PIN, LOW);
while (1);
}
}
}
void loop() {
static int numSites = 0;
static int siteInx = 100;
static int oldInx = 100;
static int upTic = 1;
static int downTic = 1;
static int loopCount = 0;
char key;
int swVal;
if(loopCount++ > SHUTDOWN_LOOPS) {
digitalWrite(POWER_PIN, LOW);
while (1);;
}
key = getKey();
if ((key >= '2') && (key <= '9')) {
numSites = readFile(key);
siteInx = numSites / 2;
}
if ((siteInx != oldInx) && (numSites > 0)) {
showSiteName(siteInx);
oldInx = siteInx;
loopCount = 0;
}
if ((key == '1') && (numSites > 0)) {
showSitePassword(siteInx);
}
if (key == '*') {
digitalWrite(POWER_PIN, LOW);
while (1);
}
if (key == '0') {
siteInx = 0;
}
if (key == '#') {
showStatus();
}
swVal = digitalRead(swUp_PIN);
if ((swVal == 0) && (upTic == 1)) {
siteInx--;
loopCount = 0;
if (siteInx < 0) {
siteInx = numSites - 1;
}
}
upTic = swVal;
swVal = digitalRead(swDown_PIN);
if ((swVal == 0) && (downTic == 1)) {
siteInx++;
loopCount = 0;
if (siteInx >= numSites) {
siteInx = 0;
}
}
downTic = swVal;
delay(LOOP_DELAY);
}
char getKey(void) { //130 microsec for no key pressed
int keyIndex = 12; //Default output if no key depressed
int selRow = 4;
int selCol = 3;
int i, j;
bool tic; //True if a key has ben depressed
char retVal = 'z';
tic = false;
for (i = 0; i < 3; i++) {
digitalWrite(colPins[i], LOW); //Poll the columns
for (j = 0; j < 4; j++) {
if (digitalRead(rowPins[j]) == LOW) { // A key press goes to 2.4 milliseconds
selRow = j;
selCol = i;
tic = true;
break; //When a key press is detected
}
}
digitalWrite(colPins[i], HIGH); //Stop polling is a key is depressed
}
if (tic) { //Find the match if a key press detected
for (int k = 0; k < 12; k++) {
if ((selRow == keyVals[k].row_inx) && (selCol == keyVals[k].col_inx)) {
keyIndex = k;
retVal = keyVals[keyIndex].keyChar;
break;
}
}
}
return retVal;
}
void showStatus(void) {
int raw;
float battVolt;
raw = analogRead(TEST_PIN);
battVolt = ((float)raw * refVolt) / 512.0;
display.clearDisplay();
display.setCursor(0, row0);
display.print("Battery = ");
display.print(battVolt, 2);
display.println(" V");
display.display();
}
int readFile(char fileChar) {
char readVal;
int charIndex = 0;
int siteIndex = 0;
int fileInx = fileChar - '2';
myFile = SD.open(filenames[fileInx]);
if (myFile) {
while (myFile.available()) {
readVal = myFile.read();
fileContent[siteIndex][charIndex++] = readVal;
if (readVal == '\n') {
fileContent[siteIndex][charIndex] = 0;
siteIndex++;
charIndex = 0;
}
}
myFile.close();
}
return siteIndex;
}
void showSiteName(int siteIndex) {
int charIndex = 6;
int indx;
display.clearDisplay();
display.setCursor(0, row0);
do {
display.write(fileContent[siteIndex][charIndex]);
} while (fileContent[siteIndex][charIndex++] > 0);
display.setCursor(0, row3);
indx = 10 * fileContent[siteIndex][2] + fileContent[siteIndex][3] - 528;
display.print(plates[indx]);
indx = 10 * fileContent[siteIndex][4] + fileContent[siteIndex][5] - 528;
display.println(caps[indx]);
display.display();
}
void showSitePassword(int siteIndex) {
int indx;
display.clearDisplay();
display.setCursor(0, row0);
indx = 10 * fileContent[siteIndex][0] + fileContent[siteIndex][1] - 528;
display.println(unames[indx]);
display.setCursor(0, row3);
indx = 10 * fileContent[siteIndex][2] + fileContent[siteIndex][3] - 528;
display.print(plates[indx]);
indx = 10 * fileContent[siteIndex][4] + fileContent[siteIndex][5] - 528;
display.println(caps[indx]);
display.display();
}