Skip to content

Instantly share code, notes, and snippets.

@X3msnake
Last active June 2, 2025 15:50
Show Gist options
  • Save X3msnake/486318a4bb46f73e65e2fa581b72904b to your computer and use it in GitHub Desktop.
Save X3msnake/486318a4bb46f73e65e2fa581b72904b to your computer and use it in GitHub Desktop.

Bayamo hand dryer reverse engineering

Counter board

image SN74HC164 GD-4021LB

IR Led Barrier

image Infrared Sensor: IRM-56384


/*

http://www.bristolwatch.com/arduino/arduino3.htm
Connecting Arduino to a 74C164 Shift Register
Lewis Loflin [email protected]

Demo to shift byte into 74HC164
8-Bit Serial-In - Parallel-Out Serial Shift Register
Will count from 0 to 255 in binary on eight LEDs

The 74HC164 has three inputs:

Input A-B (pins 1, 2) is for data. they can be tied
together or the one not used tied to +Vcc

Clock pin 8 data is serially shifted in and
out of the 8-bit register during
the positive going transition of clock pulse.

Clear (pin 9) is independent of the clock
and accomplished by a low level at the
clear input.

As far as LSB first or MSB bit first is up to software
and electrical connections on the output

*/

#define DATA 12
#define CLK 11
#define CLR 9
#define VCC 2
#define SIG A0
#define RLAY 6

#define OFF 0
#define ON 1

unsigned long startMillis;  // some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  // the value is a number of milliseconds

byte i, j, temp, val;

int data[] = {2, 62, 72, 40, 52, 160, 128, 50, 0, 32};

void setup() {
  pinMode(DATA, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(CLR, OUTPUT);
  pinMode(VCC, OUTPUT);
  pinMode(SIG, INPUT_PULLUP);
  pinMode(RLAY, OUTPUT);

  pinMode(13, OUTPUT);  // used to test-debug various sections of code

  digitalWrite(CLK, OFF);
  digitalWrite(CLR, OFF); // active LOW
  digitalWrite(VCC, ON);

  startMillis = millis();  // initial start time

  Serial.begin(115200); // open the serial port at 9600 bps:

  resetDigits();
}

void loop() {
  
  digitalWrite(13, OFF); // Debug LED 
  digitalWrite(RLAY, OFF); // PowerRelay
  delay(500);
    
  if (!digitalRead(SIG)) {
    digitalWrite(13, ON); // Debug LED
    digitalWrite(RLAY, ON); // PowerRelay

    handleInfraredSensor();
  }
  
}

void handleInfraredSensor() {

  unsigned long previousMillis = millis();
  unsigned long interval = 0; // Adjust this interval as needed

  int number = 60;
  int digit1 = 0;
  int digit2 = 0;

  while (number > 0) {
    if (millis() - previousMillis >= interval) {
      previousMillis = millis();  // Save the last time the digit was updated

      digit1 = number / 10; // First digit of the number
      digit2 = number % 10; // Second digit of the number

      // Display the same count number on both digits
      for (int count = 0; count < 50; count++) {
        digitalWrite(CLR, HIGH); // Select first 7-segment display
        val = data[digit1]; // Set value for the first 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the first digit for a short time

        digitalWrite(CLR, LOW); // Select second 7-segment display
        val = data[digit2]; // Set value for the second 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the second digit for a short time
      }

      number--;
     }
     resetDigits();
   }
 }


void shiftData(byte val) {
  for (j = 0; j < 8; j++) {
    temp = (val >> j) & 0x01;
    digitalWrite(DATA, temp);
    pulsout(CLK, 0);
  }
}

void resetDigits(){
     digitalWrite(CLR, LOW); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
     digitalWrite(CLR, HIGH); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
}

// inverts state of pin, delays, then reverts state back
void pulsout(byte x, int y) {
  byte z = digitalRead(x);
  z = !z;
  digitalWrite(x, z);
  delayMicroseconds(y);
  z = !z; // return to original state
  digitalWrite(x, z);
  return;
} // end pulsout()


image image


image

@X3msnake
Copy link
Author

X3msnake commented Feb 12, 2024

First Version Merged Code (DEPRECATED)

With the help of Copilot


#define DATA 12
#define CLK 11
#define CLR 9
#define VCC 2
#define RLAY 6

#define OFF 0
#define ON 1

const int analogPinA0 = A0;
const int analogPinA1 = A1;
const int analogPinA2 = A2;

unsigned long startMillis;  // some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  // the value is a number of milliseconds

byte i, j, temp, val;

int data[] = {2, 62, 72, 40, 52, 160, 128, 50, 0, 32};

void setup() {
  pinMode(DATA, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(CLR, OUTPUT);
  pinMode(VCC, OUTPUT);
  pinMode(RLAY, OUTPUT);

  pinMode(13, OUTPUT);  // used to test-debug various sections of code

  digitalWrite(CLK, OFF);
  digitalWrite(CLR, OFF); // active LOW
  digitalWrite(VCC, ON);

  startMillis = millis();  // initial start time

  Serial.begin(115200); // open the serial port at 9600 bps:

  resetDigits();
}

void loop() {
  
  digitalWrite(13, OFF); // Debug LED 
  digitalWrite(RLAY, OFF); // PowerRelay
  delay(500);
    
  // Read voltages from analog pins
  float voltageA0 = analogRead(analogPinA0) * (5.0 / 1023.0);
  float voltageA1 = analogRead(analogPinA1) * (5.0 / 1023.0);
  float voltageA2 = analogRead(analogPinA2) * (5.0 / 1023.0);

  // Check if any voltage is lower than 3 volts
  if (voltageA0 < 3.0 || voltageA1 < 3.0 || voltageA2 < 3.0) {
    digitalWrite(13, ON); // Debug LED
    digitalWrite(RLAY, ON); // PowerRelay

    handleInfraredSensor();
  }
  
}

void handleInfraredSensor() {

  unsigned long previousMillis = millis();
  unsigned long interval = 0; // Adjust this interval as needed

  int number = 30;
  int digit1 = 0;
  int digit2 = 0;

  while (number > 0) {
    if (millis() - previousMillis >= interval) {
      previousMillis = millis();  // Save the last time the digit was updated

      digit1 = number / 10; // First digit of the number
      digit2 = number % 10; // Second digit of the number

      // Display the same count number on both digits
      for (int count = 0; count < 50; count++) {
        digitalWrite(CLR, HIGH); // Select first 7-segment display
        val = data[digit1]; // Set value for the first 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the first digit for a short time

        digitalWrite(CLR, LOW); // Select second 7-segment display
        val = data[digit2]; // Set value for the second 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the second digit for a short time
      }

      number--;
     }
     resetDigits();
   }
 }


void shiftData(byte val) {
  for (j = 0; j < 8; j++) {
    temp = (val >> j) & 0x01;
    digitalWrite(DATA, temp);
    pulsout(CLK, 0);
  }
}

void resetDigits(){
     digitalWrite(CLR, LOW); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
     digitalWrite(CLR, HIGH); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
}

// inverts state of pin, delays, then reverts state back
void pulsout(byte x, int y) {
  byte z = digitalRead(x);
  z = !z;
  digitalWrite(x, z);
  delayMicroseconds(y);
  z = !z; // return to original state
  digitalWrite(x, z);
  return;
} // end pulsout()

@X3msnake
Copy link
Author

X3msnake commented Feb 12, 2024

@X3msnake
Copy link
Author

X3msnake commented Jun 2, 2025

New version with active shutdown after 5 inactive seconds and timer rollback if the motion is still active

// ------------------------------------------------------------------------
// Code design by X3msnake and ChatGPT OpenAI o4-mini.
// Version: 2.250602
// ------------------------------------------------------------------------

#define DATA   12 
#define CLK    11
#define CLR     9
#define VCC     2
#define RLAY    6

#define OFF     0
#define ON      1

const int analogPinA0 = A0;
const int analogPinA1 = A1;
const int analogPinA2 = A2;

// “Standard” 7‐segment bit patterns (unchanged)
int data[] = { 
  2,    // 0
  62,   // 1
  72,   // 2
  40,   // 3
  52,   // 4
  160,  // 5
  128,  // 6
  50,   // 7
  0,    // 8
  32    // 9
};

// ------------------------------------------------------------------------
//  ––  LOWER‐LEVEL DISPLAY / SHIFT‐REGISTER CODE (UNCHANGED) ––
// ------------------------------------------------------------------------

void pulsout(byte x, int y) {
  byte z = digitalRead(x);
  z = !z;
  digitalWrite(x, z);
  delayMicroseconds(y);
  z = !z;
  digitalWrite(x, z);
}

void shiftData(byte val) {
  for (byte j = 0; j < 8; j++) {
    byte bitVal = (val >> j) & 0x01;
    digitalWrite(DATA, bitVal);
    pulsout(CLK, 0);
  }
}

void resetDigits() {
  digitalWrite(CLR, LOW);
  shiftData(B11111111);
  digitalWrite(CLR, HIGH);
  shiftData(B11111111);
}

// ------------------------------------------------------------------------
//  ––  GLOBAL VARIABLES FOR THE NON‐BLOCKING COUNTDOWN FSM ––
// ------------------------------------------------------------------------

enum State {
  IDLE,
  COUNTDOWN
};

State currentState = IDLE;
int  currentNumber = 30;

unsigned long lastCountMillis    = 0;   // when we last did “--currentNumber”
unsigned long lastRefreshMillis  = 0;   // when we last toggled the display digit
unsigned long sensorAboveMillis  = 0;   // when all sensors first went ≥ 3V

// NEW: remember last time any sensor was < 3V
unsigned long lastSensorActiveMillis = 0;

// 0 = tens digit, 1 = ones digit
byte displayDigit = 0;

const unsigned long refreshInterval    = 10;    // 10 ms per half‐cycle
const unsigned long countdownInterval  = 1000;  // 1 000 ms = 1 s per step
const unsigned long abortThreshold     = 5000;  // sensors ≥ 3 V for 5 s → abort

// ------------------------------------------------------------------------
//  ––  Arduino SETUP() ––
// ------------------------------------------------------------------------

void setup() {
  pinMode(DATA, OUTPUT);
  pinMode(CLK,  OUTPUT);
  pinMode(CLR,  OUTPUT);
  pinMode(VCC,  OUTPUT);
  pinMode(RLAY, OUTPUT);

  pinMode(13, OUTPUT);            
  digitalWrite(CLK, OFF);
  digitalWrite(CLR, OFF);         
  digitalWrite(VCC, ON);

  Serial.begin(115200);
  resetDigits();
}

// ------------------------------------------------------------------------
//  ––  Arduino LOOP() ––
// ------------------------------------------------------------------------

void loop() {
  // 1) Read voltages (0…5 V) from the three analog pins:
  float voltageA0 = analogRead(analogPinA0) * (5.0 / 1023.0);
  float voltageA1 = analogRead(analogPinA1) * (5.0 / 1023.0);
  float voltageA2 = analogRead(analogPinA2) * (5.0 / 1023.0);

  unsigned long now = millis();

  // ─────────────────────────────
  // NEW: If ANY sensor is < 3 V right now,
  // record “last‐active” timestamp:
  if (voltageA0 < 3.0 || voltageA1 < 3.0 || voltageA2 < 3.0) {
    lastSensorActiveMillis = now;
  }
  // ─────────────────────────────

  switch (currentState) {
    // ============================================
    //   IDLE STATE: WAIT FOR ANY SENSOR < 3 V
    // ============================================
    case IDLE:
      digitalWrite(13, OFF);
      digitalWrite(RLAY, OFF);
      resetDigits();

      if (voltageA0 < 3.0 || voltageA1 < 3.0 || voltageA2 < 3.0) {
        currentState      = COUNTDOWN;
        currentNumber     = 30;
        lastCountMillis   = now;
        lastRefreshMillis = now;
        sensorAboveMillis = 0;
        displayDigit      = 0;
        digitalWrite(13, ON);
        digitalWrite(RLAY, ON);
      }
      break;


    // ============================================
    //   COUNTDOWN STATE: NON‐BLOCKING 30 → 1
    // ============================================
    case COUNTDOWN:
      // 1) Check if all three sensors are ≥ 3 V:
      if (voltageA0 >= 3.0 && voltageA1 >= 3.0 && voltageA2 >= 3.0) {
        if (sensorAboveMillis == 0) {
          sensorAboveMillis = now;
        }
        else if (now - sensorAboveMillis >= abortThreshold) {
          // ABORT: go back to IDLE immediately
          currentState      = IDLE;
          sensorAboveMillis = 0;
          resetDigits();
          return;
        }
      }
      else {
        sensorAboveMillis = 0;
      }

      // 2) Has 1 s passed since last countdown step?
      if (now - lastCountMillis >= countdownInterval) {
        lastCountMillis += countdownInterval;
        currentNumber--;

        // ───────────────────────────────────────────────────────────────────────
        // MODIFIED: when countdown hits zero, check “lastSensorActiveMillis”:
        if (currentNumber <= 0) {
          // If any sensor was active in the last 2 000 ms, restart countdown:
          if (lastSensorActiveMillis != 0 && (now - lastSensorActiveMillis) <= 2000) {
            currentNumber     = 30;
            lastCountMillis   = now;
            lastRefreshMillis = now;
            // keep relay + LED ON (stay in COUNTDOWN)
            return;
          }
          // Else truly finish:
          currentState = IDLE;
          resetDigits();
          digitalWrite(13, OFF);
          digitalWrite(RLAY, OFF);
          return;
        }
        // ───────────────────────────────────────────────────────────────────────
      }

      // 3) Every ~10 ms, flip between tens / ones digit:
      if (now - lastRefreshMillis >= refreshInterval) {
        lastRefreshMillis += refreshInterval;

        byte digitValue;
        if (displayDigit == 0) {
          digitalWrite(CLR, HIGH);  
          digitValue = data[currentNumber / 10];
        }
        else {
          digitalWrite(CLR, LOW);
          digitValue = data[currentNumber % 10];
        }
        shiftData(digitValue);
        displayDigit = 1 - displayDigit;
      }

      // Keep LED + relay ON throughout this state
      digitalWrite(13, ON);
      digitalWrite(RLAY, ON);
      break;
  }
}

https://chatgpt.com/share/683dade2-a8b0-8000-9c16-d6d5951f0d83

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment