Go Down

Topic: Print commands are not consistent (Read 1 time) previous topic - next topic

gen2thomas

I have used the Serial.print() command:
Code: [Select]

int aValue=32;
Serial.print(aValue); //give you "32"
Serial.print((uint8_t)aValue); //give you a space " "


Do this make a sense?

In my opinion each normal call should reply the bytes (byte by byte for long data types).
Print with special bases should be switched on with second parameter in all cases.

mem

#1
Jul 12, 2009, 05:59 pm Last Edit: Jul 12, 2009, 06:00 pm by mem Reason: 1
It makes complete sense as it's currently implemented.
Print of an 8 bit character prints the character. Print of a 16 or 32 bit value prints the value. It may seem odd to have the apparent behaviour change but it would be very strange to have print('a') print anything other than the character a.

pwillard

#2
Jul 12, 2009, 06:02 pm Last Edit: Jul 12, 2009, 06:04 pm by pwillard Reason: 1
Yes, it makes sense.  the 32 is not a number anymore... it is ASCII character for "3" and then for "2". You think you sent the value of 32... but you sent ASCII code for  "51" then "50" when using the PRINT statement.

SERIAL TRANSMISSION sends ASCII codes so that's what Serial.print does.

AWOL

#3
Jul 15, 2009, 10:43 am Last Edit: Jul 15, 2009, 10:44 am by AWOL Reason: 1
Quote
SERIAL TRANSMISSION sends ASCII codes

Nonsense; it sends binary.
ASCII only defines 128 codes, but serial transmission allows you to transmit 256 different values.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

mem

#4
Jul 15, 2009, 11:12 am Last Edit: Jul 15, 2009, 11:13 am by mem Reason: 1
The behaviour the OP has raised is not about ASCII, extended ASCII or binary. Its about the way Arduino print routines differentiate on the type of value passed to the print function.

When printing a char or byte, Arduino will send this as a single byte (it doesn't care if its ASCII or not). When printing a 16 or 32 bit integer or a float, it will send this as the string of characters that represent the value.

If the receiving side displays these as ASCII values (as does the Arduino Serial Monitor) you would see the (extended) ASCII value of a printed character (or byte), or the numerals representing the value of integers or floats.

gen2thomas

Serial.print(aValue,BYTE); //is confusing because BYTE=0 and this base couldn't handled with mathematical correctness

Next Problem: In actual arduino this will print for types with n x byte (int, real, float, double etc.) only the first byte!

My suggestion:
Serial.print(aValue);       //should always and ever send bytes
Serial.print(aValue,DEC); //should send a number as ASCII-Char
Serial.print(aValue,HEX); //should send a number as ASCII-Char
Serial.print(aValue,8);     //should send a number as ASCII-Char

DEC=10, HEX=16

Following this logic you don't need anymore the base BYTE (=0)!

mem

#6
Jul 15, 2009, 05:59 pm Last Edit: Jul 15, 2009, 06:00 pm by mem Reason: 1
I think it works well just as it is. The parameter when non zero is treated as the base used to display value, and when zero the character rather then the value is displayed.

I think most Arduino users would be surprised if the following did something other than print the digits "1234" to the serial monitor.
int  value = 1234;
Serial.print(1234);

If I understand your suggestion, your version would print whatever is the ascii value of 0xD2 - which is not what I think most Arduino users would want to see.

EmilyJane

I would be surprised now that I know what is supposed to happen. I'm not that fluent in c/c++ so I don't know if Arduino's behavior is logical or not.

I'll have to admit, I found it very counter-intuitive at first.

mem

what would you have expected this code to do?
 int  value = 1234;
 Serial.print(1234);

EmilyJane

I think I would have either expected an error or have it truncated to 0xd2. To me, a serial device is byte oriented and I would expect to have to do something special to have it print a character string.

I'm not complaining, mind you. :)

mem

#10
Jul 15, 2009, 06:44 pm Last Edit: Jul 15, 2009, 06:46 pm by mem Reason: 1
That example was meant to be
 int  value = 1234;
 Serial.print(value);

I guess your expectation would be the same.

But would you expect  
 int  value = 1234;
 lcd.print(value);
to truncate to 0xd2 ?

would you want it to?

EmilyJane

Only because I know that the LCD class derives from Print. Otherwise, I wouldn't expect it to do anything until I wrote a driver.

mem

#12
Jul 15, 2009, 07:23 pm Last Edit: Jul 15, 2009, 07:26 pm by mem Reason: 1
Quote
?Otherwise, I wouldn't expect it to do anything until I wrote a driver.

I think many of the design decisions taken by the Arduino team were to ensure that users did not need to know what a driver was, let alone think about writing one  ;)

Those of us that do understand the plumbing should accept that we are not the primary audience for Arduino

EmilyJane

Exactly!

My background is in embedded controller/processor design and while I have written nE5 lines of assembly language having any kind of high level language support has always been a luxury. The c compilers available for 8/16 bit chips usually concentrate on port and bit manipulation and if they do arithmetic at all it's normally integer only.

Consequently, Arduino is a real M-series in my opinion and for the tasks it was designed to do, I wouldn't use anything else.

The fact that some things seem a little nonintuitive to me is of no consequence, as they are quickly learned. I discovered a long time ago that it's more productive to use the tools you have than to piss and moan about the ones you wish you had. Besides, tomorrow is another day. ;)

bhagman

#14
Jul 22, 2009, 07:55 pm Last Edit: Jul 22, 2009, 08:16 pm by bhagman Reason: 1
I think the OP is trying to illustrate the inconsistency of the "print" method overloading.  Specifically, the difference between "print"ing an int versus a uint8_t.

I've already experienced this problem.  Here is some more code to clarify the problem:

Code: [Select]
uint8_t mybyte;         // this is UNSIGNED
int myword;             // an int is 16bits - explicitly: int16_t (from stdint.h)

myword = 32;
mybyte = myword;

Serial.print(myword);   // prints "32" - as expected
Serial.print(mybyte);   // prints " " - not exactly intuitive


Herein lies the problem:
What do you do with a byte?  Since a byte === unsigned char, do you print it as a series of characters in a readable format representing the number (e.g. "32")?  Do you send the direct value of the byte over the serial connection?  It's unclear, because the data type is ambiguous.

A more clearly defined Print Base Class would solve this problem.

For example, for consistency, Print::print(uint8_t n) should be:
Code: [Select]
void Print::print(uint8_t n)
{
 print((long) n);
}


and for clarity, a new method should be added:
Code: [Select]
void Print::printchar(char c)
{
 this->write(c);
}


Unfortunately, this will break a LOT of current code, since people have already accepted that Serial.print((uint8_t)32) prints a space.

The OP is saying that instead of assuming that "print"ing a uint8_t means to send a direct value over the serial connection, it should be "print"ed in the same way as a long value.  Furthermore, the OP is saying that to print a byte directly, it should be explicit, e.g. print(mybyte, BYTE).  I'm not complacent with that format (if anything BYTE should be changed to DIRECT - semantically differentiating the methods).  "print" should be consistent - i.e. always printing readable characters or such.

Again, this will break a lot of code.

b

Go Up