# UART Packet

#### TucsonDon

##### Member
I have a project that I am using two MCU's (PIC18F47K42, PIC18F45K22), to transfer data via fiber and I am using the code that is generated by MCC in MPLab X. I will be sending packets of 3 bytes. Not having any experience with the UART protocol I am trying to figure out how to mark the end of the packet so that I can process the data.

#### Nigel Goodwin

##### Super Moderator
What does your data consist of?, and how frequent is it?.

#### TucsonDon

##### Member
The way I going to have it set up is an user interface and a controller. the controller is going to be sending ADC results, valve and pump status on a regular time frame. The UI will be sending commands for the valves and pumps based on time or temp or user input.

#### Nigel Goodwin

##### Super Moderator
Well your answer's pretty vague - but presumably 'regular time frame' means a long time between readings? - so you can easily detect the end of the packet by the lack of incoming data. Or simply send it as ASCII, and detect the ending CR/LF at the end of the packet. I've used both for various projects, currently I'm tending towards ASCII. RS232 is intended as a 7 bit system, so it's easier to use ASCII than 8 bit - there's even an EOF (End Of File) character if you wish.

#### TucsonDon

##### Member
Nigel Goodwin sorry for the vagueness. From the controller to the UI will be pretty much on a regular time frame but from the UI to the controller will be anytime a user inputs a command or on a timer schedule. So then the question is how do I convert say the ADC result to ASCII to send to the UI to display a temp on a LCD? Would I use the printf command?

#### Nigel Goodwin

##### Super Moderator
Nigel Goodwin sorry for the vagueness. From the controller to the UI will be pretty much on a regular time frame but from the UI to the controller will be anytime a user inputs a command or on a timer schedule. So then the question is how do I convert say the ADC result to ASCII to send to the UI to display a temp on a LCD? Would I use the printf command?
That's one way, there are numerous way of doing it, if you're already using printf, then no problem, but otherwise it adds a LOT of overhead to your program. As you're using fairly decent spec PIC's that probably won't be an issue though.

As you're already needing to convert to display it, you may as well convert at the transmitting end rather than the receiving end.

#### Pommie

##### Well-Known Member
I prefer to use itoa(); to convert to ascii. It "feels" more efficient.

Mike.

#### Nigel Goodwin

##### Super Moderator
Here's a routine I often use, I also have ones for different sized variables.

C:
unsigned char TenM, Mill, HunK, TenK, Thou, Hund, Tens, Ones;    // Decimal convert routine variables

void convert16(unsigned int numb)        // Takes an unsigned integer number
{                                // and converts to single
TenK = numb / 10000;            // decimal numbers.
Thou = (numb % 10000)/ 1000;    //
Hund = (numb % 1000) / 100;
Tens = (numb % 100) / 10;
Ones = numb % 10;
}
Depending on it's exact use I often add 0x30 to each digit (to make it ASCII) and copy them to a string buffer, it also allows you to add a decimal point to the string, or pad it with leading or trailing zeros etc. It's fast, small and works well.

#### rjenkinsgb

##### Well-Known Member
There are many simple ways of "packetising" serial data.

If sending ASCII data, use 8 bit mode and set (or reset) the high bit to indicate the end of a packet.
Or use a different character to signal the end, eg. a colon or CR (carriage return).

For binary of moderate size, you can eg. send it as four bit "nibbles" with the high bits indicating the location on the packet or using different bits or combinations for first character, intermediate character & end character.

Or just timing, as Nigel says - but ensure you have the correct number of characters stored before doing any further processing.

#### TucsonDon

##### Member
rjenkinsgb thanks for the input.

As I have thought about this I am leaning to the timing method as some of the data will be interpreted as bit wise, the pump has 8 speeds that I use a byte to flag (0x80 is speed 8, 0x40 is speed 7...) and the same for valve commands. I am afraid if I convert to ASCII to transmit that I would have issues with the various commands

#### rjenkinsgb

##### Well-Known Member
With only 8 values, you could encode to three bit binary & use the rest of the byte for both error checking (eg. an inverse duplicate of the data in another three bits) and sequence control using the last two..

Using a full bitfield to send a number like that is rather wasteful, and more importantly not error resistant; what happens if a glitch sets an extra bit?
It's probably as or more complex to check it's one-of-eight unique than to convert to binary and back?

#### Nigel Goodwin

##### Super Moderator
rjenkinsgb thanks for the input.

As I have thought about this I am leaning to the timing method as some of the data will be interpreted as bit wise, the pump has 8 speeds that I use a byte to flag (0x80 is speed 8, 0x40 is speed 7...) and the same for valve commands. I am afraid if I convert to ASCII to transmit that I would have issues with the various commands
Why?, ASCII is easier, as RS232 is designed for ASCII. If you want to send 8 bit data, then simply detect the breaks in the data to signify the end of a packet. I would also suggest sending a unique marker to signify the start of a packet, and a different one for the end of a packet, so you can make sure that you've got a full packet.

But ASCII makes life so much easier, simply detect the end of the packet (CR/LF), copy the buffer to a string and check for the valid commands - it also makes it much easier to debug, as you simply display the data in a comms program.

You could send a string like "speed=27, valve=4" - and then search for 'speed=' followed by 'valve=' - it also easily allows partial commands like just "speed=0" if you're not changing any of the valves at that time.

Here's a live version from the lights on my drive

The first LDR readings are showing how dark it is, so I can adjust it from inside useing the SETLDR command, and is sent every 5 seconds. I typed the 'help' command, and it returns a list of the possible commands. The lights are controlled by an ESP32, via Alexa voice commands, or wireless remote control - including one in the car that's connected to the reversing lights, so the lights come on when I reverse on the drive - if it's dark enough.

17-help
17-Available commands.
17-Change LDR threshold - 'SETLDR=xxxx'
17-Display current LDR threshold - 'CURRLDR'
17-Change car delay time - 'SETDEL=xxxx'
17-Display car current delay time - 'CURRDEL'
17-Change home delay time - 'SETHOMEDEL=xxxx'
17-Display home current delay time - 'CURRHOMEDEL'
17-Change sequence time - 'SETSEQ=xxxx'
17-Display current sequence time - 'CURRSEQ'
17-Set LDR Send - 'LDRSEND= 0 or 1'
17-Display current LDRSEND - 'CURRLDRSEND'

17-Home setting - 'SETHOME=1 to 9'
17-Remote setting - 'SETREM=1 to 9'
17-Remote setting - '1 to 4' are individual lights
17-Remote setting - '5' is all lights
17-Remote setting - '6' is odd lights
17-Remote setting - '7' is even lights
17-Remote setting - '8' is 123 lights
17-Remote setting - '9' is 234 lights

17-Display current remote setting - 'CURRREM'
17-Display current home remote setting - 'CURRHOME'
17-Display all settings - 'CURRENT'
17-Force RESET on ESP32 - 'RESET'
17-Show this help - 'HELP'

#### Pommie

##### Well-Known Member
Ascii has two dedicated characters, 0x02 is STX or start text and 0x03 is ETX or end text. Seems someone thought about this problem a long time ago.

Mike.

#### Nigel Goodwin

##### Super Moderator
Ascii has two dedicated characters, 0x02 is STX or start text and 0x03 is ETX or end text. Seems someone thought about this problem a long time ago.

Mike.
As I've said all along - it's designed as a 7 bit system for ASCII data - trying to make it 8 bit messes everything up and requires different techniques.