// 준비중인 시뮬레이터 링크 : https://wokwi.com/projects/446010214971010049
/*
* 74HC165 Switch Input Reader - Reading Book Style
*
* Wiring Connections:
* ┌─────────────────┬──────────┬─────────────────────────┐
* │ 74HC165 │ Pin │ Arduino Connection │
* ├─────────────────┼──────────┼─────────────────────────┤
* │ Q7 (Serial Out) │ 9 │ D2 │
* │ CP (Clock) │ 2 │ D3 │
* │ PL (Load) │ 1 │ D4 │
* │ CE (Enable) │ 15 │ GND (Always Active) │
* │ VCC │ 16 │ 5V │
* │ GND │ 8 │ GND │
* └─────────────────┴──────────┴─────────────────────────┘
*
* Switch Connections: D0~D7 -> 10kΩ Pull-up -> 5V (외부 저항 필수!)
* Switch -> GND (Active Low)
*
* ⚠️ 주의: Arduino 내장 Pull-up(INPUT_PULLUP)은 사용 불가!
* 74HC165는 독립된 IC이므로 외부 Pull-up 저항 필수
*/
const int PIN_DATA = 2;
const int PIN_CLOCK = 3;
const int PIN_LOAD = 4;
const unsigned long READ_INTERVAL = 100;
const int TOTAL_SWITCHES = 8;
unsigned long previous_millis = 0;
byte switch_data = 0;
byte previous_switch_data = 0xFF;
void setup()
{
configure_hardware_pins();
configure_initial_pin_states();
configure_serial_communication();
display_welcome_message();
}
void loop()
{
if (is_time_to_read_switches())
{
update_current_time_stamp();
perform_switch_reading_sequence();
}
}
void configure_hardware_pins()
{
pinMode(PIN_DATA, INPUT);
pinMode(PIN_CLOCK, OUTPUT);
pinMode(PIN_LOAD, OUTPUT);
}
void configure_initial_pin_states()
{
digitalWrite(PIN_CLOCK, LOW);
digitalWrite(PIN_LOAD, HIGH);
}
void configure_serial_communication()
{
Serial.begin(9600);
}
void display_welcome_message()
{
Serial.println("74HC165 Switch Input Reader - Reading Book Style");
Serial.println("Monitoring 8 switches");
Serial.println("--------------------------------------------------");
}
bool is_time_to_read_switches()
{
unsigned long current_millis = millis();
return (current_millis - previous_millis >= READ_INTERVAL);
}
void update_current_time_stamp()
{
previous_millis = millis();
}
void perform_switch_reading_sequence()
{
load_parallel_data_into_register();
read_serial_data_from_register();
process_switch_data_if_changed();
}
void load_parallel_data_into_register()
{
set_load_pin_low();
wait_for_data_stabilization();
set_load_pin_high();
}
void set_load_pin_low()
{
digitalWrite(PIN_LOAD, LOW);
}
void wait_for_data_stabilization()
{
delayMicroseconds(5);
}
void set_load_pin_high()
{
digitalWrite(PIN_LOAD, HIGH);
}
void read_serial_data_from_register()
{
switch_data = 0;
// 74HC165는 클록 전에 비트가 준비되어 있음 (D7 먼저 출력됨)
for (int i = 7; i >= 0; i--)
{
int bit = digitalRead(PIN_DATA);
switch_data |= (bit << i);
digitalWrite(PIN_CLOCK, HIGH);
digitalWrite(PIN_CLOCK, LOW);
}
}
void process_switch_data_if_changed()
{
if (has_any_switch_state_changed())
{
display_all_switch_states();
remember_current_switch_states();
}
}
bool has_any_switch_state_changed()
{
return (switch_data != previous_switch_data);
}
void display_all_switch_states()
{
print_switch_states_header();
print_each_switch_status();
print_raw_binary_data();
print_line_ending();
}
void print_switch_states_header()
{
Serial.print("Switch States: ");
}
void print_each_switch_status()
{
for (int i = 0; i < TOTAL_SWITCHES; i++)
{
print_single_switch_status(i);
}
}
void print_single_switch_status(int switch_index)
{
print_switch_label(switch_index);
print_switch_state(switch_index);
}
void print_switch_label(int switch_index)
{
Serial.print("SW");
Serial.print(switch_index);
Serial.print(":");
}
void print_switch_state(int switch_index)
{
bool is_switch_pressed = is_switch_pressed_at_index(switch_index);
if (is_switch_pressed)
{
print_switch_on_state();
}
else
{
print_switch_off_state();
}
}
bool is_switch_pressed_at_index(int index)
{
byte bit_value = (switch_data >> index) & 0x01;
return !bit_value;
}
void print_switch_on_state()
{
Serial.print("ON ");
}
void print_switch_off_state()
{
Serial.print("OFF ");
}
void print_raw_binary_data()
{
Serial.print(" | Raw: 0b");
// 8비트 형식으로 출력 (앞에 0 표시)
for (int i = 7; i >= 0; i--)
{
Serial.print((switch_data >> i) & 0x01);
}
Serial.print(" (0x");
Serial.print(switch_data, HEX);
Serial.print(")");
}
void print_line_ending()
{
Serial.println();
}
void remember_current_switch_states()
{
previous_switch_data = switch_data;
}