user13674: I was conducting some research on wireless communication between a simple transmitter and receiver module using an Arduino. Now, I tested the channel accuracy and i received 14% error for a delay of one micro second. For a delay of 2 microseconds, my error was 0%, and for three microseconds, my error rate was 30%. I am not quite sure why the data would result in this. I think it possibly has something to do with the gain on the receiver and the delay time. Some sweet spot perhaps? Can anyone offer me some ideas/explanations? Also, sorry for any confusion in this question. I am happy to clarify. 
Part 2:
Hey Everyone, 
I also had a question regarding what purpose each of the following delay serves in wireless communication. 
// Write each of the 8 bits
for (uint8_t i = 8; i > 0; --i)
{
  if (b & 1) // choose bit
    *reg |= reg_mask; // send 1
  else
    *reg &= inv_mask; // send 0

  tunedDelay(delay);// line in question ---------------------
  b >>= 1;
}

and the delay used in the regular blink program. 
The regular delay used in the blink programs was what set the 2 microsecond delays.
Lastly, I am looking at the read and recv methods in the software serial library and i don't see any checks for start bits, so what's the point of writing one in the write method? 

user10794: 
I am looking at the read and recv methods in the software serial library and I don't see any checks for start bits, so what's the point of writing one in the write method? 

The start bit is absolutely essential in serial comms. In the graphic below, the start bit is marked "B" - which distinguishes it from "idle" data which is "A". Once received, the receiver then waits 1.5 bit times and starts clocking in the remaining bits. (Starting at "C" in the diagram, and then moving on for a total of 8 bits).

Without a start bit, how would the receiver know when the byte started? Imagine you wanted to send 0xFF (all 1 bits). Without a start bit that would be indistinguishable from the idle state.
In the graphic, "D" is the stop bit. Why have a stop bit? We need one (which is a "1" bit), so that we can detect the transition from the stop bit in the previous byte (a "1") and the start bit in the next byte (a "0").
In the graphic, "E" is the start bit for the next byte.


I don't see any checks for start bits ...

SoftwareSerial has a pin-change interrupt set up to detect that the receiving pin has changed state (to a zero usually). That is your start bit. You don't see it in the loop, because it has already arrived, otherwise you wouldn't be in the receive loop in the first place.

user4143: 
Now, I tested the channel accuracy and i received 14% error for a delay of one micro second. For a delay of 2 microseconds, my error was 0%, and for three microseconds, my error rate was 30%.

Microsecond resolution delays on an Arduino are tenuous at best.  They aren't that accurate.  Simply because you're hitting the limit of the speed of the CPU.
At 16MHz you have a clock period of 1/16000000 seconds.  That's 63ns.  That's the granularity of the delays you can achieve - and that can only be achieved by inserting a precise number of NOP assembly instructions.
So for the best 1µs delay possible you would need (0.000001 / 0.000000063) 15.87 NOP instructions.  Of course, you can't have that many, so you have to round it either up or down.  Normal integer truncation would result in 15.  So that would actually be a delay of 945ns, which is an error of 5.5%.
2µs would be (0.000002 / 0.000000063) 31.74 NOP instructions, which would round to 31, so 1.953µs, or an error of 2.35%.  As you can see increasing the length generally reduces the error.
HOWEVER
The delay function on the Arduino for microsecond accuracy (delayMicroseconds()) is maybe not as accurate as it could be.  Simply because it's impossible to just have an exact number of NOP instructions for a delay since you can't know how long the delay should be until the function is called with a parameter detailing how long the delay should be.  So it has to perform a number of calculations and make a number of assumptions.  It tries to come close, but it was written for one specific version of the compiler and compilers change. Things may have been changed in how the function gets called, and how long parts of it take (what registers are pushed and popped may change with different compiler versions, for instance).  So it's not a perfectly reliable delay.
For more detail you can look at the source code of it (it's in wiring.c) and you can see how for small delays it's very hard to get it right. For instance, this couple of lines highlights the problem nicely:
    // for a one-microsecond delay, simply return.  the overhead
    // of the function call yields a delay of approximately 1 1/8 us.
    if (--us == 0)
        return;

Note the use of the word approximately there...
Also you need to note that the delay functions are just that - a delay at that specific moment in time from the start of the call to its finish.  It doesn't take into account anything else that's going on in your code, so a delay of 1µs in a loop of code that does other things will end up in a loop that takes X + 1µs where X is the amount of time that the rest of the code takes to execute.
And that's where the tunedDelay() function comes in.  It has been specially written to be used in that specific circumstance to provide a delay that takes into account the time the rest of the loop takes to run.  That is, the loop's time plus the tunedDelay time equate to the final period you want for the whole loop.  For asynchronous serial communications the timing accuracy is important.  Since there is no separate (or even embedded) clock to get the timing from both ends have to agree what speed the communication happens at (the baud rate), and any deviation from that can cause communication errors.  So the timing has to be as close as possible. A normal delayMicroseconds() function call just wouldn't cut the mustard - they needed it more precise than that.  Manually tuned to have specific delay values that are as precise as possible, and that was done for specific baud rates on specific speed chips.  Each supported frequency has a table such as this:
static const DELAY_TABLE PROGMEM table[] =
{
  //  baud    rxcenter   rxintra    rxstop    tx
  { 115200,   1,         17,        17,       12,    },
  { 57600,    10,        37,        37,       33,    },
  { 38400,    25,        57,        57,       54,    },
  { 31250,    31,        70,        70,       68,    },
  { 28800,    34,        77,        77,       74,    },
  { 19200,    54,        117,       117,      114,   },
  { 14400,    74,        156,       156,      153,   },
  { 9600,     114,       236,       236,      233,   },
  { 4800,     233,       474,       474,      471,   },
  { 2400,     471,       950,       950,      947,   },
  { 1200,     947,       1902,      1902,     1899,  },
  { 600,      1902,      3804,      3804,     3800,  },
  { 300,      3804,      7617,      7617,     7614,  },
};

That's the value to send to the tunedDelay() function in the four different situations where its used for each of the baud rates at that specific clock frequency (16MHz in that example).
tunedDelay() itself is written in assembly code and is a very tight loop for the number of iterations specified in the parameter.  The shortest possible piece of code with the minimum of overhead to get the maximum accuracy and finest granularity (least number of clock cycles for one iteration) out of it.  

13674: <p>I was conducting some research on wireless communication between a simple transmitter and receiver module using an Arduino. Now, I tested the channel accuracy and i received 14% error for a delay of one micro second. For a delay of 2 microseconds, my error was 0%, and for three microseconds, my error rate was 30%. I am not quite sure why the data would result in this. I think it possibly has something to do with the gain on the receiver and the delay time. Some sweet spot perhaps? Can anyone offer me some ideas/explanations? Also, sorry for any confusion in this question. I am happy to clarify. </p>

<p>Part 2:</p>

<p>Hey Everyone, </p>

<p>I also had a question regarding what purpose each of the following delay serves in wireless communication. </p>

<pre><code>// Write each of the 8 bits
for (uint8_t i = 8; i &gt; 0; --i)
{
  if (b &amp; 1) // choose bit
    *reg |= reg_mask; // send 1
  else
    *reg &amp;= inv_mask; // send 0

  tunedDelay(delay);// line in question ---------------------
  b &gt;&gt;= 1;
}
</code></pre>

<p>and the delay used in the regular blink program. </p>

<p><strong>The regular delay used in the blink programs was what set the 2 microsecond delays.</strong></p>

<p>Lastly, I am looking at the read and recv methods in the software serial library and i don't see any checks for start bits, so what's the point of writing one in the write method? </p>
 10794: <blockquote>
  <p>I am looking at the read and recv methods in the software serial library and I don't see any checks for start bits, so what's the point of writing one in the write method? </p>
</blockquote>

<p>The start bit is absolutely essential in serial comms. In the graphic below, the start bit is marked "B" - which distinguishes it from "idle" data which is "A". Once received, the receiver then waits 1.5 bit times and starts clocking in the remaining bits. (Starting at "C" in the diagram, and then moving on for a total of 8 bits).</p>

<p><a href="https://i.stack.imgur.com/xmEc6.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xmEc6.png" alt="One serial byte"></a></p>

<p>Without a start bit, how would the receiver know when the byte started? Imagine you wanted to send 0xFF (all 1 bits). Without a start bit that would be indistinguishable from the idle state.</p>

<p>In the graphic, "D" is the stop bit. Why have a stop bit? We need one (which is a "1" bit), so that we can detect the transition from the stop bit in the previous byte (a "1") and the start bit in the next byte (a "0").</p>

<p>In the graphic, "E" is the start bit for the next byte.</p>

<hr>

<blockquote>
  <p>I don't see any checks for start bits ...</p>
</blockquote>

<p>SoftwareSerial has a pin-change interrupt set up to detect that the receiving pin has changed state (to a zero usually). <strong>That</strong> is your start bit. You don't see it in the loop, because it has already arrived, otherwise you wouldn't be in the receive loop in the first place.</p>
 4143: <blockquote>
  <p>Now, I tested the channel accuracy and i received 14% error for a delay of one micro second. For a delay of 2 microseconds, my error was 0%, and for three microseconds, my error rate was 30%.</p>
</blockquote>

<p>Microsecond resolution delays on an Arduino are tenuous at best.  They aren't that accurate.  Simply because you're hitting the limit of the speed of the CPU.</p>

<p>At 16MHz you have a clock period of 1/16000000 seconds.  That's 63ns.  That's the <em>granularity</em> of the delays you can achieve - and that can only be achieved by inserting a precise number of <code>NOP</code> assembly instructions.</p>

<p>So for the best 1µs delay possible you would need (0.000001 / 0.000000063) 15.87 <code>NOP</code> instructions.  Of course, you can't have that many, so you have to round it either up or down.  Normal integer truncation would result in 15.  So that would actually be a delay of 945ns, which is an error of 5.5%.</p>

<p>2µs would be (0.000002 / 0.000000063) 31.74 <code>NOP</code> instructions, which would round to 31, so 1.953µs, or an error of 2.35%.  As you can see increasing the length generally reduces the error.</p>

<p><em>HOWEVER</em></p>

<p>The delay function on the Arduino for microsecond accuracy (<code>delayMicroseconds()</code>) is maybe not as accurate as it could be.  Simply because it's impossible to just have an exact number of NOP instructions for a delay since you can't know how long the delay should be until the function is called with a parameter detailing how long the delay should be.  So it has to perform a number of calculations and <em>make a number of assumptions</em>.  It tries to come close, but it was written for one specific version of the compiler and compilers change. Things may have been changed in how the function gets called, and how long parts of it take (what registers are pushed and popped may change with different compiler versions, for instance).  So it's not a perfectly reliable delay.</p>

<p>For more detail you can look at the source code of it (it's in <code>wiring.c</code>) and you can see how for small delays it's very hard to get it right. For instance, this couple of lines highlights the problem nicely:</p>

<pre><code>    // for a one-microsecond delay, simply return.  the overhead
    // of the function call yields a delay of approximately 1 1/8 us.
    if (--us == 0)
        return;
</code></pre>

<p>Note the use of the word <em>approximately</em> there...</p>

<p>Also you need to note that the delay functions are just that - a delay <em>at that specific moment in time from the start of the call to its finish</em>.  It doesn't take into account anything else that's going on in your code, so a delay of 1µs in a loop of code that does other things will end up in a loop that takes <code>X + 1µs</code> where <code>X</code> is the amount of time that the rest of the code takes to execute.</p>

<p>And that's where the <code>tunedDelay()</code> function comes in.  It has been specially written to be used in that specific circumstance to provide a delay that <em>takes into account the time the rest of the loop takes to run</em>.  That is, the loop's time plus the <code>tunedDelay</code> time equate to the final period you want for the whole loop.  For asynchronous serial communications the timing accuracy is important.  Since there is no separate (or even embedded) clock to get the timing from both ends have to agree what speed the communication happens at (the baud rate), and any deviation from that can cause communication errors.  So the timing has to be as close as possible. A normal <code>delayMicroseconds()</code> function call just wouldn't cut the mustard - they needed it more precise than that.  Manually tuned to have specific delay values that are as precise as possible, and that was done for specific baud rates on specific speed chips.  Each supported frequency has a table such as this:</p>

<pre><code>static const DELAY_TABLE PROGMEM table[] =
{
  //  baud    rxcenter   rxintra    rxstop    tx
  { 115200,   1,         17,        17,       12,    },
  { 57600,    10,        37,        37,       33,    },
  { 38400,    25,        57,        57,       54,    },
  { 31250,    31,        70,        70,       68,    },
  { 28800,    34,        77,        77,       74,    },
  { 19200,    54,        117,       117,      114,   },
  { 14400,    74,        156,       156,      153,   },
  { 9600,     114,       236,       236,      233,   },
  { 4800,     233,       474,       474,      471,   },
  { 2400,     471,       950,       950,      947,   },
  { 1200,     947,       1902,      1902,     1899,  },
  { 600,      1902,      3804,      3804,     3800,  },
  { 300,      3804,      7617,      7617,     7614,  },
};
</code></pre>

<p>That's the value to send to the <code>tunedDelay()</code> function in the four different situations where its used for each of the baud rates at that specific clock frequency (16MHz in that example).</p>

<p><code>tunedDelay()</code> itself is written in assembly code and is a very tight loop for the number of iterations specified in the parameter.  The shortest possible piece of code with the minimum of overhead to get the maximum accuracy and finest granularity (least number of clock cycles for one iteration) out of it.  </p>
