cancel
Showing results for 
Search instead for 
Did you mean: 

Sending float32 with UART

Tom G
Associate
Posted on January 03, 2017 at 18:47

Hi there, recently I was making acustic spectrometer using STM32F4-Discover. In my project im making FFT with

'arm_math' libraries and then I need to send data to PC (with which I'll display it) via UART.

After making FFT  I recieve array of float32_t - I need to send it via UART.

And here comes my question - how do I send them via UART. I've read that I can :

  1. use sprintf and send it like it was string
  2. divide float into 4x 8-bit uint and send it.

How do I do that on STM? I preffer to use option 2.

I'm using stdPeriphLibs - they are more clear to me.

@Edit 18:00 7th of Jan 2017

I have made a program like this:

uint32_t speed;

volatile unsigned char str;

int i;

union

{

    float32_t f;

    uint8_t bytes[4];

}float2int;

/* ---------------------------------------------------------------------------*/

int main(void)

{

    speed = 9600;

    _GPIO();

    _LED();

    //_NVIC();

    _USART1(speed);

    float2int.f = 123.456;

    i = 0;

    GPIO_SetBits(GPIOD, LED_Green);

    while(i<4)

    {

        USART_SendData(USART1, float2int.bytes[1]);

        while(USART_GetFlagStatus(USART1, USART_IT_TXE) != RESET);

        GPIO_SetBits(GPIOD, LED_Red);

        i++;

    }  

Sending data works in a way - normally im recieving bytes[3], but when I'm debugging I'm recieving data properly.

Do I need some kind of delay?
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on January 03, 2017 at 19:12

Same as you would on any C platform?

void SendBuffer(size_t Size, uint8_t *Buffer)
{
 while(Size--)
 {
 while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET); // Wait for Empty
 USART_SendData(USART3, (uint16_t)*Buffer++);
 }
}

float flt;
SendBuffer(sizeof(flt), (void *)&flt);

fwrite((void *)&flt, sizeof(flt), 1, fout);

float fltarray[256];
SendBuffer(sizeof(fltarray), (void *)fltarray);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

You'd probably want a structure, and method of packetizing and synchronizing, equivalent to commas, CR, LF you'd use for ASCII data

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

7 REPLIES 7
LMI2
Lead
Posted on January 03, 2017 at 19:09

Serial bus data is 8 or 9 bits. If you send only bytes from your floats,  your machines may fall out of sync. One missing or extra byte and you get very strange results.

Posted on January 03, 2017 at 19:12

Same as you would on any C platform?

void SendBuffer(size_t Size, uint8_t *Buffer)
{
 while(Size--)
 {
 while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET); // Wait for Empty
 USART_SendData(USART3, (uint16_t)*Buffer++);
 }
}

float flt;
SendBuffer(sizeof(flt), (void *)&flt);

fwrite((void *)&flt, sizeof(flt), 1, fout);

float fltarray[256];
SendBuffer(sizeof(fltarray), (void *)fltarray);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

You'd probably want a structure, and method of packetizing and synchronizing, equivalent to commas, CR, LF you'd use for ASCII data

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Seb
ST Employee
Posted on January 03, 2017 at 20:15

If the rs232 bitrate is fine, it is better to create a printf function for sending out your float. With the proper end of string charaters such as line feed, the text can go to a teraterm pc terminal, be saved as text file with csv extension and be directly imported in excel for graph view. With comma separated fields on each string you can build a table.with labels and comments. Worth the implementation. In my side i convert pressure in milibar as 3 digits after the comma when converted aa text. If interested, a sample code maybe in this note

https://community.st.com/0D50X00009XkVtcSAF

Posted on January 03, 2017 at 20:48

ASCII has the benefit of being human readable, though probably less so at 1000 characters per line. It tends to be far more verbose, requiring additional effort to encode, and decode, and often with a loss of precision.

For machine-to-machine, sharing a common binary format, and numeric representation, sending compact binary structures is significantly more efficient.

Using sprintf() in this context

float flt;
char str[32]
SendBuffer(sprintf(str,'%f',flt), (void *)str);
SendBuffer(sprintf(str,'%e',flt), (void *)str);�?�?�?�?�?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 04, 2017 at 05:45

Perhaps the most complicated part of this problem is the program at the other end and how it will interpret the data it receives.  You need to define your own communication protocol.  ie: it would probably be good if you send some information about what you are sending (number of bytes) and perhaps something to error check (checksum or CRC).  And maybe a start sequence that the PC program can be waiting for to indicate a message is actually coming.  Sending the data is simple.  Just define a C union that allows you to access the 32 bit words in your float array as either real values or groups of bytes.  Your application will store them as floats when you do the FFT, but you want to access them as 8-bit quantities to send out the UART.   Once you do this you can easily send it via the UART, however at the other end you need to reassemble the bytes into 4-byte groups that can be interpreted by your PC application as FP values.  Again a C union will enable you to store them as bytes and then read them as an array of FP values.

If you first send the number of bytes to follow, and the checksum to be expected (checksum can be a byte or word) the receiving program can error check and request a re-send if there is an error.

You definitely DON'T want to use formatted I/O like sprintf().  It will add 20k of code and do nothing for you.  Once you have your data available in a byte (or uint8_t) array, just send it with a HAL call (HAL_UART_Transmit()).  And all of this has nothing to do with STM32. (other than HAL) it would be the same if you were doing this on an 8051 microcontroller.

Jeroen3
Senior
Posted on January 04, 2017 at 09:17

8x 4 bit nibbles. As in 0x40490fdb (pi), you can send this as:

STX 4 0 4 9 0 F D B ETX or it may be easier in little endian (little end first),

STX

BDF09404 LF .. next number .. LF .. ..

ETX

This has several advantages.

- No need for stuffing. (eg, what happens when the float contains LF 0x0A?)

- No complicated conversion (just a few shifts and a 16 char lookup table)

- Still readable by humans, easy to sniff and understand.

- Compatible with

http://www.ascii-code.com/

.

It also has a disadvantege:

- Data size is doubled relative to raw binary.

Posted on October 26, 2017 at 11:16

Hi Clive,

How can i receive different data types through uart.

I don't know the no of bytes. 

. I am receiving data from vectornav through uart to stm32f407 board. The data to be received is in this format.

$VNYMR,-168.471,-000.723,-179.360,-00.4097,-00.0397,+00.0803,-00.142,-00.068,+10.387,+00.015401,+00.018077,+00.345140*6E

$VNYMR,-169.199,-000.806,-179.314,-00.4108,-00.0317,+00.0832,-00.084,-00.118,+10.381,+00.024314,+00.061842,+00.724389*64

$VNYMR,-170.592,-000.813,-179.262,-00.4142,-00.0181,+00.0824,-00.381,+00.543,+10.543,+00.030802,+00.039011,+00.543873*66

$VNYMR,-171.556,-001.319,-179.189,-00.4118,-00.0147,+00.0788,-00.159,-00.112,+10.346,+00.011041,+00.488687,+00.845943*65