<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>programming | Microcontroller Tutorials</title>
	<atom:link href="https://www.teachmemicro.com/tag/programming/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.teachmemicro.com</link>
	<description>Microcontroller Tutorials and Resources</description>
	<lastBuildDate>Fri, 13 Oct 2023 10:34:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://www.teachmemicro.com/wp-content/uploads/2019/04/blue-icon-65x65.png</url>
	<title>programming | Microcontroller Tutorials</title>
	<link>https://www.teachmemicro.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How pinMode, digitalWrite and digitalRead Work</title>
		<link>https://www.teachmemicro.com/how-pinmode-digitalwrite-digitalread-works/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-pinmode-digitalwrite-digitalread-works</link>
					<comments>https://www.teachmemicro.com/how-pinmode-digitalwrite-digitalread-works/#respond</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Fri, 29 May 2020 04:27:15 +0000</pubDate>
				<category><![CDATA[Arduino Tutorial]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[output]]></category>
		<category><![CDATA[programming]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=4366</guid>

					<description><![CDATA[<p>I believe what makes Arduino popular is how it makes microcontrollers easier to use. I remember the time when I have to spent hours coding a project and then spend money on programming hardware. Arduino has its limitations, but the platform helps create tons of electronic projects even for non-engineers. Thus, I decided to create &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/how-pinmode-digitalwrite-digitalread-works/">How pinMode, digitalWrite and digitalRead Work</a> first appeared on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>I believe what makes <a href="https://www.win-source.net/products/detail/arduino/a000066.html">Arduino</a> popular is how it makes microcontrollers easier to use. I remember the time when I have to spent hours coding a project and then spend money on programming hardware. Arduino has its limitations, but the platform helps create tons of electronic projects even for non-engineers.</p>
<p>Thus, I decided to create a series showing how the most common Arduino functions work. This is not only for greater insight but also to appreciate all the work that was done to make programming easier for a lot of people.</p>
<p><span id="more-4366"></span></p>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-scaled.jpg"><img decoding="async" class="aligncenter size-large wp-image-4373" src="https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-1024x768.jpg" alt="arduino digital input" width="640" height="480" srcset="https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-1024x768.jpg 1024w, https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-300x225.jpg 300w, https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-768x576.jpg 768w, https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-1536x1152.jpg 1536w, https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-2048x1536.jpg 2048w, https://www.teachmemicro.com/wp-content/uploads/2020/05/arduino-digital-input-320x240.jpg 320w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>
<p>For the first part of the series, I will be looking at three essential functions for dealing with digital inputs: <a href="https://www.arduino.cc/reference/en/language/functions/digital-io/pinmode/">pinMode()</a>, <a href="https://www.arduino.cc/reference/en/language/functions/digital-io/digitalread/">digitalRead()</a> and <a href="https://www.arduino.cc/reference/en/language/functions/digital-io/digitalwrite/">digitalWrite()</a>.</p>
<h3><strong>Introduction</strong></h3>
<p>For brevity, I will choose only one out of the 19 current official Arduino board: the <a href="https://www.teachmemicro.com/arduino-uno-pinout-diagram/">Arduino UNO</a>. The UNO runs on <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf">Atmel’s ATMega328p</a> chip, whose pinout is below:</p>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2020/05/ATMega328p-Arduino-pinout.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-4367" src="https://www.teachmemicro.com/wp-content/uploads/2020/05/ATMega328p-Arduino-pinout.png" alt="ATMega328p/Arduino pinout" width="700" height="450" srcset="https://www.teachmemicro.com/wp-content/uploads/2020/05/ATMega328p-Arduino-pinout.png 700w, https://www.teachmemicro.com/wp-content/uploads/2020/05/ATMega328p-Arduino-pinout-300x193.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /></a></p>
<p>As seen here, each pin (except the power pins) is assigned to a port and a pin number. Starting from digital pin 0 to analog pin 5, PORTDs come first, then PORTBs and then PORTCs.</p>
<table style="undefined;table-layout: fixed; width: 622px;">
<colgroup>
<col style="width: 36px;" />
<col style="width: 82px;" />
<col style="width: 90px;" />
<col style="width: 37px;" />
<col style="width: 84px;" />
<col style="width: 87px;" />
<col style="width: 36px;" />
<col style="width: 84px;" />
<col style="width: 86px;" /> </colgroup>
<thead>
<tr>
<th>No.</th>
<th>Arduino Pin Number</th>
<th>Port</th>
<th>No.</th>
<th>Arduino Pin Number</th>
<th>Port</th>
<th>No.</th>
<th>Arduino Pin Number</th>
<th>Port</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>D0</td>
<td>PORTD</td>
<td>9</td>
<td>D8</td>
<td>PORTB</td>
<td>14</td>
<td>A0</td>
<td>PORTC</td>
</tr>
<tr>
<td>2</td>
<td>D1</td>
<td>PORTD</td>
<td>10</td>
<td>D9</td>
<td>PORTB</td>
<td>15</td>
<td>A1</td>
<td>PORTC</td>
</tr>
<tr>
<td>3</td>
<td>D2</td>
<td>PORTD</td>
<td>11</td>
<td>D10</td>
<td>PORTB</td>
<td>16</td>
<td>A2</td>
<td>PORTC</td>
</tr>
<tr>
<td>4</td>
<td>D3</td>
<td>PORTD</td>
<td>12</td>
<td>D11</td>
<td>PORTB</td>
<td>17</td>
<td>A3</td>
<td>PORTC</td>
</tr>
<tr>
<td>5</td>
<td>D4</td>
<td>PORTD</td>
<td>13</td>
<td>D12</td>
<td>PORTB</td>
<td>18</td>
<td>A4</td>
<td>PORTC</td>
</tr>
<tr>
<td>6</td>
<td>D5</td>
<td>PORTD</td>
<td></td>
<td>D13</td>
<td>PORTB</td>
<td>19</td>
<td>A5</td>
<td>PORTC</td>
</tr>
<tr>
<td>7</td>
<td>D6</td>
<td>PORTD</td>
<td colspan="6" rowspan="2">Arduino pin numbers and corresponding ports, in sequence</td>
</tr>
<tr>
<td>8</td>
<td>D7</td>
<td>PORTD</td>
</tr>
</tbody>
</table>
<p>This sequence makes sense later on.</p>
<p>Say you want to use digital pin 13 (PB5) as an output pin and digital pin 5 (PD5) as an input pin. You would normally do this:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">void setup(){
  pinMode(13, OUTPUT);
  pinMode(5, INPUT);
}

void loop(){
  digitalWrite(13, HIGH);
  int input = digitalRead(5);
}</code></pre></pre>
<p>From here on out, I will use this example sketch in our discussion.</p>
<h3><strong>The pinMode() Function</strong></h3>
<p>The pinMode() function accepts a pin number and mode as <a href="https://www.google.com/url?q=https://www.w3schools.com/cpp/cpp_function_param.asp&amp;sa=D&amp;ust=1590723474958000">parameters</a>:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">void pinMode(uint8_t pin, uint8_t mode)</code></pre></pre>
<p>This function is inside <em>wiring_digital.c</em> which is found in <em>&lt;Your Installation Folder&gt;\Arduino\hardware\arduino\avr\cores\arduino</em>. The Arduino platform is based on <a href="https://www.google.com/url?q=http://wiring.org.co/&amp;sa=D&amp;ust=1590723474960000">Wiring</a>, hence the name of the file.</p>
<p>Here’s the function in full:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">void pinMode(uint8_t pin, uint8_t mode)
{
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  volatile uint8_t *reg, *out;

  if (port == NOT_A_PIN) return;

  // JWS: can I let the optimizer do this?

  reg = portModeRegister(port);
  out = portOutputRegister(port);

  if (mode == INPUT) {
    uint8_t oldSREG = SREG;
    cli();
    *reg &amp;= ~bit;
    *out &amp;= ~bit;
    SREG = oldSREG;
  } else if (mode == INPUT_PULLUP) {
    uint8_t oldSREG = SREG;
    cli();
    *reg &amp;= ~bit;
    *out |= bit;
    SREG = oldSREG;
  } else {
    uint8_t oldSREG = SREG;
    cli();
    *reg |= bit;
    SREG = oldSREG;
  }
}</code></pre></pre>
<h4><strong>The pin Parameter</strong></h4>
<p>In the first two lines of the function, the eight-bit variables <em>pin</em> and <em>mode</em> are passed to <a href="https://www.google.com/url?q=https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzarg/cpxmac.htm&amp;sa=D&amp;ust=1590723474968000">macros</a> <em>digitalPinToBitMask</em> and <em>digitalPinToPort</em>:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);</code></pre></pre>
<p>Both of these macros are inside <em>Arduino.h</em> found inside <em>&lt;Your Installation Folder&gt;\Arduino\hardware\arduino\avr\cores\arduino</em> and are defined as:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#define digitalPinToPort(P)(pgm_read_byte( digital_pin_to_port_PGM + (P)))
#define digitalPinToBitMask(P)(pgm_read_byte(digital_pin_to_bit_mask_PGM + (P)))</code></pre></pre>
<p>Here, the parameter pin is passed to P which is then used to select an element from the arrays <em>digital_pin_to_port_PGM</em> and <em>digital_pin_to_bit_mask_PGM</em>. Both these arrays are stored inside the microcontrollers program memory as the <a href="https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#ga88d7dd4863f87530e1a34ece430a587c">pgm_read_byte()</a> function suggests. This makes sense since the ATMega328p has a lot of flash memory space compared to its RAM.</p>
<p>The elements of these arrays are viewable in the file <em>pins_arduino.h</em> which is in &lt;<em>Your Installation Folder&gt;\Arduino\hardware\arduino\avr\variants\&lt;Your Arduino Model&gt;</em>. There are different <em>pins_arduino.h</em> files for different Arduino boards. For the UNO, this file is inside the “standard” folder.</p>
<p>Here’s how the <em>digital_pin_to_port_PGM</em> array looks like:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
  PD, /* 0 */
  PD,
  PD,
  PD,
  PD,
  PD,
  PD,
  PD,
  PB, /* 8 */
  PB,
  PB,
  PB,
  PB,
  PB,
  PC, /* 14 */
  PC,
  PC,
  PC,
  PC,
  PC,
};</code></pre></pre>
<p>This 20-element array contains the ports of the ATMega328p pins following the same sequence in the table above.  For example, doing this:</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">pinMode(13, OUTPUT)</code></pre></pre>
<p>passes a value 13 to the macro:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t port = digitalPinToPort(pin);</code></pre></pre>
<p>which is now the value of P here:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">digitalPinToPort(P)(pgm_read_byte( digital_pin_to_port_PGM + (P)))</code></pre></pre>
<p>which now returns the 14th element (count starts at zero) from the array.</p>
<p>This means that the variable port is now equal to a constant “PB”. This is a an alias for values defined in <em>Arduino.</em>h:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#ifdef ARDUINO_MAIN
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
#define PG 7
#define PH 8
#define PJ 10
#define PK 11
#define PL 12
#endif</code></pre></pre>
<p>So “PB” is an alias for “2”. The others are there for Arduino boards with lots of ports and pins (the Arduino Mega contains up to PL).</p>
<p>Meanwhile, the array <em>digital_pin_to_bit_mask_PGM</em> has the following elements:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
  _BV(0), /* 0, port D */
  _BV(1),
  _BV(2),
  _BV(3),
  _BV(4),
  _BV(5),
  _BV(6),
  _BV(7),
  _BV(0), /* 8, port B */
  _BV(1),
  _BV(2),
  _BV(3),
  _BV(4),
  _BV(5),
  _BV(0), /* 14, port C */
  _BV(1),
  _BV(2),
  _BV(3),
  _BV(4),
  _BV(5),
};</code></pre></pre>
<p>This also accepts the number 13 and, similar to <em>digital_pin_to_port_PGM</em>, will return the 14th element in the array, which is <em>_BV(5)</em>.</p>
<p>_BV, short for bit value, is an AVR macro that sets a bit number in a byte. So _BV(5) in binary means:</p>
<pre class="">0010 0000</pre>
<p>where the 5th bit from the right, starting at zero is set. This is 0x20 in hexadecimal. So in this line</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t bit = digitalPinToBitMask(pin);</code></pre></pre>
<p>The variable <em>bit</em> is equal to 0x20.</p>
<p>As you see, both <em>digital_pin_to_port_PGM</em> and <em>digital_pin_to_mask_PGM</em> contain 20 elements inside the array. So what happens if you pass a number beyond the number of array elements? For example, what happens if you do this:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">pinMode(21, OUTPUT)</code></pre></pre>
<p>Since there’s nothing inside both arrays at position 21, these two will return with 0 bytes</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);</code></pre></pre>
<p>Also, the value 0 is conveniently assigned an alias inside Arduino.h</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#define NOT_A_PIN 0
#define NOT_A_PORT 0</code></pre></pre>
<p>Hence, inside the <em>pinMode()</em> function, you will see this line:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">if (port == NOT_A_PIN) return;</code></pre></pre>
<p>So passing a pin number beyond 20 bypasses <em>pinMode()</em> and will do nothing on the pins.</p>
<h4><strong>The mode Parameter</strong></h4>
<p>The mode can be <em>INPUT</em>, <em>INPUT_PULLUP</em> and <em>OUTPUT</em> and these are defined inside Arduino.h:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#define INPUT 0x0
#define OUTPUT 0x1
#define INPUT_PULLUP 0x2</code></pre></pre>
<p>In AVR microcontrollers, controlling the behavior of a pin requires manipulating three registers: DDR, PORT and PIN. Each pin group has these three registers so registers DDRB, PORTC and PIND exist.</p>
<p>The DDR register is responsible for making a pin input or output. So if you write this in an Arduino code:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">DDRD = B11110000</code></pre></pre>
<p>This makes pins PD4, PD5, PD6 and PD7 as output pins while PD0, PD1, PD2 and PD3 as input pins.</p>
<p>The PORT register clears or sets the actual pins. For example,</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">PORTD = B00000001</code></pre></pre>
<p>This sets the pin PD0 and clears all other pins.</p>
<p>The PIN register contains the digital value of the pins as inputs. They are used in the function <em>digitalRead()</em>. More on this later.</p>
<p>So the mode parameter inside <em>pinMode()</em> is passed to the macros</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">reg = portModeRegister(port);
out = portOutputRegister(port);</code></pre></pre>
<p>These macros are defined as</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )</code></pre></pre>
<p>Again, the mode, which can be either 0x0, 0x1 or 0x2 is used to point inside the arrays <em>port_to_output_PGM</em> and <em>port_to_mode_PGM.</em></p>
<p>The arrays are</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">const uint16_t PROGMEM port_to_mode_PGM[] = {
  NOT_A_PORT,
  NOT_A_PORT,
  (uint16_t) &amp;DDRB,
  (uint16_t) &amp;DDRC,
  (uint16_t) &amp;DDRD,
};

const uint16_t PROGMEM port_to_output_PGM[] = {
  NOT_A_PORT,
  NOT_A_PORT,
  (uint16_t) &amp;PORTB,
  (uint16_t) &amp;PORTC,
  (uint16_t) &amp;PORTD,
};</code></pre></pre>
<p>Recall that this function</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t port = digitalPinToPort(pin);</code></pre></pre>
<p>Returns “PB” equal to the number 2. This would point us to both DDRB and PORTB (3rd element in the arrays with starting count at 0). This means reg and port and these lines:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">reg = portModeRegister(port);
out = portOutputRegister(port);</code></pre></pre>
<p>Which by the way are 8-bit pointers:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">volatile uint8_t *reg, *out;</code></pre></pre>
<p>Will be equal to the contents of registers DDRB and PORTB respectively.</p>
<p>Now let’s see how these ports are manipulated based on the value of mode.</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">if (mode == INPUT) {
  uint8_t oldSREG = SREG;
  cli();
  *reg &amp;= ~bit;
  *out &amp;= ~bit;
  SREG = oldSREG;
} else if (mode == INPUT_PULLUP) {
  uint8_t oldSREG = SREG;
  cli();
  *reg &amp;= ~bit;
  *out |= bit;
  SREG = oldSREG;
} else {
  uint8_t oldSREG = SREG;
  cli();
  *reg |= bit;
  SREG = oldSREG; 
}</code></pre></pre>
<p>If a pin is to be an OUTPUT pin, the reg variable, which points to the DDR register, is OR’d with the “bit” value.</p>
<p>For our example:</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">pinMode(13, OUTPUT)</code></pre></pre>
<p>Recall that the variable “bit” is equal to 0x20. So the DDRB register is equal to</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">DDRB = DDRB | B00100000;</code></pre></pre>
<p>This makes PB5 an output pin. Why do this instead of assigning 0x20 to DDRB directly? This method is known as <a href="https://www.google.com/url?q=https://en.wikipedia.org/wiki/Mask_(computing)&amp;sa=D&amp;ust=1590725455536000">masking</a>. Through this, you can set (or clear) bit(s) in a byte, word, nibble while all other bits are unaffected.</p>
<p>Similary, if the pin is an input:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">pinMode(5, INPUT)</code></pre></pre>
<p>The corresponding DDR pin and PORT pin are manipulated like this:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">*reg &amp;= ~bit;
*out &amp;= ~bit;</code></pre></pre>
<p>For our example, this is equivalent to:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">DDRD = DDRD &amp; 0xDF;
PORTD = DDRD &amp; 0xDF;</code></pre></pre>
<p>which uses AND masking and where 0xDF is the bitwise complement of 0x20.</p>
<h4><strong>Status Register</strong></h4>
<p>Notice this part:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t oldSREG = SREG;
cli();
...
SREG = oldSREG;</code></pre></pre>
<p>This is found whether mode is INPUT, INPUT_PULLUP or OUTPUT. SREG is the ATMega328’s status register which is the register that holds information regarding the last Arithmetic Logic Unit operation, among other things.</p>
<p>What happened here is that the current SREG value is stored in a variable named oldSREG. This effectively preserves the status of the microcontroller’s CPU. Then, all <a href="https://www.teachmemicro.com/arduino-interrupt-tutorial/">interrupts</a> are cleared via the command <a href="https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html#ga68c330e94fe121eba993e5a5973c3162">cli()</a>. After the DDR value assignment, the previous content of the SREG is loaded back to itself.</p>
<h3><strong>The digitalWrite() Function</strong></h3>
<p>Now let’s look at the digitalWrite() function:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">void digitalWrite(uint8_t pin, uint8_t val)
{
  uint8_t timer = digitalPinToTimer(pin);
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  volatile uint8_t *out;

  if (port == NOT_A_PIN) return;
  // If the pin that support PWM output, we need to turn it off
  // before doing a digital write.
  if (timer != NOT_ON_TIMER) turnOffPWM(timer);
    out = portOutputRegister(port);
    uint8_t oldSREG = SREG;
    cli();
    if (val == LOW) {
       *out &amp;= ~bit;
    } else {
       *out |= bit;
    }
  SREG = oldSREG;
}</code></pre></pre>
<p>This function accepts <em>pin</em> and <em>val</em> as parameters. Some parts are similar to <em>pinMode()</em> except</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t timer = digitalPinToTimer(pin);</code></pre></pre>
<h4>Turning On/Off PWM</h4>
<p>The <em>digitalPinToTimer()</em> function is defined as</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )</code></pre></pre>
<p>Again, this reads an array, <em>digital_pin_to_timer_PGM</em> which contains:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
  NOT_ON_TIMER, /* 0 - port D */
  NOT_ON_TIMER,
  NOT_ON_TIMER,
  // on the ATmega168, digital pin 3 has hardware pwm
  #if defined(__AVR_ATmega8__)
  NOT_ON_TIMER,
  #else
  TIMER2B,
  #endif
  NOT_ON_TIMER,
  // on the ATmega168, digital pins 5 and 6 have hardware pwm
  #if defined(__AVR_ATmega8__)
  NOT_ON_TIMER,
  NOT_ON_TIMER,
  #else
  TIMER0B,
  TIMER0A,
  #endif
  NOT_ON_TIMER,
  NOT_ON_TIMER, /* 8 - port B */
  TIMER1A,
  TIMER1B,
  #if defined(__AVR_ATmega8__)
  TIMER2,
  #else
  TIMER2A,
  #endif
  NOT_ON_TIMER,
  NOT_ON_TIMER,
  NOT_ON_TIMER,
  NOT_ON_TIMER, /* 14 - port C */
  NOT_ON_TIMER,
  NOT_ON_TIMER,
  NOT_ON_TIMER,
  NOT_ON_TIMER,
};

#endif</code></pre></pre>
<p>The array is quite long, because the code anticipates the use of an ATMega8 microcontroller which has a different set of timers. So if you exclude #if defines for the ATMega8, you still have 20 elements in the same sequence as that in the table.</p>
<p>Looking back at the pinout of the ATMega328p, pins PD3, PD5, PD6, PB1, PB2 and PB3 are PWM pins. Pulse width modulation is possible through <em><strong>timer registers</strong></em> to which the ATMega328p has three kinds: Timer0, Timer1 and Timer2. Each timer uses at least two pins thus, you’ll see Timer0A, Timer0B, Timer1A, Timer1B, Timer2A, Timer2B.</p>
<p>Digital pin 13 is not a PWM pin, so this</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">uint8_t timer = digitalPinToTimer(pin);</code></pre></pre>
<p>will just return NOT_ON_TIMER which is another alias for 0. But if you will use a PWM pin say D5, this function will return <em>TIMER0A</em> which is an alias for “1”</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER1C 5
#define TIMER2 6
#define TIMER2A 7
#define TIMER2B 8</code></pre></pre>
<p>and so the variable timer is now equal to 1. Back inside the <em>digitalWrite()</em> function, there’s this line:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">if (timer != NOT_ON_TIMER) turnOffPWM(timer);</code></pre></pre>
<p>Since timer is now not equal to 0, this line holds true. So, the <em>turnOffPWM()</em> function disables the PWM function of the timer register pointed by the pin number. This effectively makes the pin a digital output pin only.</p>
<p>Now for the rest of <em>digitalWrite():</em></p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">...
out = portOutputRegister(port);
uint8_t oldSREG = SREG;
cli();
if (val == LOW) {
  *out &amp;= ~bit;
} else {
  *out |= bit;
}
SREG = oldSREG;</code></pre></pre>
<p>The pointer <em>out</em> returns the (address of) PORT register. In our example:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">digitalWrite(13, HIGH);</code></pre></pre>
<p>that’s PORTB. The contents of the status register is saved then interrupts are cleared.</p>
<p>If the variable <em>val</em> is LOW (an alias of zero), the PORTB register has a value that clears the pin. If the bit variable is 0x20, then</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">PORTB = PORTB &amp; 11011111;</code></pre></pre>
<p>This masks the other pins except PB5 which is now LOW.</p>
<p>In contrast, if the variable <em>val</em> is HIGH (an alias of one), the PORTB register has a value that sets the pin. If the bit variable is 0x20, then</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">PORTB = PORTB | 00100000;</code></pre></pre>
<p>Similarly, this masks the other pins except PB5 which is now HIGH. In our example, this is the value of PORTB.</p>
<h3><strong>The digitalRead() Function</strong></h3>
<p>Here’s what’s inside the <em>digitalRead()</em> function:</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">int digitalRead(uint8_t pin)
{
  uint8_t timer = digitalPinToTimer(pin);
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  if (port == NOT_A_PIN) return LOW;
  // If the pin that support PWM output, we need to turn it off
  // before getting a digital reading.
  if (timer != NOT_ON_TIMER) turnOffPWM(timer);
  if (*portInputRegister(port) &amp; bit) return HIGH;
  return LOW;
}</code></pre></pre>
<p>The function only accepts a <em>pin</em> parameter. Here, we see this for the first time:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">if (*portInputRegister(port) &amp; bit) return HIGH;
return LOW;</code></pre></pre>
<p>The <em>portInputRegister()</em> is a another macro:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )</code></pre></pre>
<p>Similar to other macros, this uses an array <em>port_to_input_PGM</em> with five elements:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">const uint16_t PROGMEM port_to_input_PGM[] = {
  NOT_A_PORT,
  NOT_A_PORT,
  (uint16_t) &amp;PINB,
  (uint16_t) &amp;PINC,
  (uint16_t) &amp;PIND,
};</code></pre></pre>
<p>So when you do this:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">int input = digitalRead(5);</code></pre></pre>
<p>First it checks if this is a PWM pin and if it is, it turns off the timer associated with that pin. Then the <em>portInputRegister()</em> macro returns the appropriate PIN register. Recall that the PIN register is the data input register.</p>
<p>The value of the <em>port</em> variable is 4 and so in this case, the function returns the location of &amp;PIND (fifth element in the array).</p>
<p>The bit value 0x20 masks the PIND register:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">PIND = PIND &amp; B00100000;</code></pre></pre>
<p>This checks if PD5 is high or low. If it’s high, then the <em>digitalRead()</em> function exits and returns HIGH, hence <em>input</em>, which is a 16-bit variable, is equal to 1. Otherwise, <em>input</em> is equal to zero.</p>
<h3><strong>Conclusion</strong></h3>
<p>Overall, this code snippet:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">void setup(){
  pinMode(13, OUTPUT);
  pinMode(5, INPUT);
}

void loop(){
  digitalWrite(13, HIGH);
  int input = digitalRead(5);
}</code></pre></pre>
<p>Is equivalent to this:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">int main(void){
  DDRB |= B00100000;
  DDRD |= B11011111;

  while(1){
    PORTB |= B0010000;
    int input = PORTD &amp; B0010000;
  }
  return 0;
}</code></pre></pre>
<p>Both are short programs but the first one is easier to understand compared to the second (<a href="https://www.google.com/url?q=https://forum.arduino.cc/index.php?topic%3D43127.0&amp;sa=D&amp;ust=1590725455576000">which may not work if coded in Arduino IDE</a>). As seen in this article, it takes a lot of work to make microcontroller programming easier.</p>
<p>If you find this article useful, kindly drop a comment below. Thanks for reading!</p><p>The post <a href="https://www.teachmemicro.com/how-pinmode-digitalwrite-digitalread-works/">How pinMode, digitalWrite and digitalRead Work</a> first appeared on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/how-pinmode-digitalwrite-digitalread-works/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: www.teachmemicro.com @ 2026-06-16 20:00:38 by W3 Total Cache
-->