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 4D OLEDS with Arduino 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.
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?
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*)
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.
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.
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.
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)
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.
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.
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.
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.
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, 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...
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.