Skip to main content
Arduino

Return to Answer

+ warning about AVR-specific stuff.
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

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:

Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

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");
}
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /