serial.print or serial.write?

Hi,

Could someone explain what the difference is between using Serial.print(value, BYTE) or Serial.write(value) ? I've read the reference but somehow i couldn't understand what the difference is.

I'm writing some functions for a 4d uoled-160-g1 display connected to a serial connection on my arduino mega. I've found a library at http://jennylc.com/4d/ to give me a general direction but that uses the (old?) printByte function. I've got it all working with the Serial.write(value) except if i wanted to send 0 (zero) to send as a terminator.

Thanks in advance,

Jeroen

According to the documentation, Serial.print(value, BYTE) converts the value to the ASCII character that corresponds to value, and sends that character. Therefore, it is valid only for values that are in the range 0 to 255.

Serial.write, on the other hand, streams the bit pattern for value. Therefore, it will send any one-byte value as is.

What happens when you user Serial.write to send a 0?

Thanks for the explanation but...

Therefore, it will send any [u]one-byte[/u] value as is.

Isn'n a one-byte value a value in the range of 0-255?

Not to be a smart-a.., i just don't get it.

What happens when you user Serial.write to send a 0?

The ide spits an error at me while verifying. Here it is.

error: call of overloaded 'write(int)' is ambiguous

And the full tekst in the black 'terminal'

In function 'char OLED_DrawText(char, char, char, char*, int)': error: call of overloaded 'write(int)' is ambiguousC:\Documents and Settings\hgn\My Documents\arduino-0017-PROG\hardware\cores\arduino/HardwareSerial.h:53: note: candidates are: virtual void HardwareSerial::write(uint8_t)

C:\Documents and Settings\hgn\My Documents\arduino-0017-PROG\hardware\cores\arduino/Print.h:39: note: virtual void Print::write(const char*)

Thanks for your time,

Jeroen

The compiler is right. There are many ways to interpret a 0. If you want it to interpret it a specific way, you need to help it out a little.

You could do this:

int i = 0;
Serial.write(i);

The compiler now doesn't know anything about the specific value. It just knows that you want to write an int, so it selects the overloaded method that writes ints.

You could also do this:

Serial.write((int)0);

This casts the value to an int, so, again the compiler can choose the correct method.

I find the first method easier to understand, but they both achieve the same result.

"Therefore, it will send any one-byte value as is. "

"int i = 0; Serial.write(i);

But an int is 16 bits long, two bytes. So does it just send one byte or two? if one, the hi or low byte?

Lefty

Serial.write() expects a byte argumet (8 bits). If you call this method with an int (16 bit) argument , the compiler will complain because there is no write method in the serial class that will accept int arguments.

If you want to use Serial.write to print the lower 8-bits as a byte you need to help the compiler (using a type cast) as follows:

Serial.write((byte)val16)

When you call Serial.print(val,BYTE) this will end up as a Serial.write((byte)val). Serial.print will check the second argument (BYTE) and call write accordingly.

So in terms of output Serial.print(val,BYTE) and Serial.write(val) are functionally identical.

Thanks for your time all,

So in terms of output Serial.print(val,BYTE) and Serial.write(val) are functionally identical.

Is there a reason to use one OR the other? Just nittpicking but i'm thinking to use the Serial.print(val,BYTE) because that is what i'm seeing the most in other sketches. Besides that i think its nicer to pick one and stick with it in one sketch.

Thanks again,

Jeroen

The Serial.print(value, BYTE) method will handle non-byte size inputs, sending multiple bytes as required.

The Serial.write() method won't.

If you are sending bytes, it doesn't matter which you use. If not, it might. Depends on whether the loss of the high order bytes is important, or not.

As far as i can see (understand) from the datasheet all commands/data is send in 1 byte chunks. The 16bit colour is sent in 2 bytes (msb:lsb). For example;

#define      OLED_LINE            0x4C   //command for drawing a line

void OLED_DrawLine(char x1, char y1, char x2, char y2, int color) {
  // Line drawing
  Serial1.write(OLED_LINE); // Line
  Serial1.write(x1);          // x1
  Serial1.write(y1);          // y1
  Serial1.write(x2);          // x2
  Serial1.write(y2);          // y2
  // Color
  Serial1.write(color >> 8);            // MSB                  
  Serial1.write(color & 0xFF);            // LSB
}

OLED_DrawLine(5, 5, 100, 5, 63488);    //void OLED_DrawLine(char x1, char y1, char x2, char y2, int color)

For completeness or anyones interest the link to the datasheet of the display. http://www.4dsystems.com.au/downloads/micro-OLED/uOLED-160-G1/Docs/uOLED-160-G1_Users_Manual_Rev1.0.pdf

My question is answered (i think).

Jeroen

The serial protocol is byte oriented and anything sent will have to be converted to one or more bytes and sent sequentially. The Serial.print variants were added to make conversion to a byte stream straight forward and easy to use. E.g. printing the decimal number 123 will end up as the three bytes/characters '1', '2', and '3'.

Once print has done the appropriate coversions (decimal, long, float, string, hex, bin etc.), the individual bytes will be passed to Serial.write which is the only function that actually send bytes to the hardware.

You may argue that using Serial.write is a tad more efficient than calling Serial.print(val,BYTE) since no conversion will take place and "val" will simply be passed on to Serial.write. This is typically not much of an issue however - so either format will be just fine.

Thanks BenF,

Especially

the individual bytes will be passed to Serial.write which is the only function that actually send bytes to the hardware.

made it clear to me.

From the point of (thought of) overhead i'll stick to Serial.write(); and change Serial.print(0, BYTE); to int i = 0; Serial.write(i);

Thanks all,

Jeroen

Is that correct? Doesn't:

From the point of (thought of) overhead i'll stick to Serial.write(); and change Serial.print(0, BYTE); to int i = 0; Serial.write(i);

Cause a complier error told here:

Serial.write() expects a byte argumet (8 bits). If you call this method with an int (16 bit) argument , the compiler will complain because there is no write method in the serial class that will accept int arguments.

Lefty

That's correct retrolefty. What i meant was

byte i = 0;
Serial.write(i);

The int version does give the compiler error.

Thanks,

Jeroen

From the point of (thought of) overhead i'll stick to Serial.write();

I have a hard time believing that, for serial communications at 9600 baud, the overhead of one extra function call could be significant.

It seems to me that the best coding practice would be the one that is the clearest and easiest to read and understand.

Obviously i want to stick by the "1 make it work" then "2 make it readable" and "3 make it fast" rules in that order. I think that in my sketch it wouldn't make that much of a difference in readability if i used the Serial.print(value, BYTE) or the Serial.write(value) method other than that the reader has to know the difference. (at this time, me. hehe)

About the baudrates used. I use 115200 for debugging on my computer and 57600 for the connection to the display. The display accepts speeds up to 256000 but at 115200 i had some glitches (1 out of 50 or so transmissions failed) I don't know what the extra overhead will be if i used the Serial.print(value, BYTE) over the Serial.write(value) method but the word 'overhead' alone pushes me to the Serial.write(value) side.

Thanks for the thoughts,

Jeroen

I agree about the readability. Since your data is not text, Serial.write seems to makes more logical sense, while Serial.print implies human-readable data (to me).

I'm not an expert but my understanding is that the extra overhead of Seril.print is probably a few instructions and a function call. Even at high baud rates, I'm guessing that would be just roundoff errors in performance.

But I'm really just speculating and waiting for a more knowledgeable geek to chime in here on this increasingly prolonged (by me) discussion of marginal utility.

;D

Prolonged discussions of marginal utility. What a luxury isn't it? :)

Jeroen

Prolonged discussions of marginal utility. What a luxury isn't it?

Maybe, but it's not unlike the use of Arduino pin numbering Vs direct port I/O access. The first is more readable and portable across the various AVR chips but it does carry a speed penalty compared to the second method. So it's nice to be educated about both methods, their trade-offs so that one's application can point to the best method needed.

Lefty

Lefty, you're good at performance calculations. Any estimates on the Serial.print vs Serial.write runtime overhead? Of academic interest and pure curiosity, at this point...

Lefty, you're good at performance calculations.

Nah, I'm more of a electronics hardware guy, still learning C/C++ and the class stuff really kind of confuses me a little, no more like a lot, ;) Someone more qualified would have to tackle your question.

I do know that the speed difference (as seen on a scope) between using Arduino pin statements Vs direct acess I/O was pretty significant. Again it's not important for all applications but where you really need to flip the bits in min time it's a good tool to have around.

Lefty