Arduino microcontrollers have plenty of I/O pins, some of which have an “analog” capability. Although Arduino’s function pinMode() sets the pins as inputs or outputs, neither do they always need to be set, nor they will always work as we expect them to. The aim of this tutorial is to clarify the use and behavior of I/O pins on 8bit AVR Arduino boards, such as Dasduino Core, Dasduino Lite, Arduino Uno, Mega, etc.


When starting Arduino, all pins are set to INPUT. As an INPUT, the pins are in a high impedance state, which prevents short circuits. If we would read the state of these pins, it would not be stable, i.e. the pin would float between LOW and HIGH. More about that phenomenon in the tutorial about pull-up resistors.

An exception is the digital pin13, which is defined as an OUTPUT. The reason for it is the fact that Arduino starts the bootloader program at each startup, whose purpose is listening of serial pins in order to registrate the new code in PROGMEM. Try to reset the Dasduino, and you will notice that the orange LED on the 13th pin has blinked. Upon completion, pin13 returns to INPUT state and you can continue using it as every other I/O pin.


INPUT is each pin defined to read the input state, e.g. photo-resistor, push-button, potentiometer and some sensors. The state of pin is determined in a way that microcontroller reads the voltage on the pin. There are analog and digital inputs. Analog inputs are, unlike digital ones, connected to a multiplexer, and each of them to an A/D converter.

analogRead() by the reference voltage gives 32bit values (0-1023). The default value of the reference voltage is 5V. It means that, if the microcontroller charges the voltage of 0V, it will assign the analog value 0, while 1023 indicates 5V. For other values, proportional to that. We can assign the reference voltage ourselves, by bringing it to aref Arduino pin, ofcourse, under the assumption that it is not greater than the maximum the microcontroller can take (5V).

digitalRead() defines every voltage above 3V (for 5V boards) as HIGH, and every one below it as LOW. NOTE: the practice is to define pins as HIGH/LOW, even though they will work properly as 1/0 (as shown by the Serial Monitor) or true/false.  

pinMode() can be used to define pins as INPUT, but it is good to bear in mind that:
1. pinMode() defines pins as digital, not analog inputs.
2. when analogRead() is called upon, the pin automatically reconfigures to an input pin

Regardless of the above, the reccomendation is to use the pinMode() while defining input pins, because of the transparency of the code. The code will be more clear by knowing which pins we use and in which way.

An example:

int ulaz = A0;
void setup() {
    pinMode(ulaz, INPUT); // not necessary
    Serial.begin(9600);  // starting serial communication  
void loop() {
    int digOcitanje = digitalRead(ulaz); // saving digital reading of the pin A0 in the dig0citanje variable
    int anaOcitanje = analogRead(ulaz);  // saving analog reading of the pin A0 in the an0citanje variable
    // printing out the read values in Serial Monitor
    Serial.print("Digitalno ocitanje: ");
    Serial.print("Analogno ocitanje: ");

If you have a potentiometer at hand, connect it according to the picture below, change the position and monitor changes in Serial Monitor.


OUTPUT defines output pins, i.e. output voltage. As with inputs, we distinguish digital and “analog” (PWM) pins. Examples of components and modules used as OUTPUT : LED diodes, buzzer, relays, engines, etc.

analogWrite() works with pins supporting the PWM (Puls-Width Modulation). On the Croduino, those are digital pins 3, 5, 6, 9, 10 i 11, and they are marked with an apostrophe (‘). Check the pin-out. As with analogRead (), analogWrite () sets the pin as OUTPUT. The value we can set with analogWrite is 8bit (0-255).

digitalWrite “sends” 5V (HIGH) or 0V (LOW) to the pin.

We connect the cathode(shorter pin) of the LED diode through 330ohm resistor to the gnd, and the anode(longer pin) to the digital pin(PWM)9 as shown in the picture below

int led = 9; // LED on the PWM pin 9
int pwnVrijednost = 153; // defining the pwm value (between 0 and 255)
                         // 0 = 0V; 255 = 5V and proportionally
void setup() {
    pinMode(led, OUTPUT); // defining LED as OUTPUT
void loop() {
    digitalWrite(led, HIGH); // the first argument is the pin, the second LOW/HIGH; turning the LED(5V) on
    delay(500);              // we stop the program at 500ms = 0.5sek
    digitalWrite(led, LOW);  // turning the LED(0V) off
    analogWrite(led, pwmVrijednost); // the first argument is the pin, the second a value between 0 i 255, turning the LED(3v) on
    analogWrite(led, 0); // turning the LED(0V) off

NOTE(in the example above): 153(PWM) is equivalent to a voltage of 3V. We get this from the ratio x / 5V = 153/255. So, x = 153 * 5V / 255 = 3V. * (we know that 0V = 0 (PWM) and that 5V = 255 (PWM))



In the end we will show how to turn analogue readings(0-1023) to PWM(0-255). From the example with the potentiometer and LED diode we used for testing INPUT/OUTPUT, we will read the potentiometer status, and depending on it, amplify/decrease the light of the LED. Although, at first glance, it looks very simple and easy, the problem may arise due to the range. Let’s see in the example below, which IS NOT CORRECT:

int led = 9;   // LED on the pin 9
int ulaz = A0; // potentioneter on the pin A0
void setup() {
pinMode(ulaz, INPUT);
pinMode(led, OUTPUT);
void loop() {
int ocitanje = analogRead(ulaz); // defining new variable reading
// in which we save the analogue reading(0-1023) of the potentiometer
analogWrite(led, ocitanje); // the LED's status is set according to the values of analogue readings of the A0 pin
Upload the code and observe what happens. At the full turn of the potentiometer, the LED went out four times, even though we expected the values to range from fully turned off to maximum illuminated. The reason for this is when the reading variable has a value of 256 (for PWM maximum of 255), analogWrite () defines it as 0, or completely extinguishes the LED, because the PWM accepts only 8bit (0-255) values. So, 256 becomes 0, 257 becomes 1, 258 becomes 2 and so on. In order to avoid this, we introduce the integrated function map(), which will map the value into default range. We use it in the following way:
// the variable to which we save the new value =
// map(
// the variable we want to map, minimum value we map, maximum value we map,
// minimum value into which we map, maximum value into which we map
// );
int mapiranaVrijednost = map(ocitanje, 0, 1023, 0, 255);

Apropos, in the example with the potentiometer and LED diode:

int led = 9;   // LED on the 9
int ulaz = A0; // potentiometer on the pin A0
void setup() {
    pinMode(ulaz, INPUT);
    pinMode(led, OUTPUT);
void loop() {
    int ocitanje = analogRead(ulaz); // defining new variable reading
                                     // in which we save the analogue reading(0-1023) of the potentiometer
    int mapiranaVrijednost = map(ocitanje, 0, 1023, 0, 255);
    analogWrite(led, mapiranaVrijednost); // the LED's status is set according to the values of analogue readings of the pin A0


Do you know that in one line of code you can change OUTPUT pin status and use digitalRead () with OUTPUT pins?

digitalWrite(13, !digitalRead(13));

The first thing you notice is how the digitalRead() is used to define pin13’s status. Does it mean that the pin is used as INPUT and OUTPUT at the same time? No. Actually, it seems that, when calling a digitalRead () to a pin defined as OUTPUT, we read the status of the PORTX register within the ATmega microcontroller.

There are several such registers inside the microcontroller (x represents “B, C, D”), and they contain the current pin status. In particular, pin13 is located at PORTB. When the pin is defined as OUTPUT, digitalWrite () communicates with PORT to change it, i.e. enable HIGH or LOW. When calling digitalRead (), the PORTx register changes to the current value, if digitalWrite () is set to LOW digitalRead (), it will return LOW and vice versa. Interesting!

!” still needs to be explained. We call it NOT operator or bang, and in fact, it is the fastest way to invert the value. It converts HIGH to LOW, and vice versa.

In the end, try out the code:

void setup() {
    pinMode(13, OUTPUT); // we use the orange LED on the Croduino board
void loop() {
    digitalWrite(13, !digitalRead(13));