View previous topic :: View next topic |
Author |
Message |
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
Converting raw string to int |
Posted: Tue Mar 24, 2020 8:11 pm |
|
|
I have an unusual application. I am reading frequency data from an ICOM receiver. The data comes out of the serial port at 9600. I am using an 18F25k80. I am reading in 11 bytes just fine into a string variable (sBuffer). Unfortunately, the radio vendor will send a frequency in LSB to MSB order. I extract the various digits just fine, but I need to mathematically multiply the decades to get the final frequency. The problem is that the bytes coming in are direct values. I.e. 10 is read back as 0x10 in a single byte as are the other digits.
I have tried to get them in a form I can multiply and add but with no luck.
char sBuffer[11]; // I want the 8th byte (0x10) to be an int 10
long nCurrentFreq;
char sAdr[1];
memcpy(sAdr,sBuffer+8,1);
nCurrentFreq=strtoul(sAdr,1,1);
// I need nCurrentFreq to me a long int that I can do math with.
Thanks for any help. I tried sprintf but could not get it to work either. _________________ Ed J |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 25, 2020 1:30 am |
|
|
- Post an example of the incoming string, with a space between each byte.
- Tell us which of the bytes in the string are the frequency.
- Tell us the frequency that the bytes represent.
In other words, give total information. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Mar 25, 2020 1:39 am |
|
|
The eighth byte is an integer that you can multiply already. However
remember you are probably going to have to build the result into an
int16 or int32 variable (the char locations will not be big enough to hold
the result), and you need to be using a similar longer type for the
multiplication.
As PCM_Programmer says, show us what you get, and what you
actually want to do. |
|
|
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
|
Posted: Wed Mar 25, 2020 9:13 am |
|
|
Here is the raw data as I receive it. I have added a space between bytes for clarity but there is no space sent:
0xFE 0xFE 0x00 0x54 0x00 0x80 0x42 0x16 0x07 0x00 0x00 0x00 0xFD
The first 4 bytes are preamble and address, 0xFD is end of message byte
The message length is always the same.
The above data represents a frequency of 7164.2800
I don't need anything but 7164 ignoring everything to the right 0f 7164. As you can see, the protocol from the ICOM product is really strange.
The highest value for nFrequency is 54000 so a long int should do it.
I was planning to take only bytes 9 (0x07), 8 (0x16) and 7 (0x42) to assemble the final value of 7164 which
Thanks for the quick response to my first post and hope I am clarifying the problem I am having (been away from C for too long). _________________ Ed J |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 25, 2020 1:01 pm |
|
|
This will give you 7164:
Code: | #include <18F46K22.h>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOPBADEN
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
//======================================
void main()
{
int8 sBuffer[] = {
0xFE,0xFE,0x00,0x54,0x00,0x80,0x42,0x16,0x07,0x00,0x00,0x00,0xFD};
int16 freq;
freq = (sBuffer[8] & 0x0F) * 1000;
freq += (sBuffer[7] >> 4) * 100;
freq += (sBuffer[7] & 0x0F) * 10;
freq += (sBuffer[6] >> 4);
printf("%lu\r\n", freq);
while(TRUE);
} |
|
|
|
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
Raw Int |
Posted: Wed Mar 25, 2020 2:56 pm |
|
|
Thanks for the sample code. The only problem is that the rawdata received by the uart has no spaces and no commas. Is there another way? Otherwise I can create variables for each of the bytes and define the array
using these bytes and do the math on the bytes. Any thoughts? _________________ Ed J |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 25, 2020 3:06 pm |
|
|
The commas are to separate the data bytes, per the C standard, when
initializing an array. There are no actual commas in the array.
How are you receiving the data from the ICOM receiver ? Through a serial
port. So, somehow you must be reading it into a buffer. It will be in the
buffer just as I've stored it in the array. (No commas, no spaces).
Post your receiving code for the serial bytes. |
|
|
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
|
Posted: Wed Mar 25, 2020 5:58 pm |
|
|
Code: | char cTemp;
int8 sBuffer[12];
//------------- rs232 interrupt routine--------------------------------------
#int_rda //turn on serial interrupt
void serial_isr() // serial interrrupt service routine
{
disable_interrupts(int_timer1);
cTemp = Getc(); //hold Getc() in cTemp
if(cTemp==0xFD) //look for a # in buffer, then set nFlag
{
nFlag=1; //- we have received a #
nRead=0; //- but dont empty sBuffer yet
nBytes=0;
}
else //else if cTemp is NOT 0xFD
{
If (nFlag==1) //- if previous byte rcvd was a 0xFD
{ //- and this one is not
sBuffer[nBytes] = cTEMP; //load up buffer
nbytes++; //increase string cntr
if (nBytes>=11) //if we got # and then 64 bytes
{
nFlag = 0; //- turn off # rcvd flag
nBytes = 0; //- reset byte counter
}
}
else // if nflag not = 1
{
memset(sBuffer,0,11);
nbytes=0;
cTemp = 0;
nread=0;
} //end else
} //end if cTemp! }
} //- end function
|
There are two data streams send by the ICOM radio. The last byte is always 0xFD so I wait for the first packet to end with an 0xFD and copy the 12 bytes that come after into sBuffer. I see that I am extracting the data into cTemp but I define it as a character instead of an int. This may be part of my problem. I use nFlag to show that the 0xFD has come and gone so the next data received is valid. Thanks again. _________________ Ed J |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 25, 2020 6:53 pm |
|
|
The code I posted should work. Try it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Mar 26, 2020 3:06 am |
|
|
I'd make one change to it PCM:
freq += (sBuffer[7] >> 4) * 100L;
I think otherwise there is a risk of a numeric overflow on this one line.
Doesn't apply on the other lines (the 1000, forces int16 maths, and the
*10, is small enough that there should never be an overflow).
As PCM_Programmer says, this should work for your data. It is a demo
with his buffer filled to simulate what you have. |
|
|
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
Update |
Posted: Thu Mar 26, 2020 6:25 am |
|
|
Thanks to you both for the recommendations. I have it working with your code with the exception that any frequency over 10000 does not calculate correctly
0xFE 0xFE 0x00 0x54 0x00 0x20 0x49 0x14 0x18 0x00 0x00 0xFD
should display 18144. Instead I get 8144. It seems the error only exists when the frequency is at 10000 or greater. In reality the highest frequency I need to read is 54000.
I am trying to understand the bit manipulation you are doing in the calculations but I will have to study it more. I have been away from C for a number of years plus I'm not as young as I used to be :-) Thanks again _________________ Ed J |
|
|
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
Working |
Posted: Thu Mar 26, 2020 6:43 am |
|
|
I added the following to the top of your code and now its working ok
Code: |
nFreq = (buffer[8] >> 4 ) * 10000; |
and changed the = to += in the top line of your code. Thanks for all the help... this one has been making me totally crazy for the past few days _________________ Ed J |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Thu Mar 26, 2020 7:07 am |
|
|
Nice you got it working !!!What amazed me is that device has a REAL RS232 connector !! 25 pins... |
|
|
|