PORT Manipulation in Arduino (Register Level Programming)

In today's article we will see the topic of port manipulation in Arduino. As we know, it is possible to program the Arduinos we have through the Arduino IDE. In addition, as we know, through the Arduino IDE, we actually program our microcontroller, which is included in our Arduino development card. During this programming process, we are able to perform these operations closer to the human language through the libraries they have already provided us.

In fact, we can simply call it a high-level microcontroller programming method. Because if we program Arduino using ready-made libraries without using direct port manipulations, the code we write will be more readable. But that's where we face a huge problem. In fact, many people who are engaged in this business as a hobby in the market are not aware of this handicap. Perhaps the biggest reason for this is that they keep their projects at a hobby level. This problem, which occurs when we program our microcontroller using ready-made libraries, is that our microcontroller unnecessarily overuses its memory. Another negative situation will be that our processing speed will be reduced to a small extent by performing more transactions than it should due to the libraries used ready-made.

At this point, in fact, these problems depend on the person. People who keep their projects at a hobby level do not need much such port manipulations, as they will not need much speed anyway. Because their goal is to make their project the most understandable and fast. However, people who want to continue their work in a professional way like the rest of us need each byte in the memory of their microcontroller when the time comes.

So why do you think using these prebuilt libraries take up extra space in the memory of our microcontroller and slow down our speed?

As we know, we don't actually write our code directly in C-language in Arduino ide. At this point, we use the ready-made libraries offered to us by Arduino ide. The code we have written here actually consists of prebuilt functions. And when we compile our code, the code we actually write is not directly loaded into the memory of our microcontroller. Because, as you know, in order for our microprocessor to perform the operations, the code written first must be in a form that he can understand. At this point, you may have some questions. So how do these codes work?

At this point, our arduino code, which we have prepared by using ready-made functions:

void setup() {
  pinMode(2, OUTPUT);  Pin #2 set to output
  pinMode(3, INPUT);   Pin 3 set to input
}

void loop() {
  if(digitalRead(3) == 1) // Pin entry 3 becomes high 
  { 
  digitalWrite(2, HIGH); Led connected pine power
  }
  else
  {
  digitalWrite(2, LOW); The power supplied to the pine to which led is connected has been cut off
  }
}

In fact, as we have seen, preparing our project in this way will be much more understandable and easy. However, in this case, these ready-made functions are translated into C language, which is programmed at register level through the ide you used first. Because within each library, we see the corresponding of the function in the programming at the register level. These codes are then translated into C language. In other words, it is translated into machine language, which we are all familiar with by name. Here's what you think a little bit, and we can simply comprehend the logic. If we write our code directly at register level, or if we create our own library and avoid unnecessary functions and definitions, the place that our code will keep in memory will decrease.

Arduino

As we know, Arduino is a development card designed to make your use easier for multidisciplinary projects and has a free development environment. At this point, there are many arduino varieties. For this reason, the microcontroller contained in arduinos also changes according to the variety. The two examples I can give to this will be:

  • Arduino Uno -> ATmega328P with 32 KB Flash Memory is used.
  • Arduino Mega -> ATmega2560 with 256 KB Flash Memory is used.
PORT Manipulation in Arduino
Arduino UNO

Here we understand that some important parameters may vary depending on which card we program. Well, we're getting to the bottom of this. Then let's write our LED burning code with Arduno libraries and write using port manipulation technique. In this way, let's see the differences between them as syntax.

At this point, you should first know that in this article we write our sample code according to Arduino UNO. These codes may vary some minorly from the magnetizer to the microcontroller.

LED Burning with Ready Libraries in Arduino

At this point, our job is actually very simple. We already have a detailed article about it. From there, you can do it again and reinforce the subject. Let's go straight to our code.

int ledPin=2;               We connected led to pine number 2
void setup() {  
pinMode(ledPin, OUTPUT);    We set our LED to output
}
void loop() {

digitalWrite(ledPin, HIGH); We've powered the LED
delay(1000);                We waited for a second.
digitalWrite(ledPin, LOW);  We've cut the power to the LED.
delay(1000);                We waited for a second.

LED Burning with Port Manipulation in Arduino

At this point, the first thing we need to know is what the microcontroller we will program is. Since we will use Arduino Uno here, it will be to our advantage to review the datasheet of ATmega328P. At this point, the biggest reason for this is that you should never memorize when programming microcontrollers. We can give you commands that need to be applied directly, ready. But this will not really add much to understanding microcontroller programming. If you also learn why you use those commands, it will be much easier in the future.

PORT Manipulation in Arduino
datasheet

At this point, we will share you a small image from datasheet, but it will be to your advantage to download and review this datasheet. Because here you can see where the codes that we will see in the field below actually come from. If you examine this datasheet a little more, you can find out exactly where it came from or what other commands are.

PORT Manipulation in Arduino
ATmega Pin Configuration

Pin Configuration with Port Manipulation

At this point, let's see how I adjust the pins of our microcontroller in and out. Then let's actually see what it's like if we use Arduino's ready-made libraries so we can make a little comparison.

At this point, let's see which pinin Arduino stumbles across in Atmega and which Data direction Register.

PORT Manipulation in Arduino
Arduino Pins

From the image above, we can easily tell which pin of Arduino corresponds to which bit in Atmega and which bit in the Register.

Set Pin as Output with Port Manipulation

At this point, let's set our pin number 10 in Arduino as the bride exit. Of course, in order to better understand this, we can understand which number 4 pi actually corresponds to which in which Register.

PORT Manipulation in Arduino
DDRB

At this point, we actually see that our pin number 10 corresponds to the PB2 bit from the image above.

DDRB = 0b00000100;

The code at the bottom does the same as the top one. Using only the bitic processing operator in the underlying code, you can use "|" We've made our (OR) code a little more understandable.

DDRB |= (1 << PB2);

Thanks to this code, we set the pin number 10 of our Arduino (which corresponds to PB2 in the microcontroller) to OUTPUT. Thanks to this code, you can get output on your projects as you wish via that pin.

Set a Pin as An Output with Ready-made Libraries

pinMode(10, OUTPUT);

Let's set our pin number 10, which is also located in Arduino, as the bride exit. This code, as we know, performs the same process as programming using port manipulation. And in fact, if you examine it carefully, you can understand how readable this line of code is, but as we know, if we prefer this command, we will face negative effects on issues such as memory and speed. However, as we mentioned earlier, such negativity may not cause you much headaches in hobby projects. It's a matter of personal preference. It would be the right decision to implement the most logical solution depending on what problem you are facing at that moment.

Pine PowerIng Set to Output with Port Manipulation

PORTB = 0b00000100;

Let's power our pin 10. The code at the bottom does the same as the top one. Using only the bitic processing operator in the underlying code, you can use "|" We've made our (OR) code a little more understandable.

PORTB |= (1 << PB2);

Thanks to this code you have seen, we make the pin #10 of our Arduino (which corresponds to PB2 in the microcontroller) HIGH. In this way, we can apply the process we want through that pin in our projects.

Pine PowerIng Set to Output with Ready-made Libraries

digitalWrite(10, HIGH);

Source Code Comparison on a Project

In this project, we will use 4 LEDs. Actually, it's going to be a really simple project. Our only goal here will be to carefully examine the syntax difference between the two separate source codes of our project. In our project, our 2 LEDs will burn at the same time. Our other two LEDs will stand dimmed. Then our side 2 LEDs will dim and the others will burn.

LED Project with Ready Library

#define led1 8
#define led2 9
#define led3 10
#define led4 11

void setup() {
  pinMode(led1, OUTPUT);     8. Pin Set to Output
  pinMode(led2, OUTPUT);     9. Pin Set to Output
  pinMode(led3, OUTPUT);     10. Pin Set to Output
  pinMode(led4, OUTPUT);     11. Pin Set to Output
} 

void loop() {
  digitalWrite(led1, HIGH);  8. Pine Power Given
  digitalWrite(led2, HIGH);  9. Pine Power Given
  digitalWrite(led3, LOW);   10. Pinden Power Cut
  digitalWrite(led4, LOW);   11. Pinden Power Cut
  delay(1000);               1 Second Expected  
  digitalWrite(led1, LOW);   8. Pinden Power Cut
  digitalWrite(led2, LOW);   9. Pinden Power Cut
  digitalWrite(led3, HIGH);  10. Pine Power Given
  digitalWrite(led4, HIGH);  11. Pine Power Given
  delay(1000);               1 Second Expected  
}

LED Project with Port Manipulation

void setup() {
  DDRB = 0b000001111;    Pins 8, 9, 10, 11 Set to Output
  PORTB = 0x00;          Resetting the Data Register At The Beginning of Each Project Will Be To Your Advantage
  
}

void loop() {
  PORTB = 0b000000011;   Pins 8, #9 Powered and Other Pins Reset
  _delay_ms(1000);       1 Second Expected
  PORTB = 0b000001100;   Pins #10, 11 Powered and Other Pins Reset
  _delay_ms(1000);       1 Second Expected
}

In fact, there are a few things we should know at this point. One is that there are multiple ways to write code and set up algorithms. As we know, programming languages have loops such as for, while. In fact, we can further shorten such cycles by using them in our source code. Or we can do what we want to do in different ways. However, since our goal here is to see how the process actually works and the clear difference between them, we chose to write it this way. Otherwise, we could have written in different ways.

At this point, as you can see, the logic is exactly the same, but the spelling is different. One of the reasons for this is that there are no commands such as digitalWrite, pinMode, in programming with Port Manipulation. Instead, we use commands such as DDRx, PORTx. This actually helps us to reserve space in the extra memory. We already mentioned the exact reasons for this at the beginning of our article.

In short, that's the difference, but let's not forget this for the last time. Programming with Port Manipulation is also completely sea of sea. We just really talked to you about their differences at the entry level and wanted to log in programming with Port Manipulation. We're thinking of making a good series about it in the future. In this way, you will actually learn about register-level programming and pin configuration, communication systems, etc. In this way, you will be able to step into a more professional source code development process in your large and high quality projects.