Relationship among PORTX, PINX, DDRX, pinMode(), .... of Arduino

4.2 Relationship among PORTX, PINX, DDRX; pinMode(); digitalWrite(), bitSet(), bitClear(), bitWrite(); digitalRead(), bitRead(); PORTX = 0xNN, DDRX = 0xNN

1. PORTB: PORTB stands for Port-B Register (PBR). It is a latch type (Flip-flop) register; it receives data from the Processor Unit (PU) for the output port-lines (PB5-PB0). We may recognize PORTB as a 'Data Transmission Register' for those port-lines which have been configured to work as output. In the present case, we have only one output port-line (PB5).

There is no internal pull-up resistor associated with an output port-line.

2. PINB: PINB stands for Pin-B Register. It receives data from the pins of the input port-lines (PB5-PB0). We may recognize PINB as a 'Data Reception Register' for those port-lines which have been configured to work as input. In the present case, we have only one input port-line (PB0).

Every input port-line is associated with an internal pull-up resistor, which (by default) remains disconnected. It can be connected with input line using program instruction.

3. DDRB: The full-name of DDRB is Data Direction Register for port-lines (PB5-PB0). This register helps to set the directions of the IO lines (port-lines) either as input or output depending on the requirement.

To set the direction of a port-line (say, PB5) as output, we write LH (1) at the corresponding bit (DDRB5) of the DDRB register. To set direction as input, we store LL (0) at the corresponding bit of DDRB.

4. Setting Direction of Port-line:
(a) To set the the direction of a single port-line (PB5) as output, we use the following function:
pinMode(DPin, value);
===> pinMode(13, HIGH);

(b) To set the the direction of a single port-line (PB0) as input with internal pull-up resistor
connected, we use the following function:
pinMode(DPin, value);
===> pinMode(8, INPUT_PULLUP);

(c) To set the the direction of all the six (6) port-lines (PB5-PB0) as output at the same time, we
take the help of DDRB register and use the following assignment statement:
DDRB = B00111111; //Leading two zeros are padding bits; B is notation for binary
===> DDRB = 0xFF; //0x is notation for hexadecimal number.

(d) To set the the direction of all the six (6) port-lines (PB5-PB0) as input (without internal pull-up
register) at the same time, we take the help of DDRB register and use the following assignment
statement:
DDRB = B00000000;
===> DDRB = 0x00;

(e) To connect internal pull-up resistors with all the input port-lines (PB5-PB0) of Step-4d, we use the
following assignment statements:
DDRB = B00000000; // port-pins must be set as inputs
PORTB = B00111111; // 1s should be written to PORTB see Figure-2
LL ---> PUD-bit (Bit-4) of MCUCR; bitClear (MCUCR, 4); //see Figure-2

(f) In summary: (due to CrossRoads of Arduino Forum)
Or just use one of these in setup(), easier to remember and not mess it up:
pinMode (pinX, INPUT); // pinX = 0 to 13, A0 to A5
pinMode (pinX, INPUT_PULLUP);
pinMode (pinX, OUTPUT);

5. Writing Data into Port-line:
(a) To write 1-bit (0 or 1) into a port-line (PB5), we use the following function:
(i) digitalWrite(DPin, Value);
===> digitalWrite(13, HIGH);

(ii) bitSet(13); //writing LH at PB5
bitClear(13); //writing LL at PB5

(iii) bitWrite(PORTX, n, x); // X = B/C/D, n=Bit_position, x = Bit_value
===> bitWrite(PORTB, 5, HIGH);

(b) To write to all port-lines (PB5-PB0) at the same time, we use the following statements:
PORTB = 0xFF; // 1s are written to all pins
PORTB = 0x00; // 0s are written to all pins

(c) In summary
digitalWrite(Dpin, Value); //DPin = 0 to 13, A0 to A5
bitSet(VAR, n); // VAR (variable) PORTX, DDRX; n = 0 to 7
bitClear(VAR, n);
bitWrite(VAR, n, x); // x = HIGH or LOW

6. Reading Data from Port-line:
(a) To read 1-bit data from a port-line, we use the following functions:
(i) boolean x = digitalRead(8); //reading 1-bit data

(ii) boolean x = bitRead(PORTB, 0);

(b) To read data from all the port-lines at the same time, we use the following assignment
statement:
byte x = PINB;

(c) In summary
boolean y = digitalRead(Dpin); //DPin = 0 to 13, A0 to A5
boolean z = bitRead(VAR, n); // VAR (variable) PINX; n = 0 to 7
byte = PINX; // PINX = PINB, PINC, PIND

7. Examples:
(a) Write C/C++ codes to check that K1-switch of Figure-1 is closed and only then keep blinking
L (built-in LED) at 1-sec interval. Test the program (sketch) using Arduino UNO Kit. Use
goto statement and if-else structure.

void setup()  //keep under this functions those tasks that are executed only for once/limited number 
                  //of times.
{
   //set direction of IO lines as needed (known as initialisation)
   pinMode(13, OUTPUT);           //PB5 as outut port-line
   pinMode(8, INPUT_PULLUP);   // PB0 as input port-line with internal pull-up resistor enabled

   //check if K1 is closed or not
   L1:  boolean x = digitalRead(8);
   L2:  if (x != LOW)
              goto L1;
}

void loop()  //keep under this function those tasks that keeps executing
{
     digitalWrite(13, HIGH);
     delay(1000);
     bitWrite(PORTB, 5, LOW);
     delay(1000);
 }

8. Exercises:
(a) Repeat Example-(a) using while-do structure instead of goto, if-else.

(b) Discuss merits and demerits of the programs of Example-(a) and Exercise-(a).

(c) Repeat Exercise-(a) by including cli() instruction under setup() function (before while-

  • do*). Observe that the L is not blinking even though you have closed K1. Find the exact reason
    for the L not to blink and then solve the problem by keeping the cli() instruction.

"3. DDRB: The full-name of DDRB is Data Direction Register for port-lines (PB5-PB0). This register helps to set the directions of the IO lines (port-lines) either as input or output depending on the requirement.

To set the direction of a port-line (say, PB5) as output, we write LH (1) at the corresponding bit (DDRB5) of the DDRB register. To set direction as input, we store LL (0) at the corresponding bit of DDRB."

Or just use one of these in setup(), easier to remember and not mess it up:
pinMode (pinX, INPUT);
pinMode (pinX, INPUT_PULLUP);
pinMode (pinX, OUTPUT);

pinMode can be used in loop() code also if the mode needs to change. For example, say two uCs were sharing a pin as an indicator to each other. uC1 pulls the line low, when it goes high it indicates to uC2: "I'm done loading a shared chip with data, go read it". uC2 pulls it low to indicate it's reading it, when it goes high indicates it's done reading and writing any data back to uC1.

I think ultrasonic ping sensors do the same, driving the line to send out a ping, then reading the line to register any return signal(s).

@CrossRoads

Many many thanks for revising and adding valuable information with the topics. I will append it with with my lecture notes.

In fact, the post is a some kind of Tutorial; it's organization is very much close to the lecture format that I deliver to the 3/2 students of EE Engineering. The students have pledged to compose the lecture and to post it in a widely reputed and accessed Public Forum like Arduiono so that they study online and download. They also practice the corresponding Lab works using a repackaged Arduino UNO Learning Kit.

I hope that you and others will recognize the fact that the students (listeners) exhibit their tendencies to have exposition to exhaustive textual description (in the theoretical class room) of the topics followed by Pseudo Code/Control Structure, Flow Chart, HLL, Visual, Structured Programming, Lab Works, and etc.

Myself, being a hardware novice designer and an ASM Programmer, has been assigned the teaching job of tailoring the Electrical Engineering students to acquire the abilities of programming a Computer/MPU/MCU to control industrial machinery and household appliances. From this view point, the ASM language is the most perfect and ideal one; however, the majority of the students do not like much the AVR Studio 4, ASM Language and the RMCKIT and yet they want to know what is going on at the bit level within the MCU/MPU.

Not only that, they also want to know the interaction of a high level method/function like Serial.Read()'s interaction with the USART hardware of the ATmega328 given the fact that the serial data reception can be done using both polling and interrupt events. Serial.Read() method of Arduino IDE works on interrupt, and it can read as many as 64 bytes incoming data in one one-go. On the other hand, the basic read instruction for the USART port is in r16, UD0. Now, it becomes very difficult job for a course teacher to establish a correlation between Serial.Read() and in r16, UD0. In this case, the Flow Chart and the simple Pseudo Code appear as great helping tools to explain/describe the activities being carried out by the highly abstracted method - the Serial.Read().

Learning is a very slow and costly process; it does not dare much on the profit side of the Institution. The Corporate body has to look at the cost-effective methods of solving a problem, which means the codes must be executed within shortest possible time, space, and energy in order to save money.

Thanks once again for tracking my posts on 'Education and Teaching'; your interactions in all issues add values and hope you will continue the same on my upcoming Tutorial Posts.

(i) boolean x = digitalRead(8);

Hint: [nobbc][/nobbc]

(a) To set the the direction of a single port-line (PB5) as output, we use the following function:
pinMode(DPin, value);
===> pinMode(13, HIGH);

OUTPUT is so much easier to remember than HIGH, don't you find?

Thanks for the tool to get rid of 'Cool' which replaced 8?

OUTPUT is so much easier to remember than HIGH, don't you find?

This is an excellent catch. Because memory cheats sometimes, the surgeon enters into the Operation Theatre with a Check List.