views:

706

answers:

5

Hello everyone,

I am making an 8051 microcontroller communicate wirelessly with a computer. The microcontroller will send a string to its serial port (DB9) and the computer will receive this string and manipulate it.

My problem is that I do not know how to make the 8051 transmit the string just once. Since I need to manipulate the string at the PC end it has to be received only one time. Currently, even though in the C code I am sending the string once, on my computer I am receiving the same string continuously. I assume this is because whatever is in the SBUF is continuously transmitted. Is there any way that I can send my string only once? Is there a way to empty the SBUF?

I tried to use the RTS (Request to Send) pin (7th pin) on the DB9 because I read somewhere that if I negated the voltage on that pin it would stop the flow of data to the serial port. So what I did was programmed my microcontroller to send the string and then sent logic level 0 to an output pin that was connected to my DB9 RTS pin. However, that didn't work.

Does anyone have any suggestions? I'd really appreciate them.

EDIT

The software that I'm using on the PC is X-CTU for Xbee modules. This is the code on my microcontroller:

include reg51.h 
void SerTx(unsigned char);  
void main(void)  
{  
  TMOD = 0x20;  
  TH1 = 0xFD;  
  SCON = 0x50;  
  TR1 = 1;   

  SerTx('O');  
  SerTx('N');  
  SerTx('L');  
  SerTx('Y'); 

}

void SerTx(unsigned char x)  
{  
  SBUF = x;  
  while(TI==0);   
  TI = 0;   
}  

Could someone please verify that it is in fact only sending the string once?

EDIT

Looks like Steve, brookesmoses and Neil hit the nail on the head when they said that it was what was happening AFTER my main function that was causing the problem. I just tried the suggested code Steve put up (more specifically the for(;;); and defining serTX outside of main) and it worked perfectly. The controller is probably rebooted and hence the same code keeps repeating itself.

Thanks so much for the help! :)

A: 

This particular article is for assembly, not C, but it might prove useful: http://www.8052.com/tutser.phtml

Amber
+2  A: 

It's hard to say what the problem is without seeing any of the 8051 code. For example, a logic error on that side could lead to the data being sent multiple times, or the 8051 software might be waiting for an ACK which is never received, etc.

Normally on an 8051 code has to explicitly send each character, but I assume this is taken care of for you by the C run-time.

Use of the RTS/CTS (Request To Send/Clear To Send) is for flow control (i.e. to prevent buffer overruns - the buffers are usually pretty small on these microcontrollers) and not to stop transmission altogether.

Vinay Sajip
+2  A: 

Can you confirm that the 8051 really is sending the data only once? One way to check would be to use a scope to see what is happening on the UART's TX pin.

What software are you using on the PC? I'd suggest using simple communications software like HyperTerminal or PuTTY. If they are showing the string being sent to the PC multiple times, then chances are the fault is in the software running on the 8051.

EDIT: To be honest, this sounds like the kind of debugging that engineers have to face on a regular basis, and so it's a good opportunity for you to practise good old-fashioned methodical problem-solving.

If I may be very blunt, I suggest you do the following:

  1. Debug. Try things out, but don't guess. Experiment. Make small changes in your code and see what happens. Try everything you can think of. Search the web for more information.
  2. If that doesn't produce a solution, then return here, and provide us with all the information we need. That includes relevant pieces of the code, full details of the hardware you're using, and information about what you tried in step 1.

EDIT: I don't have the rep to edit the question, so here's the code posted by the OP in the comment to her question:

#include<reg51.h>

void SerTx(unsigned char);

void main(void)
{
    TMOD = 0x20; TH1 = 0xFD; SCON = 0x50; TR1 = 1;
    SerTx('O'); SerTx('N'); SerTx('L'); SerTx('Y');

    void SerTx(unsigned char x)
     { SBUF = x; while(TI==0); TI = 0; } 
}

As Neil and Brooksmoses mention in their answers, in an embedded system, the main function is never allowed to terminate. So you either need to put your code in an infinite loop (which may be what is inadvertently happening), or add an infinite loop at the end, so the program effectively halts.

Also, the function SerTx should be defined outside main. This may be syntatically correct, but it keeps things simple not declaring functions within other functions.

So try this (I've also added some comments in an attempt to make the code easier to understand):

#include<reg51.h>

void SerTx(unsigned char);

void main(void)
{
    /* Initialise (need to add more explanation as to what
     each line means, perhaps by replacing these "magic
     numbers" with some #defines) */
    TMOD = 0x20;
    TH1  = 0xFD;
    SCON = 0x50;
    TR1  = 1;

    /* Transmit data */
    SerTx('O'); SerTx('N'); SerTx('L'); SerTx('Y');

    /* Stay here forever */
    for(;;) {}

}

void SerTx(unsigned char x)
{
    /* Transmit byte */
    SBUF = x;

    /* Wait for byte to be transmitted */
    while(TI==0) {}

    /* Clear transmit interrupt flag */
    TI = 0;
}
Steve Melnikoff
I'm using Xbee modules, Steve, so the software on the PC is X-CTU. However, I did try to troubleshoot by using Hyperterminal too. The same thing happens on that, i.e. the string is received continuously.
CodeConfused
Absolutely you may be very blunt, Steve! :) Anything that helps! Your code did the trick, thanks very much. P.S. TI=0 isn't exactly to disable the transmitter. TI has to be forced to zero because after the transmission of one character the 8051 raises the TI flag to signal that it's ready for more transmission.
CodeConfused
+5  A: 

The code you posted has no loop in main(), so you need to determine what your compiler's C runtime does when main() returns after sending 'Y'. Given your problem, I imagine the compiler generates some code to do some cleanup then restart the micro (maybe a hardware reset, maybe just be restarting the C runtime). It looks like your program works exactly as you've written it, but you've ignored what happens before and after main() is called.

If you want your string sent once and only once, ever, then you need something like while(1) {} added after the last character is sent. But, then your program is doing nothing -- it will just execute an empty loop forever. A reset (such as power cycling) is needed to start again, and send the string.

Note that if your micro has a watchdog timer, it might intervene and force an unexpected reset. If this happens, your string will be sent once for each watchdog reset (which could be something like once each second, with the rate depending on your hardware).

Also, having serTx() defined nested inside main() is probably not what you want.

Neil
Thanks Neil, you were absolutely right. But is there a way for me to exit the empty loop without involving hardware?
CodeConfused
P.S. I don't think my micro has a watchdog timer.
CodeConfused
I guess the simple answer is: make the loop do something. Embedded firmware typically has a main loop that runs forever. This loop would poll the hardware to see if there is some work to do, such as new data from a serial port or a changed digital input, then call an appropriate function to deal with that event.
Neil
+2  A: 

Echoing Neil's answer (in a reply, since I don't yet have the rep to comment): In a typical microcontroller situation without an OS, it's not immediately clear what the exit() function that gets implicitly called at the end of main() should do -- or, more accurately, it can't do the usual "end the program and return to the OS", because there's no OS to return to.

Moreover, in a real application, you almost never want the program to just stop, unless you turn off the system. So one thing that the exit() implementation should definitely not do is take up a lot of code space.

In some systems I've worked on, exit() is not actually implemented at all -- if you're not going to use it, don't even waste a byte on it! The result is that when the execution path gets to the end of main(), the chip just wanders off into a lala land of executing whatever happens to be in the next bit of memory, and typically quickly ends up either stuck in a loop or faulting with an illegal opcode. And the usual result of a fault with an illegal opcode is ... rebooting the chip.

That seems like a plausable theory for what's happening here.

Brooks Moses
Thanks brooksmoses. You explained that really well! And I think that's exactly what was going on here.
CodeConfused