Using the internal I/O registers of an Arduino directly

I am trying to use the Arduino I/O registers directly. I have a switch connected to Arduino pin 5 (pin PD5) and an LED is connected to Arduino pin 2 (pin PD2). The objective is to have the LED glow when the switch is pressed. PD5 is configured as an input with internal pull-up resistor activated.

When I am coding with digitalRead() and digitalWrite() functions, the code works just fine. But when I am trying to use the internal registers DDRx, PORTx and PINx, the code is not working correctly. The LED remains ON even when the switch is not pressed. My code is given below.

uint8_t x;

void setup() {
  // put your setup code here, to run once:
  
DDRD = (0<<DDD7)|(0<<DDD6)|(0<<DDD5)|(0<<DDD4)|(0<<DDD3)|(1<<DDD2); //PD5 input/ PD2 output
PORTD = 0b11111000; //pull up resistor activated for PD5
}

void loop() {
  // put your main code here, to run repeatedly:

x = PIND;

if((x & (0b00100000)) == 0)
{
   delay(20);
   if((x & (0b00100000)) == 0)
   {
    PORTD = (1<<PORTD2);
   }
}
else
{
  PORTD = (0<<PORTD2);
}

}

What is wrong in my code??? Please help...

Your write to PORTD disabled the internal pull-up. You want use read-modify-write.

This is a bit rough because it set the whole port when you want to set only one bit.

PORTD = (1<<PORTD2) ;

Try something like

PORTD |= (1<<PORTD2) ; sets 1 bit

or

PORTD &= ~(1<<PORTD2) ; clears 1 bit

Isn't that the same as a microchip PIC read write modified error?

6v6gt:
Try something like
PORTD |= (1<<PORTD2) ; sets 1 bit

That operation is non-atomic. Therefore, it is not interrupt-safe. Suppose an interrupt occurs after PORTD is read but before it is rewritten. If the ISR for that interrupt modifies the contents of PORTD, then after it exits your code will corrupt that change when it writes back the value with Bit 2 set.

Use:

  noInterrupts();
  PORTD |= (1 << PORTD2);
  interrupts();

On AVRs settings or clearing single bit in some registers (such as I/O related) is atomic.
Disabling interrupts is needed only when some interrupt changes the register.

The compiler uses the sbi, cbi instructions when dealing with the i/o registers.

int
main ()
{

	PORTB |= ( _BV( PB5 ) );
  80:	2d 9a       	sbi	0x05, 5	; 5
	
	PORTB &= ~( _BV( PB5 ) );
  82:	2d 98       	cbi	0x05, 5	; 5
	
}