Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I continuously send and receive with wireless serial-port in 8051?

Tags:

I'm trying to make a microcontroller communicate with a program on my desktop. I'm using serial port connections with Xbee radios on both ends.

The communication works fine when I send something from the microcontroller to the desktop and the program on the desktop then sends something back to the microcontroller.

However, when I require the information to be sent from the controller to the desktop program continuously until the desktop program sends a particular answer it doesn't work.

Here's the code for what I'm talking about:

    unsigned char ans = 'N';
    unsigned int count = 0;

    void main(void)
    {


        while(1)
        {
            if(count == 0)
            {
                Configure();
                count = 1;
            }

                  //there is some more code here but is irrelevant to the serial communication

         }

    }


void Configure()
{


    //Repeat this until the user accepts the sent string as correct
    while(ans == 'N')
    {

        BuildString();
        Send();
        Receive();
    }
}

void Send()
{
    unsigned int i;

    TMOD = 0x20;
    TH1 = 0xFD;
    SCON = 0x50;
    TR1 = 1;

    for(i=0; i<4; i++)
    {
        SBUF = toSend[i];
        while(TI == 0);
        TI = 0;
    }   

}

void Receive()
{
    unsigned int j;

    TMOD = 0x20;
    TH1 = 0xFD;
    SCON = 0x50;
    TR1 = 1;


    for(j=0; j<2; j++)
    {
        while(RI == 0);
        Received[j] = SBUF;
        RI = 0; 
    }


    if(count == 0)
        ans = Received[1];

    else
    {   
        RunType = Received[0];
        Move = Received[1];
    }


}

The BuildString() function simply constructs a string on the basis of some sensor inputs. The send and receive functions work fine usually but when I need them to send and receive continuously, like in the Configure() function above, it doesn't work.

Any suggestions? I'd really appreciate them.

like image 933
CodeConfused Avatar asked Oct 24 '09 19:10

CodeConfused


2 Answers

Your program as written should send 4 bytes and then read 2 bytes.(assuming the registers you have are correct, but if you got it to work at all they are probably correct) then send 4 bytes again... It probably isn't hanging on the send part but the receiving side as it will always be waiting to read two bytes, and if for some reason two bytes don't arrive at the input register you will continue to wait for ever.

It maybe when you stress the system(send byte too quickly) you are overflowing the input buffer and end up loosing a byte? thus never getting two bytes. and will get stuck.

  1. can you debug where you are getting stuck? is it in fact in the receive loop?
  2. can you throttle the transmission from the pc to the micro so you can manually send one byte at a time?
  3. is there any handshaking between the micro and xbee interface? can that be throttled by the micro?
like image 22
simon Avatar answered Oct 12 '22 07:10

simon


The problem is that both your send and receive functions are polled and blocking. When you call the receive function, it will only return after a complete message is received. Dito for the send function, but in case of send the duration is propably shorter (your program will propably only call send when there is a message to be sent, while receive can wait for days before a message arrives.

If you require asynchronous commmunication, the best is to use interrupt based communications; at least for the receive and ideally for both send and receive.

It is also possible to impement this using polled communications, but then you need to write a function which checks if a character is available for receive (or if tx-empty), to read/write the next character from/to the buffer.

The advantages of interrupt based communication are:

  • full duplex
  • less cpu time is used (no wait loops necessary)
  • less power (it allows the cpu to go to a low power/standby mode, with wakeup on interrupt; polling always requires full power)

As a first step I advise you to implement (or get) a interrupt based receive; even when the transmit function is still blocked, it will allow full duplex operation with minimal effort. If you haven't got a os (rtos/scheduler) you'll have to think of a synchronisation mechanism. The simplest form is for your receive to handle a message if there is one available, and to return immediately if there isn't a (complete) message.

good luck.

Edit after comments On a message-by-message basis, things may seem to work if the desktop is reacting on messages sent by the controller. If your controller has a large FIFO buffer (i.e. 64 bytes) on the receive, this may work. Most controllers I know haven't got this. Many have only a single character buffer. You can detect this using an OVERFLOW bit in the registers; if this is set, then characters were lost on receive.

Some usecases: * you want to send 2 messages in one go (say: init + do_something). The pc responds to the first msg, but the controller is still sending and drops most of the data. * PC starts sending before controller is executing the receive() function. Data at the beginning of the packet may get lost * any drop in communication may cause a deadlock (i.e. controller and desktop are both waiting for the other end to send something.

So to diagnose: check the overflow bit. If it is set, you have lost data and you need to work on the interrupt functions. If possible, monitor both sides (at least the state; a blink a led for send, and one for receive for instance).

A rs232 monitor may help you (you'll need some additional ports for this. There are many (including freeware) applications which can monitor multiple rs232 ports and provide timestamps. So you can observe the order of communications. Google found me : link; I've used several similar utilities in the past years.

like image 196
Adriaan Avatar answered Oct 12 '22 07:10

Adriaan