sending data from microcontroller to the computer

2019-09-19 11:15发布

问题:

I am using Tiva C Series TM4C123GH6PM with Code Composer Studio for getting data from another microcontroller of the same type. Well, I get the data in bytes. The Goal of project is to assemble each 8 bytes and convert them to double then send these double to the computer. I have to use USART to send the data to the computer.

When I use USART, I have two Methods:

  1. One to get data from a USART_x: UARTCharGet(UART1_BASE)
  2. The other to send the data over USART_x: UARTCharPut(UART0_BASE,d)

The problem consists in having two methods that accept only characters. So using these methods for double is impossible since a double is 8 bytes and a character is one byte. I am trying to send doubles to my computer. Any idea?

The second Problem is to write a program from the side of the computer to get the data (bytes) from the microcontroller.

Should I write this program in c (an alternative is using matlab because I will use these data for simulation)? How can I access com-Port in c (or in matlab if it is possible)?

回答1:

Generally speaking you are facing here serialization problem and the best approach would be using specialized library for this purpose.

In a dirty but simple way you can solve it like that. You have to just properly assemble your data on the other side back to double.

typedef union _MyDouble {
    double d;
    unsigned char bytes[sizeof(double)];
} MyDouble;


MyDouble my_double;
my_double.d = 1.234;

for(i=0; i < sizeof(double); i++) {
    UARTCharPut(UART0_BASE, (char)my_double.bytes[i]).
}

The other thing is that if you are using UART you should encapsulate this union into some frame e.g. in order to successfully reassemble this on the other side.

 _____________ ________ __________ ___________ ________
|             |        |          |           |        |
| FRAME_BEGIN | LENGTH | MyDouble | FRAME_END | CRC-8? |
|_____________|________|__________|___________|________|

The next thing is that you should probably enforce byte alignment on this struct which is done by the compiler directives. It ensures that your struct has no padding bytes etc. and allocates minimum requires size. This is very popular in embedded applications use-cases where some binary object is going to be transmitted on the serial interface - which is exactly your case. Such a simple solution might work on specific hw+sw configuration but for sure it is not portable and good solution from professional point of view.



回答2:

You need to find a way to break up large amounts of data, and send it to the client, who then needs a way to re-assemble the data, and also know when such data is being sent.

A very simple approach would be to convert all the digits of the double to characters. Inefficient, but it gets the job done easily enough, as shown below. The reason this is preferable is because it lets you easily create your own "instruction set". For example, you could reserve the character '!' as "the letter following ! denotes a special instruction", so when the client sees the sequence "!d", it knows the following 32 bytes of data represent a double, and to re-assemble it.

If you just send the raw bytes, it becomes more convoluted when you want to create escape codes or op codes to signal special circumstances to the client.

Code Listing


#include <stdio.h>

#define BUF_LEN (32)
typedef union {
    float f;
    struct {
        unsigned int mantissa : 23;
        unsigned int exponent : 8;
        unsigned int sign : 1;
    } parts;
} double_cast;

int main(void)
{
    double_cast d1;
    d1.f = 0.15625;
    printf("sign = %x\n",d1.parts.sign);
    printf("exponent = %x\n",d1.parts.exponent);
    printf("mantissa = %x\n",d1.parts.mantissa);

    char buf[BUF_LEN+1] = { 0 };
    snprintf(buf, BUF_LEN+1, "%01X%08X%023X", d1.parts.sign, d1.parts.exponent,
         d1.parts.mantissa);

    // Send over UART
    printf("Double as string: [%s]\n", buf);

    //UART_printf("!d%s", buf);    

    return 0;
}

Sample Output


sign = 0
exponent = 7c
mantissa = 200000
Double as string: [00000007C0000000000000000020000]

Credit for the code to break a double into a string goes to u/eran.



回答3:

Another solution (similar to the solution of Krystian) that works for me. I defined a function that has as parameters a double and an array of Bytes. The double must be converted to an array of Bytes. That´s why I defined an array of Bytes which has a size of 8 Bytes. Here some code:

unsigned char bytesArray[sizeof(double)];

unsigned char * doubleToBytes(double num,unsigned char bytes []){
    return memcpy(bytes,&num,sizeof(double));
 }

After getting the Bytes in the Array you can send data using the following loop:

for(i=0;i<sizeof(double);i++){
    UARTCharPut(UART1_BASE,(unsigned char)*(bytesArray+i));

}