如何从仅8011的ONCE串行发送字符串?

时间:2021-09-26 01:41:08

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.

我正在使8051微控制器与计算机进行无线通信。微控制器将字符串发送到其串行端口(DB9),计算机将接收此字符串并对其进行操作。

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?

我的问题是我不知道如何让8051只传输一次字符串。由于我需要在PC端操作字符串,因此必须只接收一次。目前,即使在C代码中我发送一次字符串,在我的计算机上我连续收到相同的字符串。我认为这是因为SBUF中的任何内容都是连续传输的。有什么方法可以只发送一次我的字符串吗?有没有办法清空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.

我试图在DB9上使用RTS(请求发送)引脚(第7个引脚),因为我读到某个地方,如果我否定了该引脚上的电压,它将阻止数据流到串行端口。所以我所做的是编程我的微控制器发送字符串,然后将逻辑电平0发送到连接到我的DB9 RTS引脚的输出引脚。但是,这没有用。

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:

我在PC上使用的软件是Xbee模块的X-CTU。这是我的微控制器上的代码:

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, *esmoses 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.

看起来像史蒂夫,布鲁克斯和尼尔在他们说这是我的主要功能导致问题之后发生的事情时头上钉了一针。我刚刚尝试了Steve提出的建议代码(更具体地说是for(;;);并在main之外定义了serTX)并且它工作得很好。控制器可能重新启动,因此相同的代码不断重复。

Thanks so much for the help! :)

非常感谢你的帮助! :)

5 个解决方案

#1


6  

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.

你能否确认8051真的只发送一次数据?一种检查方法是使用示波器来查看UART TX引脚上发生的情况。

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.

你在PC上使用什么软件?我建议使用HyperTerminal或PuTTY等简单的通讯软件。如果他们多次显示发送到PC的字符串,则可能是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. 调试。尝试一下,但不要猜。实验。对代码进行细微更改,看看会发生什么。尝试你能想到的一切。在网上搜索更多信息。
  3. 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.
  4. 如果这不能产生解决方案,那么请返回此处,并向我们提供我们需要的所有信息。这包括代码的相关部分,您正在使用的硬件的完整详细信息,以及您在步骤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:

编辑:我没有编辑问题的代表,所以这里是OP在她的问题的评论中发布的代码:

#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 *smoses 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.

正如Neil和*smoses在他们的答案中提到的那样,在嵌入式系统中,主要功能永远不会被允许终止。因此,您需要将代码置于无限循环中(这可能是无意中发生的),或者在末尾添加无限循环,因此程序有效地停止。

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.

此外,函数SerTx应该在main之外定义。这可能在语法上是正确的,但它使事情变得简单,而不是在其他函数中声明函数。

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;
} 

#2


6  

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.

您发布的代码在main()中没有循环,因此您需要确定在发送'Y'后main()返回时编译器的C运行时所执行的操作。鉴于你的问题,我想编译器会生成一些代码来进行一些清理,然后重新启动微控制器(可能是硬件复位,也许只是重新启动C运行时)。看起来你的程序与你编写的程序完全一样,但是你忽略了调用main()之前和之后发生的事情。

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.

如果您希望您的字符串只发送一次,那么您需要在发送最后一个字符后添加while(1){}之类的内容。但是,那么你的程序什么都不做 - 它将永远执行一个空循环。需要重置(例如电源循环)才能重新启动,并发送字符串。

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).

请注意,如果您的micro具有看门狗定时器,它可能会介入并强制意外重置。如果发生这种情况,您的字符串将在每次看门狗复位时发送一次(可能类似于每秒一次,速率取决于您的硬件)。

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

另外,serTx()定义嵌套在main()中可能不是你想要的。

#3


2  

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.

如果没有看到任何8051代码,很难说出问题是什么。例如,该侧的逻辑错误可能导致数据被多次发送,或者8051软件可能正在等待从未接收到的ACK等。

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.

通常在8051代码上必须显式发送每个字符,但我认为这是由C运行时为您处理的。

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.

使用RTS / CTS(请求发送/清除发送)用于流量控制(即防止缓冲区溢出 - 缓冲区通常在这些微控制器上非常小)而不是完全停止传输。

#4


2  

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.

回应Neil的回答(在回复中,因为我还没有代表评论):在没有操作系统的典型微控制器情况下,不能立即清楚在main结尾隐式调用的exit()函数是什么( )应该做 - 或者更确切地说,它不能做通常的“结束程序并返回操作系统”,因为没有操作系统可以返回。

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.

而且,在实际应用程序中,除非关闭系统,否则几乎从不希望程序停止运行。因此,exit()实现绝对不应该做的一件事就是占用大量的代码空间。

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.

在我工作的一些系统中,exit()实际上根本没有实现 - 如果你不打算使用它,甚至不会在它上面浪费一个字节!结果是,当执行路径到达main()的末尾时,芯片就会徘徊进入执行下一位存储器中的任何事情的lala land,并且通常很快就会陷入循环或者发生非法操作错误。非法操作码故障的通常结果是......重新启动芯片。

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

对于这里发生的事情来说,这似乎是一个可信的理论。

#5


-1  

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

这篇特别的文章是用于汇编而不是C,但它可能有用:http://www.8052.com/tutser.phtml

#1


6  

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.

你能否确认8051真的只发送一次数据?一种检查方法是使用示波器来查看UART TX引脚上发生的情况。

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.

你在PC上使用什么软件?我建议使用HyperTerminal或PuTTY等简单的通讯软件。如果他们多次显示发送到PC的字符串,则可能是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. 调试。尝试一下,但不要猜。实验。对代码进行细微更改,看看会发生什么。尝试你能想到的一切。在网上搜索更多信息。
  3. 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.
  4. 如果这不能产生解决方案,那么请返回此处,并向我们提供我们需要的所有信息。这包括代码的相关部分,您正在使用的硬件的完整详细信息,以及您在步骤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:

编辑:我没有编辑问题的代表,所以这里是OP在她的问题的评论中发布的代码:

#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 *smoses 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.

正如Neil和*smoses在他们的答案中提到的那样,在嵌入式系统中,主要功能永远不会被允许终止。因此,您需要将代码置于无限循环中(这可能是无意中发生的),或者在末尾添加无限循环,因此程序有效地停止。

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.

此外,函数SerTx应该在main之外定义。这可能在语法上是正确的,但它使事情变得简单,而不是在其他函数中声明函数。

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;
} 

#2


6  

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.

您发布的代码在main()中没有循环,因此您需要确定在发送'Y'后main()返回时编译器的C运行时所执行的操作。鉴于你的问题,我想编译器会生成一些代码来进行一些清理,然后重新启动微控制器(可能是硬件复位,也许只是重新启动C运行时)。看起来你的程序与你编写的程序完全一样,但是你忽略了调用main()之前和之后发生的事情。

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.

如果您希望您的字符串只发送一次,那么您需要在发送最后一个字符后添加while(1){}之类的内容。但是,那么你的程序什么都不做 - 它将永远执行一个空循环。需要重置(例如电源循环)才能重新启动,并发送字符串。

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).

请注意,如果您的micro具有看门狗定时器,它可能会介入并强制意外重置。如果发生这种情况,您的字符串将在每次看门狗复位时发送一次(可能类似于每秒一次,速率取决于您的硬件)。

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

另外,serTx()定义嵌套在main()中可能不是你想要的。

#3


2  

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.

如果没有看到任何8051代码,很难说出问题是什么。例如,该侧的逻辑错误可能导致数据被多次发送,或者8051软件可能正在等待从未接收到的ACK等。

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.

通常在8051代码上必须显式发送每个字符,但我认为这是由C运行时为您处理的。

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.

使用RTS / CTS(请求发送/清除发送)用于流量控制(即防止缓冲区溢出 - 缓冲区通常在这些微控制器上非常小)而不是完全停止传输。

#4


2  

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.

回应Neil的回答(在回复中,因为我还没有代表评论):在没有操作系统的典型微控制器情况下,不能立即清楚在main结尾隐式调用的exit()函数是什么( )应该做 - 或者更确切地说,它不能做通常的“结束程序并返回操作系统”,因为没有操作系统可以返回。

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.

而且,在实际应用程序中,除非关闭系统,否则几乎从不希望程序停止运行。因此,exit()实现绝对不应该做的一件事就是占用大量的代码空间。

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.

在我工作的一些系统中,exit()实际上根本没有实现 - 如果你不打算使用它,甚至不会在它上面浪费一个字节!结果是,当执行路径到达main()的末尾时,芯片就会徘徊进入执行下一位存储器中的任何事情的lala land,并且通常很快就会陷入循环或者发生非法操作错误。非法操作码故障的通常结果是......重新启动芯片。

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

对于这里发生的事情来说,这似乎是一个可信的理论。

#5


-1  

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

这篇特别的文章是用于汇编而不是C,但它可能有用:http://www.8052.com/tutser.phtml