News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Serial communication between 2 Microcontrollers

Started by basparky, Feb 09, 2026, 01:01 PM

Previous topic - Next topic

basparky

Hi All,

I have a dsPic (a) which communicaties with a Pic(b) over UART. The Dspic is the master and the Pic the slave. The slave(b) can be a unique device with his own data packet output.
In my current deisgn i have the slave sending his datapacket like following:

Proc SendMessage(Nr As Byte)
'Str = 255-3-200-0-100-100-233 wChecksum = 891 bCheckSUm = 123 
    StrToMain[0]    = 255           'Fixed ID
    StrToMain[1]    = Modus   
    StrToMain[2]    = Command     
    StrToMain[3]    = Throttle
    StrToMain[4]    = Dir
    StrToMain[5]    = SafetySwitch
    StrToMain[6]    = 233 'dummy           
    wCheckSum = StrToMain[0] + StrToMain[1] + StrToMain[2] + StrToMain[3] + StrToMain[4] + StrToMain[5]+ StrToMain[6]
    bCheckSum = wCheckSum.LowByte   
    StrToMain[7] = bCheckSum
   
    TMR0ON = 0
    TMR0IE = 0 
   
    For bIndex = 0 To 7
      HRSOut StrToMain [bIndex]
    Next
   
    Interval = 0             
    TMR0ON = 1
    TMR0IE = 1         
EndProc

The master is receiving like:
Isr U2RXInterrupt   
    ID = 255'121 'Id from joystick
       
    If U2STAbits_OERR = 1 Then
        Clear U2STAbits_OERR
        SOM = 0
        Index2 = 0
        GoTo ExitInterrupt2
    EndIf
       
    USART2bRx = U2RXREG   
   
    'catch start off message
    If USART2bRx = ID And SOM = 0 And Index2 = 0 Then
        SOM = 1
        Index2 = 0
    EndIf

    '   
    If SOM = 1 Then
        StrJoyStick[Index2] = USART2bRx
        Inc Index2
        If Index2 > 7 Then
            Index2 = 0
            ReceivedFromJoystick = 1
            SOM = 0
            Toggle LedRd
        EndIf
    EndIf
   
    ExitInterrupt2:
    Clear IFS1bits_U2RXIF
EndIsr


So the slave is sending his ID and a data packet in a fixed length. As shown the receiver waits for the ID 255 and then expects the payload before waiting for the next startbyte (ID).

I would like to make this communication more robuust and create somehow a ID based receive routine.
At this moment i have 3 types of slave. each with their own different datapacket and ID. Does anyone have some suggestions how to build this robuust?
I had issues with sending the SLaves ID because the value 255 van also be the value of one of the bytes in the payload. After knowing this i made a catch start off message as shown in the ISP but i think its too basic to have this working for 3 slave ID's.

I think i'm asking a direction and some help make this work in practise. I have no experience with dynamic data packages but believe this is what it should be on the receiver side.

Any hints or information how to do this would help me a lot. Thanks in advance!






John Lawton

You could use ninth bit addressing to indicate the packet start?

John
-----------------------------------------------------------------------------------------
Amicus 8 and 16A/16B dev boards
Especially created for Positron development
https://www.easy-driver.co.uk/Amicus

trastikata

Is it possible to include a MAC address to each packet?

TimB

I would recommend that you use the 3.5T end of packet system. It's pretty simple to implement you start a timer after the RX of every byte.  In your RX routine when you get a new byte just check if the timer has zeroed out. If that is the case then clear pointers etc and presume this is the address byte.

Check the address against your own and if it matches set your RX state machine to load the rest of the packet.

Just to clarify the 3.5T is the time to send 3.5t bytes





basparky

Thanks! I like the simplicity of the use of 9th bit usage to detect start.
Just wondering which register present this bit in my dspic33FJ.
i will dive into the datasheet :)


John Lawton

-----------------------------------------------------------------------------------------
Amicus 8 and 16A/16B dev boards
Especially created for Positron development
https://www.easy-driver.co.uk/Amicus

shantanu@india

You can also implement Modbus RTU if packet integrity is an issue.
Regards
Shantanu

Gamboa

#7
Basparky,

I use a very structured frame model. This is cumbersome to manage, but it's very useful and versatile.

A typical frame might look like this:
{STX}{TRANSMITTER_ADDRESS}{TRANSMITTER_DEVICE_TYPE}{RECEIVER_ADDRESS}{RECEIVER_DEVICE_TYPE}{VER_PROTOCOL}{COMMAND1}{COMMAND2}{DATA_0}...{DATA_N}{NUMBER_BYTES}{CHCKSUM1}{CHCKSUM2}{ETX}

If you use point-to-point communication you don't need addresses, but on an RS485 bus you do need to address the devices.

STX and ETX are the frame delimiters. This is very useful because you know in advance when a frame has arrived.
With this structure, you don't need the frame length to always be the same; it can be variable, giving you flexibility for each command.

Now, with a structure like this or a similar one, we need to see how the reception is carried out.

I always use an array for USART reception, an index that indicates array fill level, and a USART reception interrupt. You also need a Timer interrupt to clear the array if the frame arrives incomplete within a specified time (three times the character's lifespan or more). The reception process is simple: as characters arrive, you store them in the array and check if the end of the frame has been reached and if the array has overflowed. You continue filling the array until the end of the frame is reached. When the end of the frame is reached, you set a flag in the interrupt, FLAG FRAME RECEIVED, which will indicate to your main program that a frame has arrived.

Now, in the main program, you analyze the frame to see if it is correctly formatted:

Does it start with STX and end with ETX? Yes

Is the frame length correct? Yes

Is the checksum correct? Yes

Are the command and data within acceptable limits? Yes
Etc..Etc
If everything is correct, you proceed to execute the received command. If something goes wrong, you send a NACK with the error and discard the frame.
Once the command has been executed successfully, you send an ACK.

This is how I usually handle communications through USART. I hope it helps give you some ideas.

Regards,
Gamboa

Long live for you

basparky


Quote from: Gamboa on Feb 11, 2026, 09:08 AMSTX and ETX are the frame delimiters. This is very useful because you know in advance when a frame has arrived.
With this structure, you don't need the frame length to always be the same; it can be variable, giving you flexibility for each command.

Now, with a structure like this or a similar one, we need to see how the reception is carried out.

Thanks for your suggestion. However what happens if the value in my data is the same as the STX value?


charliecoutas

You have to make sure that it doesn't. I use this frame format a lot and one way is to (if possible) set the top bit of any "payload" bytes. The control char STX, ETX are all low values so there can't be any confusion.

Another way is to follow the initial STX with a count - the number of payload chars that follow. You therefore don't look for the ETX until you have received this many "payload" chars. But again, you must ensure that the count cannot be mis-interpreted as a control char. Perhaps imposing a minimum payload size would do the trick.

Charlie

Gamboa

Hi,

Charlie is right. STX and ETX cannot be used in the rest of the datagram. If you need to send numeric values, for example 2, then you'll have to send it in ASCII, 50 in decimal, or 0x32. To send 127, you'll have to send three bytes: 0x31, 0x32, and 0x37. It's more overhead in the protocol, but it works well.

I've also used Charlie's other option of counting the characters that enter the USART, but it's slower to manage within the interrupt.

Regards,
Gamboa



Long live for you

joesaliba

#11
I had to decode a serial. What they used to send data was to send 3-byte header. Interestingly, and something that I couldn't read in the serial terminal was that I was reading non-printable characters, so there was no way that data was being mixed.

I had two data sets, 3-bytes start, and then 16 bytes data. So I wait for the 1st header made of 3-bytes and then get the rest: -

HRSIn2 {100, Not_rxU}, Wait ($1B, $43, $80)     ' Wait for $1B, $43, $80
    HRSIn1 Str U_Data\16                            ' then capture the next 16 bytes


The second set of data was as follows: -

HRSIn2 {100, not_rx}, Wait ($1B, $43, $C0)     ' Wait for $1B, $43, $C0
    HRSIn1 Str U_Data\16                            ' then capture the next 16 bytes

After some time I needed to decode another set of data made of 88 bytes. Use was similar to the first project, but from different maker.

Interestingly they used the same method, but different characters as the header.

What I couldn't achieve was to first wait i.e. for $1B, then Wait for $43 and then Wait for $C0.

It DO not work! However, I dig further and found that Arduino C code waits for different characters in separate lines, and it works, but not with Positron.

Having said all the above, many, many moons ago I had one master and 8 slaves.

I asked on this forum and someone, I cannot remember who, told me that it is important that slaves never talk if not requested. So I gave each slave an `address'.

For example: - Slave 1: - #+1, Slave 2: - #+2.... and so on.

So each slave always listened but never talked if not requested.

Then, I created a set of commands similar to each slave, i.e: - $BD means, give me information, $BF turn ON something and so on.

So if I wanted to get data from slave 2: -

Hrsout1 $23, $2B, $32, $BD
 HrsIn1 $23, $2B, $32   ' Wait for slave to answer
 HRSIn1 Str U_Data\5    ' Receive the next 5 bytes


You can add your own acknowledgment when receiving from slave 2. I mean, you can put slave continuously sending data until an acknowledgment is received.

I have seen the 3-byte header in sensitive applications and never miss a beat. But as the manual says, communication must be built step by step.   

EDIT: - You know how I found out what the printable  characters where? In the serial terminal I was getting similar pattern but there was some spaces. I highlighted that space and copied it. I then pasted it into google search and printed in the search bar came up written very small text `ESC' for $1B. Therefore I did the same with the other `spaces'.