What is the best way to send data to a serial port?

This is due to microcontrollers, but it is believed that they are published here because it is a problem with algorithms and data types, and not with hardware. I will explain the problem so that someone who does not have the hardware knowledge can still participate :)

  • The Microcontroller has an analog-to-digital converter with 10 bits. (It will output a value from 0 to 1023)

  • I need to send this value to a PC using the serial port.

  • But you can only write 8 bits at a time. (You need to write bytes). This is a limitation in the microcontroller.

  • So, in the case above, at least I need to send 2 bytes.

  • The PC application simply reads a sequence of numbers to construct. So it should capture two consecutive bytes and build the number back. But here we need a character delimiter. but still the delimiter character has an ascii value between 0 - 255, then it will mix the process.

So what is the easiest way to do this? Should I send values ​​as a sequence of characters?

Ex : 1023 = "1""0""2""3" Vs "Char(255)Char(4)" 

In conclusion, I need to send a sequence of 10 bits via Serial in the fastest way. :)

+7
algorithm embedded microcontroller pic
source share
4 answers

You need to send 10 bits, and since you send a byte at a time, you need to send 16 bits. The big question is how much speed is a priority, and how synchronized are the sender and receiver? I can think of 3 answers, depending on these conditions.

Regular sampling, unknown join point

If the device works all the time, you are not sure when you are going to connect (you can join at any time in sequence), but the sampling rate is slower than the communication speed, so the size does not matter to you. I think I will probably do it as follows. Suppose you are trying to send ten bits of abcdefghij (each letter is one bit).

I would send pq0abcde , then pq1fghij , where p and q are error checking bits . Thus:

  • no separator required (you can specify which byte you are reading 0 or 1)
  • you can pinpoint any 1-bit error so that you know about bad data.

I try my best to find a good error correction code, so I think I just set the pa parity bit for bits 2,3 and 4 (0, ab above) and qa parity bit for 5 6 and 7 (c, d, e above). This may be clearer with an example.

  • Suppose I want to send 714 = 1011001010.
  • Divide by 2 10110, 01010
  • Add bits to indicate first and second bytes 010110, 101010
  • calculate the parity for each half: p0 = par (010) = 1, q0 = par (110) = 0, p1 = par (101) = 0, q1 = par (010) = 1
  • bytes then 10010110, 01101010

Then you can find many different error conditions, quickly check which byte you send if you lose synchronization, and none of the operations takes a very long time in the microcontroller (I would parity with an 8 search query table).

Dense data, known junction point

If you know that the reader starts at the same time as the writer, just send 4 ten-bit values ​​as 5 bytes. If you always read 5 bytes at a time, then there is no problem. If you want even more space saving and have good sample data, I would compress using huffman encoding .

Dense data, unknown junction

In 7 bytes, you can send 5 ten-bit values ​​with 6 spare bits. Send 5 values:

  • byte 0: 0 (7 bits)
  • byte 1: 1 (7 bits)
  • byte 2: 1 (7 bits)
  • byte 3: 1 (7 bits)
  • byte 4: 0 (7 bit)
  • byte 5: 0 (7 bit)
  • byte 6: (8 bit)

Then whenever you see 3 lines in a line for the most significant bit, you know that you have bytes 1, 2 and 3. This idea takes up 1 bit in 56, so it can be made even more efficient, but you would for sending more data at the same time. For example (5 consecutive, 120 bits sent in 16 bytes):

  • byte 0: 0 (7 bits) 7
  • byte 1: 1 (7 bits) 14
  • byte 2: 1 (7 bits) 21
  • byte 3: 1 (7 bits) 28
  • byte 4: 1 (7 bit) 35
  • byte 5: 1 (7 bit) 42
  • byte 6: 0 (7 bit) 49
  • byte 7: (8 bit) 57
  • byte 8: (8 bit) 65
  • byte 9: (8 bit) 73
  • byte 10: (8 bit) 81
  • byte 11: 0 (7 bit) 88
  • byte 12: (8 bits) 96
  • byte 13: (8 bits) 104
  • byte 14: (8 bit) 112
  • byte 15: (8 bit) 120

This is a pretty funny problem!

+15
source share

The best way is to convert the data to an ASCII string and send it this way - this simplifies debugging and eliminates various communication problems (special meaning of some control characters, etc.).

If you really need to use all the available bandwidth, then you can pack 4 10-bit values ​​into 5 consecutive 8-bit bytes. You will need to carefully monitor the synchronization.

+7
source share

Since you specified the “fastest way”, I think that expanding the number to ASCII is excluded.

In my opinion, a good compromise on the simplicity and performance of the code can be obtained using the following encoding:

Two ten-bit values ​​will be encoded in 3 bytes, like this.

first 10 bits bit bits: = abcdefghij

second 10 bit bit bit: = klmnopqrst

Bytes for encoding:

 1abcdefg 0hijklmn 0_opqrst 

There is another bit (_) that you can use to parity all 20 bits for error checking, or simply set a fixed value.

Sample example code (puts 0 at position _):

 #include <assert.h> #include <inttypes.h> void write_byte(uint8_t byte); /* writes byte to serial */ void encode(uint16_t a, uint16_t b) { write_byte(((a >> 3) & 0x7f) | 0x80); write_byte(((a & 3) << 4) | ((b >> 6) & 0x7f)); write_byte(b & 0x3f); } uint8_t read_byte(void); /* read a byte from serial */ void decode(uint16_t *a, uint16_t *b) { uint16_t x; while (((x = read_byte()) & 0x80) == 0) {} /* sync */ *a = x << 3; x = read_byte(); assert ((x & 0x80) == 0); /* put better error handling here */ *a |= (x >> 4) & 3; *b = x << 6; x = read_byte(); assert ((x & 0xc0) == 0); /* put better error handling here */ *b |= x; } 
+4
source share

Usually I use the start byte and the checksum, and in this case a fixed length, so I send 4 bytes, the recipient can look for the start byte, and if the next three are added to the knowledge quantity, then this is a good package to take out the middle two bytes, if you do not continue to look. The receiver can always re-sync and it does not waste ascii bandwidth. Ascii is your other option, a start byte, which is not a number, and possibly four numbers for decimal numbers. The decimal value, of course, is not funny in the microcontroller, so start with something non-hexadecimal, like X, and then three bytes with the ascii hex values ​​for your number. Find x, learn the next three bytes, hope for the best.

0
source share

All Articles