-2

What is the best way to convert a unsigned 16 bit integer into ASCII HEX? I'm trying to integrate my Arduino with a serial communication protocol that expects the payload as an array of 2 byte ASCII HEX values. I'd like to be able to store each character of the HEX representation in a char array since the full message (with start and stop characters) needs to be CRC checksummed before being transmitted.

For example, to transmit a decimal value of 129, it would expect a string 0081 (0x00 and 0x81). To transmit a decimal value of 35822, it would expect a string of 8BEE.

I mostly work with Python so I'm not very familiar with casting to different data types.

Thanks!

EDIT: I'm actually working with a Teensy 4.0, just wrote Arduino out of habit

the busybee
  • 10,755
  • 3
  • 13
  • 30
popc0rnx
  • 13
  • 2
  • The *string* `"0081"` is very different from the two-byte value `0x0081`. For starters, the string is *five* bytes. – Some programmer dude Sep 10 '21 at 15:09
  • The operations would be very similar in Python and C/C++. Shift and mask the number to isolate 4 bits at a time, then use that 4-bit number as an index into a string of hex digits. – Mark Ransom Sep 10 '21 at 15:09
  • Doesn't the sprintf format `%X` do what you want? – Barmar Sep 10 '21 at 15:10
  • 2
    @Barmar on Arduino sprintf takes more than 1/3 of the available memory :) – 0___________ Sep 10 '21 at 15:12
  • you can use sprintf or the CStringBuilder class from my StreamLib (available in Library manager) – Juraj Sep 10 '21 at 15:12
  • I'm not sure I understand "_ASCII HEX_" and "_2 byte ASCII HEX values_". For a `uint16_t`, how many bytes are you expected to send? 2 or perhaps 4 (as ASCII)? – Ted Lyngmo Sep 10 '21 at 15:12
  • @TedLyngmo the question seemed pretty clear to me, 4 digits representing 2 bytes. – Mark Ransom Sep 10 '21 at 15:13
  • @MarkRansom I thought so at first but then I was thinking that OP may have misunderstood the requirement. – Ted Lyngmo Sep 10 '21 at 15:14
  • @0___________ As long as it fits into the memory and performance requirements, it's perfectly OK to use any high-level functions. – the busybee Sep 10 '21 at 15:14
  • Could you paste up the code you use to send the string? And hardcode the string value. Then we will have a clearer sense of the requirement. Cheers, – Bathsheba Sep 10 '21 at 15:15
  • @thebusybee yes if you want to blink LED then no prob – 0___________ Sep 10 '21 at 15:20
  • @Barmar ahh yes that sounds like exactly what I'm looking for. Like I said, I'm basically clueless haha – popc0rnx Sep 10 '21 at 15:36
  • @0___________ Remember the times when personal computers had as low as 16 KB of memory? We ran word processors in there, spread sheets, and C and Pascal compilers and their generated executables, without the need of premature optimization. So please don't overestimate the memory needs of the majority of embedded applications. -- I don't care how big the share of used libraries is in the executable as long as it fits and my source is well written and easily maintainable. Any line not written for the project avoids a chance of an error. – the busybee Sep 10 '21 at 18:19
  • @thebusybee `Remember the times when personal computers had as low as 16 KB of memory?` When IBM PC had 16kB programming in assembler was something normal at that time (or Basic). No compilers were available. `without the need of premature optimization.` At the time programming was a big and total optimization. Pascal compiler was available only for the PCs having two floppy stations and 256kB RAM. – 0___________ Sep 10 '21 at 18:54
  • @thebusybee the pas2.exe was more than 100k in size. So I think you do not really remember those times – 0___________ Sep 10 '21 at 18:59
  • @0___________ The CP/M version needed much less memory and worked without the disk if you liked. x86 machines are not the only PCs, and the [ZX81](https://en.wikipedia.org/wiki/ZX81) (8KB ROM, 1KB RAM) was not the first computer I used. Its case already had "Personal Computer" on its bottom. – the busybee Sep 10 '21 at 20:46
  • ZX81 was not very usable before 16k expansion. But it was world of nano ( not even micro) optimizations. I was writing a lots of code for zx-81 & zx spectrum. As an example of nano optimization - all were using "illegal" or maybe only not documented Z80 instructions :). – 0___________ Sep 10 '21 at 21:24

1 Answers1

3
static const char *digits = "0123456789ABCDEF";

char *toHex(char *buff, uint16_t val, int withNULL)
{
    buff[0] = digits[(val >> 12)];
    buff[1] = digits[((val >> 8) & 0xf)];
    buff[2] = digits[((val >> 4) & 0xf)];
    buff[3] = digits[(val & 0xf)];
    if(withNULL) buff[4] = 0;
    return buff;
}

char *toHex1(char *buff, uint16_t val, int withNULL)
{
    unsigned char d;
    buff[0] = (char)((d = (val >> 12)) > 9 ? ('A' + d - 10) : ('0' + d));
    buff[1] = (char)((d = ((val >> 8) & 0xf)) > 9 ? ('A' + d - 10) : ('0' + d));
    buff[2] = (char)((d = ((val >> 4) & 0xf)) > 9 ? ('A' + d - 10) : ('0' + d));
    buff[3] = (char)((d = (val & 0xf)) > 9 ? ('A' + d - 10) : ('0' + d));
    if(withNULL) buff[4] = 0;
    return buff;
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • `'A' + d - 10` is not portable. A portable solution is within reach given you've taken the time to define `digits`. – Bathsheba Sep 10 '21 at 15:23
  • 1
    @Bathsheba it is for arduino - it does not have to be portable at all. Secondly OP should check which one generates smaller code for 8 bit Atmega. – 0___________ Sep 10 '21 at 15:25
  • 1
    @Bathsheba two different approaches were presented, and the first is the portable one you're looking for. And while the second might not be portable to an IBM mainframe, I've never actually used a system myself where it wouldn't work. – Mark Ransom Sep 10 '21 at 15:25
  • @Bathsheba actually I'd be more concerned whether `d =` is guaranteed to define `d` before the ternary expressions are evaluated. – Mark Ransom Sep 10 '21 at 15:28
  • @MarkRansom it is guaranteed – 0___________ Sep 10 '21 at 15:30
  • @MarkRansom: It is. ? and : are sequencing points in C and C++. – Bathsheba Sep 10 '21 at 15:30
  • Sorry for trolling the answer. Have an upvote for good feelings ;-) – Bathsheba Sep 10 '21 at 15:30
  • @0___________ I'm actually working with a 32 bit Teensy 4.0, just wrote Arduino out of habit as that's been my previous experience – popc0rnx Sep 10 '21 at 15:30
  • 1
    @Bathsheba except for the fact that the digits are in the opposite order from what's specified in the question, but that's easily fixable. – Mark Ransom Sep 10 '21 at 15:31
  • @MarkRansom good spot. Too many hours of programming as for Friday :). It is time to start the weekend – 0___________ Sep 10 '21 at 15:37