The last point is about going bare metal and learning how to use the I/O registers directly. JudgingA small warning first: you have to keep in mind that this is board-specific. You tagged your question with both "arduino-uno" and "arduino-mega", but these boards have different pin mappings (digital 13 is PB7 on the Mega). The general way of using the DDRx, PORTx and PINx registers is the same across all AVR chips, but is not portable to Arduinos based on a different architecture.
So let's assume this is intended to work only on an Uno, Nano, or other board based on an ATmega328P. Judging from the example code you show, you seem to already understand pretty well how these registers work. There is no problem in your code, beside the fact that it requires an external pull-up. If you want to enable the internal pull-up, you have to set the appropriate bit in PORTB. This can seem confusing, as the same register is used for pull-up control (when the pin is in input mode) and for output control (when the pin is an output). Essentially, each GPIO pin has four distinct electrical states which are controlled by to I/O bits:
The last point is about going bare metal and learning how to use the I/O registers directly. Judging from the example code you show, you seem to already understand pretty well how these registers work. There is no problem in your code, beside the fact that it requires an external pull-up. If you want to enable the internal pull-up, you have to set the appropriate bit in PORTB. This can seem confusing, as the same register is used for pull-up control (when the pin is in input mode) and for output control (when the pin is an output). Essentially, each GPIO pin has four distinct electrical states which are controlled by to I/O bits:
The last point is about going bare metal and learning how to use the I/O registers directly. A small warning first: you have to keep in mind that this is board-specific. You tagged your question with both "arduino-uno" and "arduino-mega", but these boards have different pin mappings (digital 13 is PB7 on the Mega). The general way of using the DDRx, PORTx and PINx registers is the same across all AVR chips, but is not portable to Arduinos based on a different architecture.
So let's assume this is intended to work only on an Uno, Nano, or other board based on an ATmega328P. Judging from the example code you show, you seem to already understand pretty well how these registers work. There is no problem in your code, beside the fact that it requires an external pull-up. If you want to enable the internal pull-up, you have to set the appropriate bit in PORTB. This can seem confusing, as the same register is used for pull-up control (when the pin is in input mode) and for output control (when the pin is an output). Essentially, each GPIO pin has four distinct electrical states which are controlled by to I/O bits:
There seem to be several, separate issues in your question.
One is a simple matter of language. In English, "1st" is an abbreviation for "first", which is an ordinal adjective applied to an item in a list meaning that there is no other item before it in that list. In the same vein, "5th" means "fifth", which applies to the item that has exactly four items before it. For instance, the list of pins of port B is {PB0, PB1, PB2, PB3, PB4, PB5}. PB0 is the first in the list, and PB4 is the fifth. The fact the first item bears the number 0 makes this confusing. Thus, I recommend avoiding ordinal adjectives altogether and instead calling the pins by their names, like "digital 13" (Arduino naming) or "PB5" (AVR naming).
The second issue, and probably your main concern, is about the floating
input pin. You cannot expect a reliable reading from a floating input. I
will not try to explain why, as the issue has been discussed ad nauseam
here and elsewhere. Just do a Web search. The simplest solution is to
use the built-in pull-up resistor and externally connect a push button
between the pin and ground. You will read LOW
whenever the button is
pressed:
void setup() {
pinMode(13, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
if (digitalRead(13) == HIGH)
Serial.println("HIGH");
else
Serial.println("LOW");
}
The last point is about going bare metal and learning how to use the I/O registers directly. Judging from the example code you show, you seem to already understand pretty well how these registers work. There is no problem in your code, beside the fact that it requires an external pull-up. If you want to enable the internal pull-up, you have to set the appropriate bit in PORTB. This can seem confusing, as the same register is used for pull-up control (when the pin is in input mode) and for output control (when the pin is an output). Essentially, each GPIO pin has four distinct electrical states which are controlled by to I/O bits:
│ DDRxn │ PORTxn │ state │
├───────┼────────┼──────────────┤
│ 0 │ 0 │ INPUT │
│ 0 │ 1 │ INPUT_PULLUP │
│ 1 │ 0 │ OUTPUT LOW │
│ 1 │ 1 │ OUTPUT HIGH │
└───────┴────────┴──────────────┘
The example program above can be translated to low-level AVR style as follows:
void setup() {
DDRB &= ~_BV(PB5); // input mode
PORTB |= _BV(PB5); // enable pullup
Serial.begin(9600);
}
void loop() {
if (PINB & _BV(PB5))
Serial.println("HIGH");
else
Serial.println("LOW");
}