Working with Serail

Hello all,
I want to send a value 0-10 in a single byte over serial. To this end, I have chosen to use ":" to represent 10, as it falls directly after "9" on the ascii chart. The following code does not achieve what I want.

Serial.print(setHoursTens == 10 ? ':' : setHoursTens);

Instead of sending ":", it sends "5" followed by "8" How can I get it to send ascii : instead? Can it still be done with a ternary operator?

Why not send A instead?
0,1,2,3,4,5,6,8,9,10,11,12,13,14,15

or hex equivalent
0,1,2,3,4,5,76,8,9,A,B,C,D,E,F

Try to cast setHoursTens to a byte too before sending

CrossRoads:
Why not send A instead?
0,1,2,3,4,5,6,8,9,10,11,12,13,14,15

or hex equivalent
0,1,2,3,4,5,76,8,9,A,B,C,D,E,F

on the receiving side, 0-10 is an index to an array, which I can get easily by subtracting '0' from the received char.

arduino_new:
Try to cast setHoursTens to a byte too before sending

setHoursTens is a byte. Serail.print() prints the ASCII value of the byte, so for 0-9 it sends 48-57 but for ':' it sends 53 followed by 56.

Ok, makes sense looking at asciitable.com

Try sending 0x3A vs ':'

Use Serial.write instead of Serial.print.

Edit: Oh, and you probably want to add '0' to setHoursTens:

Serial.write(setHoursTens == 10 ? ':' : setHoursTens + '0');

But since ':' comes right after '9' in ASCII, you can simplify to this:

Serial.write(setHoursTens + '0');

christop:
Use Serial.write instead of Serial.print.

perhaps

Serial.write((setHoursTens + 48));

CrossRoads:
Try sending 0x3A vs ':'

still sends "5 and "8"

As far as I know .write() should just send a single byte. Do you receive 0x05 0x08 or ‘5’ ‘8’ (values vs ascii char)?

septillion:
As far as I know .write() should just send a single byte. Do you receive 0x05 0x08 or ‘5’ ‘8’ (values vs ascii char)?

.write() did the trick, so thanks to @christop for the suggestion. When using .print() I would get ascii characters 5 and 8 with .print(’:’);. With .write(), I could still use ternary operators to qualify my output if necessary, but it also eliminated the need in many lines.

Ahh, okay. It seems like the compiler thinks ':' is an unsigned char and thus calls .print(unsigned char) which is the same as .print(int) which calls .printNumber() which prints the value in ascii.

I have to say, I did expect ':' to be a signed char and thus calling .print(char) which is just a different name of .write(char).

septillion:
Ahh, okay. It seems like the compiler thinks ‘:’ is an unsigned char and thus calls .print(unsigned char) which is the same as .print(int) which calls .printNumber() which prints the value in ascii.

I have to say, I did expect ‘:’ to be a signed char and thus calling .print(char) which is just a different name of .write(char).

I think (I could be wrong) that C++ converts the ‘:’ to byte (the same as setHoursTens) so that the ternary operator yields the same type regardless of which branch is taken.

I did a quick read and saw a character literal is a int in the C days and a char in the C++ days. And I thought the compiler threatens variables as not explicitly defined as unsigned. But that's where I might be wrong...

I don't expect it to have something to do with the ternary operator or the variable type of setHoursTens. Compiler can compare signed and unsigned just fine.

septillion:
I don't expect it to have something to do with the ternary operator or the variable type of setHoursTens. Compiler can compare signed and unsigned just fine.

This seems to answer the question:

C++ draft standard

5.16 Conditional operator:
Otherwise, if the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other.

It further describes which operand will be chosen to be converted to the type of the other. In the case with char and byte (aka unsigned char) in the second and third operands of the conditional operator, the char value is converted to byte because unsigned types are preferred when two different types have the same rank.

Ahh, you're right! Thank you! One of the weirder pitfalls :smiley: I was not aware the ternary did manipulation on it's arguments so to speak.

And does indeed explain why .print(unsigned char) aka .printNumber() is called instead of .print(char) aka .write() :smiley:

Yeah, it is one of those dark corners of the language that I don't venture into very often!

And I didn't actually read that section very closely. What I quoted is only for class types. :-[

The actual part farther down in the same section that applies (for arithmetic types) is this:

The second and third operands have arithmetic or enumeration type; the usual arithmetic conversions are performed to bring them to a common type, and the result is of that type.

The result is the same, though.