Similar Code - Drastically Different Results

In the code below, there are four blocks of comments. Although the code in each block is different, I would expect the same resulst to be printed to the console. However, only the fourth block produces the correct results. I anticipate the differing results are due to the actual hardware (pipelining, or some other timing related issue) and not the code. Could some please explain to me what is going on in the hardware that causes the differing results?

void loop() {
  unsigned long data[12] = {0};
  int i;
  
  while(pulseIn(pin, LOW) < 2200);
  
/*   
  for(i = 0; i < 12; i++)
    Serial.println(pulseIn(pin, HIGH)); 
*/


/*  
  for(i = 0; i < 12; i++) {
    data[i] = pulseIn(pin, HIGH);
    Serial.println(data[i]);
  }   
*/

/*  
  for(i = 0; i < 12; i++) {
    data[i] = pulseIn(pin, HIGH);
    delay(500);
    Serial.println(data[i]);
  }   
*/

/*
  for(i = 0; i < 12; i++) 
    data[i] = pulseIn(pin, HIGH);  

  for(i = 0; i < 12; i++)
    Serial.println(data[i]);
*/

  Serial.println("\n");

}

I'm not sure why you would expect the same results to be printed, as they're all different. One even has a 500ms delay! You might get the same results if you were looking at a uniform waveform.

Serial IO takes time; Serial.print() blocks (does not return) until the next-to-last character is printed. Depending on your input waveform, this could allow time for many pulses to be missed.

-j

Serial.print() blocks (does not return) until the next-to-last character is printed.

This is incorrect.

It will block only if data is still being sent (from a previous call).

Yes it [u]is[/u] correct; I've watched discussions on the developer's list concerning the issue since it concerns some projects of mine.

I may be off by ~one character, e.g. it may return when the next-to-last character is being sent, but in the case of a print that generates more than two bytes it will most definitely block. Serial.prinln(float) will generate at least 5 bytes which will block for at least 3 characters which translates to 3ms at 9600 baud.

-j

Yes it is correct; I’ve watched discussions on the developer’s list concerning the issue since it concerns some projects of mine.

I watched nothing, but I did read the code.

http://code.google.com/p/arduino/source/browse/trunk/hardware/arduino/cores/arduino/HardwareSerial.cpp#206

void HardwareSerial::write(uint8_t c)
{
  while (!((*_ucsra) & (1 << _udre)))
    ;

  *_udr = c;
}

I watched nothing, but I did read the code.

This is not the code referred to however.

In relation to "Serial.print", it will be challenging to sum up the behavior more accurately than " blocks (does not return) until the next-to-last character is printed".

In relation to "Serial.print", it will be challenging to sum up the behavior more accurately than " blocks (does not return) until the next-to-last character is printed".

I guess ::) (but only for strings longer than 1 character)

but only for strings longer than 1 character

Not really - it will still apply as written.

Good for you. Now take some time to understand it, then go read the code that calls this function, then maybe the code that calls that function, then think a bit.

For starters you'll find no output buffer beyond the single byte in the hardware output buffer. A buffer to store the as-yet untransmitted data [u]must[/u] exist if non-blocking output is implemented. There's also the matter of needing code to service the nonexistent output buffer.

The function you pasted will return as soon as it can transfer the byte (check the parameters, write only operates on single bytes) into the USART output buffer. IIRC there's some buffering of the last bit of a byte, so that the one byte system buffer is available 2 or more bit times (depending on number of stop bits , number of parity bits, etc) before the previous byte is completely transmitted.

The net effect of all this is that all Serial.print() calls of more than 1 byte block while (effectively) n-1 bytes are written. Since the code originally posted is a serial.println(long int) There will be a minimum of 2 bytes up to a maximum of 12 bytes printed by this call, which means 1 to 11 bytes will be transmitted before Serial.println() returns.

-j