Author Topic: sending data to UART in C  (Read 11293 times)

0 Members and 1 Guest are viewing this topic.

Offline Tony RTopic starter

  • Regular Contributor
  • *
  • Posts: 117
  • Country: 00
sending data to UART in C
« on: November 16, 2011, 04:13:19 pm »
ok, I never had to do this before and i want to know what the best way to do this is.

i have a struct like
Code: [Select]
struct status
{
uint16_t heading;
uint8_t speed;
uint8_t battery;
uint8_t event;
uint8_t headlights;
};

what I want to do is use a UART connection to send this data. first two bytes heading and the remaining bytes speed battery event and headlights in that order.

The function prototype for the UART is this:

Code: [Select]
void UARTSend( uint32_t portNum, uint8_t *BufferPtr, uint32_t Length );
now I would like a simple way of just sending the struct, i know i will have to use pointers but i am not sure how to use them in this case.

instead i have done the following.

Code: [Select]
void transmit(struct status stat)
{
uint8_t data[6];
data[0] = stat.heading & 0x00FF;
data[1] = (stat.heading & 0xFF00)>>8;
data[2] = stat.speed;
data[3] = stat.battery;
data[3] = stat.event;
data[4] = stat.headlights;
UARTSend( 0, data, sizeof(data));
}

Does anyone know if a cleaner way to do this?
Tony R.
Computer Engineering Student
Focus: Embedded Assembly Programming, Realtime Systems,  IEEE Student Member
 

Offline enz

  • Regular Contributor
  • *
  • Posts: 134
  • Country: de
Re: sending data to UART in C
« Reply #1 on: November 16, 2011, 04:31:53 pm »
Hello Tony,

just skip the skip the  unnecessary copy action and add a cast to a pointer to uint8_t for the address of the the struct:

void transmit(struct status stat)
{
   UARTSend( 0, (uint8_t *) stat, sizeof(struct status));   
}

Regards, Martin
 

Offline Tony RTopic starter

  • Regular Contributor
  • *
  • Posts: 117
  • Country: 00
Re: sending data to UART in C
« Reply #2 on: November 16, 2011, 04:40:11 pm »
Hello Tony,

just skip the skip the  unnecessary copy action and add a cast to a pointer to uint8_t for the address of the the struct:

void transmit(struct status stat)
{
   UARTSend( 0, (uint8_t *) stat, sizeof(struct status));   
}

Regards, Martin

Tried that but it says "invalid type conversion" error number 171

I am using the Keil IDE for the ARM M3 LPC1768
Tony R.
Computer Engineering Student
Focus: Embedded Assembly Programming, Realtime Systems,  IEEE Student Member
 

Offline Tony RTopic starter

  • Regular Contributor
  • *
  • Posts: 117
  • Country: 00
Re: sending data to UART in C
« Reply #3 on: November 16, 2011, 04:42:02 pm »
Hello Tony,

just skip the skip the  unnecessary copy action and add a cast to a pointer to uint8_t for the address of the the struct:

void transmit(struct status stat)
{
   UARTSend( 0, (uint8_t *) stat, sizeof(struct status));   
}

Regards, Martin

Tried that but it says "invalid type conversion" error number 171

I am using the Keil IDE for the ARM M3 LPC1768

but this seems to work:

Code: [Select]
void transmit(struct status *stat)
{
UARTSend( 0, (uint8_t *) stat, sizeof(struct status));
}

Thanks for your help!
Tony R.
Computer Engineering Student
Focus: Embedded Assembly Programming, Realtime Systems,  IEEE Student Member
 

Offline baljemmett

  • Supporter
  • ****
  • Posts: 665
  • Country: gb
Re: sending data to UART in C
« Reply #4 on: November 16, 2011, 04:44:33 pm »
   UARTSend( 0, (uint8_t *) stat, sizeof(struct status));   

Tried that but it says "invalid type conversion" error number 171

You need to take a pointer to the structure and cast that; you can't cast the struct itself:

Code: [Select]
void transmit(struct status stat)
{
    UARTSend( 0, (uint8_t *) &stat, sizeof(stat));
}

Although do be aware that this doesn't guarantee the data format is the same as the routine you had originally.  The two main things to look out are endianness (your two-byte heading field might get transmitted high-byte-first or low-byte-first depending on architecture) and structure padding (junk bytes between structure elements used to keep things in alignment, although I believe in this case you'll be OK since the natural alignment of the elements shouldn't require any padding).

In general it could be considered better practice to serialise the data into a known format for transmission (as you are currently doing), so that you don't need to worry about the wire protocol being tied to the struct's exact memory layout.  At least, that's the case in the world of full-blown computers and software; in the embedded space it's probably less of a worry, but I'm a bit of a neophyte there so could be wrong.
 

alm

  • Guest
Re: sending data to UART in C
« Reply #5 on: November 16, 2011, 04:56:32 pm »
I believe that C only guarantees the order of the struct fields in memory, i.e. &stat.heading < &stat.speed. Alignment is not guaranteed. Endianness is indeed another issue. If you rely on compiler/platform-specific or even undocumented behavior, be sure to make this very clear in the documentation, so the poor soul who happens to port your code to another compiler/platform will not bang his head against the desk trying to debug this. For example, if you ever change headlights to uint16_t, you may suddenly find a padding byte inserted in front of headlights.

Sending structs is only acceptable if both sides are under your control and use the same platform and compiler for both. Even then it's an issue if you ever change one of them, eg. from PIC to PIC32 so you can use a flashy touch screen.
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11891
  • Country: us
Re: sending data to UART in C
« Reply #6 on: November 16, 2011, 06:38:23 pm »
now I would like a simple way of just sending the struct, i know i will have to use pointers but i am not sure how to use them in this case.

instead i have done the following.

Code: [Select]
void transmit(struct status stat)
{
uint8_t data[6];
data[0] = stat.heading & 0x00FF;
data[1] = (stat.heading & 0xFF00)>>8;
data[2] = stat.speed;
data[3] = stat.battery;
data[3] = stat.event;
data[4] = stat.headlights;
UARTSend( 0, data, sizeof(data));
}

Does anyone know if a cleaner way to do this?

As others have said, unpacking the data from the structure like this gives you better guarantees about portability and robustness.

However, you can avoid unnecessary copying of data by passing in a pointer to the struct, rather than the whole struct itself:

Code: [Select]
void transmit(struct status *stat)
{
uint8_t data[5];
data[0] = stat->heading & 0x00FF;
data[1] = (stat->heading & 0xFF00)>>8;
data[2] = stat->speed;
data[3] = stat->battery;
data[3] = stat->event;
data[4] = stat->headlights;
UARTSend( 0, data, sizeof(data));
}

You would not be able to measure the difference in performance on a desktop computer, but on a micro it might make a difference. And coding for best performance is a good habit to get into.

(But if you pass a pointer to the struct, you have to make sure the struct can't be modified while you are accessing it. This could be an issue with parallel threads of execution, e.g. interrupt service routines that trigger and update the data while you are trying to send it.)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf