CD4021 is a synchronous shift register. It requires a clock for both serial shifts and parallel loads. You're not clocking the load.
To latch parallel data:
- Set PAR/#SER to 1 (par).
- Toggle the clock (0, then 1) to latch.
To shift serial data:
- Set PAR/#SER to 0 (ser).
- Read Q7 and shift into the variable.
- Toggle the clock (0, then 1).
- Repeat 2-3 a total of 8 times.
Readable C code for that might look as follows:
#include <avr/cpufunc.h> static __attribute__((noinline)) void SR_DELAY(void) { _NOP(); _NOP(); _NOP(); _NOP(); } #define SR_PAR() do { PORTD |= 0x80; SR_DELAY(); } while (0) #define SR_SER() do { PORTD &= ~0x80; SR_DELAY(); } while (0) #define SR_CLK_PULSE() do { PORTD &= ~0x40; SR_DELAY(); PORTD |= 0x40; SR_DELAY(); } while (0) #define SR_BIT() (PIND & 0x10) uint8_t read_controller() { SR_PAR(); SR_CLK_PULSE(); SR_SER(); uint8_t result = 0; for (uint8_t i = 0; i < 8; ++i) { if (SR_BIT()) result |= 1; result <<= 1; SR_CLK_PULSE(); } return result; } ```