|
|
View previous topic :: View next topic |
Author |
Message |
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
Converting characters in a serial buffer.... |
Posted: Thu Sep 10, 2020 8:47 am |
|
|
Hi All,
I'm receiving a serial message in the format:
In this case, the '3' is the node number of a remote device, and can be any number from 1 to 5, and '1' is the state of this devices output, and can be any number from 0 to 2. In my code, I have an array 'NodeStatus' that contains the output state for all the connected nodes. So, I need to extract the node number and the output state contained in the serial message to fill my array.
NodeStatus is defined as:
Code: |
int8 NodeStatus[6] = {0,0,0,0,0,0}; //0 = Unavailable, 1 = Off, 2 = On
|
I'm doing it like this:
Code: |
//Here we check if there are any pending Node reply messages!
if (Node_Msg_Ready == True){
Node_Msg_Ready = False;
fprintf(Diag, "Node Reply Msg: %s\n\r", Node_Msg_Buffer);
fprintf(Diag, "Node Number Received: %u\n\r", AsciiToHex(Node_Msg_Buffer[2]));
fprintf(Diag, "Node Value Received: %u\n\r", AsciiToHex(Node_Msg_Buffer[5]));
//Note: We subtract 1 from the node number as our NodeStatus array is 0 based.
NodeStatus[AsciiToHex(Node_Msg_Buffer[2]) - 1] = AsciiToHex(Node_Msg_Buffer[5]);
}
|
Here is my AsciiToHex routine:
Code: |
char AsciiToHex(char Digit)
{
//This routine takes an uppercase ASCII hex character (0 - 9) and (A - F) and converts
//the character to a binary representation.
//Here we check if the char is an ASCII hex char
if ((Digit < '0') || (Digit > 'F') || ((Digit < 'A') && (Digit > '9')))
break;
//Here we convert the ASCII hex char to binary and return the value
Digit -= 0x30;
if(Digit > 9)
Digit -= 7;
return(Digit);
}
|
My issue is that his code correctly extracts the node number and state, but does not seem to manipulate the array correctly. I suspect that the printf statement is formatting these values to appear correct, but that I'm actually not working with what I think?
Here is the diagnostics that are printed when a serial message is received:
Quote: |
Node Reply Msg: !N3:Q1
Node Number Received: 3
Node Value Received: 1
NodeStatus[0] = 0
NodeStatus[1] = 0
NodeStatus[2] = 0
NodeStatus[3] = 0
NodeStatus[4] = 0
|
Any thoughts on what I'm doing wrong?
Thanks,
Jack |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1348
|
|
Posted: Thu Sep 10, 2020 10:06 am |
|
|
Your IF statement is wonky. The 3rd check (<'A') will fail if you receive a number '0' to '9' as all of those are less than 'A'.
Also, even if you get through with a letter, you are subtracting 0x30 from the letter which doesn't work out mathematically. For example, 'A' is 0x41. 0x41-0x30 = 0x10 = 16 decimal, and it is supposed to be 10 decimal. Even with your -7, it would be incorrect.
Start with fixing your IF and then fix math. When you do your math, you will need two different equations, one for numbers and one for the letters.
There are functions like atoi() available that can do this for you as well, though you will need to convert your character to a short string with a null character at the end.
EDIT: If I were gonna do it, I would break this up into 3 sections:
1. Digit between '0' and '9': subtract '0' from the result
2. Digit between 'A' and 'F' subtract 'A' from the result and add 10 decimal
3. return an error (0xFF for example) if the input does not fit the first two (but you would need to check this in your code before using it..you wouldn't want to access a bad array value if you had an error) |
|
|
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
|
Posted: Mon Sep 14, 2020 1:06 pm |
|
|
Hi All,
Well, thanks for the input! In the end, I was never able to get the method of converting the ASCII character representing '0' to '5' to the numerical value 0 to 5. That approach would seem to work for a while, and then my program would start behaving very strangely, and/or crash, so I suspect I was coming up with an occasional array indices that was out-of-bounds....
So, I swallowed my pride and took a much more 'brute force' approach like this:
Code: |
if (Node_Msg_Buffer[5] == '0') TempVar = 1; else TempVar = 2;
switch (Node_Msg_Buffer[2]){
Case '1':
NodeStatus[0] = TempVar;
break;
Case '2':
NodeStatus[1] = TempVar;
break;
Case '3':
NodeStatus[2] = TempVar;
break;
Case '4':
NodeStatus[3] = TempVar;
break;
Case '5':
NodeStatus[4] = TempVar;
break;
}
|
Pretty? No! Working? Yup!!
Jack (hanging my head in 'C' shame.....) |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Sep 14, 2020 2:32 pm |
|
|
Hay if it works, it's GOOD !!
I was thinking the CCS function ATOI() might somehow be used but.....as long as what you code works, and YOU understand it, that's all that really matters.
I ain't no 'C' wizard either !!
I mumble and fumble but in the end 'stuff works'.
Besides I'm too old to goto school !
Jay |
|
|
AESPOSITO
Joined: 28 Jul 2020 Posts: 4 Location: Arizona
|
Num2Hex2Num |
Posted: Thu Sep 17, 2020 2:19 pm |
|
|
I keep files I call "Globals.c" and "Globals.h" for various projects;
The snippets here avoid using any string functions for speed.
Code: |
Header file:
//----------------------------------------------------------------------------
#DEFINE Num2Hex(i) if(i>9){i+=0x37;}else{i+=0x30;}
// converts 0-15 to hexadecimal character (4 bit nibble)
int8 HEXnibble[2]; // declare
// use union for converting to and from different bit-length operations
union uxl {
int32 asLong; // Long is actually double long
int16 asWord[2];
signed int16 asSWord[2];
int8 asByte[4];
signed int8 asSByte[4];
int1 asBit[32];
} XferLW;
//----------------------------------------------------------------------------
C file:
//----------------------------------------------------------------------------
int8 Hex2Num(char h) { // convert ASCII Hexadecimal characters
int8 x=0;
if(h<65) {
if((h<58)&&(h>47)) { x=h-48; } // numbers
if(h<16) { x=h; } // hexnumber
}
else {
if(h<71) { x=h-55; } // upper case
else { x=h-87; } // lower case
}
return x;
}
//----------------------------------------------------------------------------
int8 Hex2Byte(char a,b) { // convert 2 Hexadecimal characters
int8 x,y;
x=Hex2Num(a); y=Hex2Num(b);
x<<=4; x+=y;
return x;
}
//----------------------------------------------------------------------------
int16 Hex2Word(char a,b,c,d) { // MSB-LSB convert 4 Hexadecimal characters
int16 x,y;
x=Hex2Byte(a,b); y=Hex2Byte(c,d);
x<<=8; x+=y;
return x;
}
//----------------------------------------------------------------------------
void HEXnibbles(int8 b) { // convert Byte to Hexadecimal characters
// HEXnibble[0/1] BYTE BECOMES HEX CHARACTER USED BY OTHER ROUTINES
HEXnibble[0]=0x0F&b; // low nibble
swap(b);
HEXnibble[1]=0x0F&b; // high nibble
// convert decimal value to Hex character's Ascii value
Num2Hex(HEXnibble[0]); Num2Hex(HEXnibble[1]); // #Defined
}
//----------------------------------------------------------------------------
int16 Byte2Hex(int8 b) { // convert Byte to 2 Hexadecimal characters
int16 x;
HEXnibbles(b); x=make16(HEXnibble[1],HEXnibble[0]);
return x; // Word contains 2 character values for HEX numbers
}
//----------------------------------------------------------------------------
int32 Word2Hex(int16 w) { // convert Word to 4 Hexadecimal character values
int16 x;
XferLW.asWord[0]=w;
HEXnibbles(XferLW.asByte[1]);
x=make16(HEXnibble[1],HEXnibble[0]);
HEXnibbles(XferLW.asByte[0]);
XferLW.asWord[0]=make16(HEXnibble[1],HEXnibble[0]);
XferLW.asWord[1]=x;
return XferLW.asLong; // contains 4 character values for HEX numbers
}
//----------------------------------------------------------------------------
|
This has been working for about 2 decades now
_________________ A Esposito, CEO
Avatar Engineering Corp. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|