【问题标题】:How can I send a string serially from an 8051 only ONCE?如何仅从 8051 串行发送字符串一次?
【发布时间】:2009-08-01 10:58:10
【问题描述】:

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

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

我尝试使用 DB9 上的 RTS(请求发送)引脚(第 7 个引脚),因为我在某处读到,如果我取消该引脚上的电压,它将停止数据流向串行端口。所以我所做的是对我的微控制器进行编程以发送字符串,然后将逻辑电平 0 发送到连接到我的 DB9 RTS 引脚的输出引脚。然而,这并没有奏效。

有人有什么建议吗?我真的很感激他们。

编辑

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

有人可以验证它实际上只发送一次字符串吗?

编辑

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

非常感谢您的帮助! :)

【问题讨论】:

  • 我在PC上使用的软件是X-CTU for Xbee模块。这是我的微控制器上的代码:#include void SerTx(unsigned char);无效主(无效){ TMOD = 0x20; TH1 = 0xFD; SCON = 0x50; TR1 = 1; SerTx('O'); SerTx('N'); SerTx('L'); SerTx('Y'); void SerTx(unsigned char x) { SBUF = x;而(TI==0); TI = 0;有人可以验证它实际上只发送一次字符串吗?
  • 请编辑您的问题,并插入代码,格式化为代码,以便于阅读。
  • @CodeConfused:很高兴我们都找到了解决方案!我还有两个要求给你。 (1) 对于这个问题,以及您在 Stack Overflow 上的所有其他问题,请通过单击您认为可以为您的问题提供最佳答案的大勾号,将答案标记为“已接受”。这对于将来可能有相同问题的其他人很有用,因为他们可以立即看到最佳答案。 (2) 在本题中,请将代码格式化为代码。为此,请编辑问题,选择代码,然后按代码按钮(它是带有 1 和 0 的按钮)。谢谢。

标签: c embedded serial-port microcontroller 8051


【解决方案1】:

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

您在 PC 上使用什么软件?我建议使用超级终端或PuTTY 等简单的通信软件。如果他们多次显示正在发送到 PC 的字符串,那么很可能是 8051 上运行的软件出现故障。

编辑:说实话,这听起来像是工程师必须定期面对的那种调试,所以这是一个很好的机会来练习好的老式有条不紊的问题 -解决。

如果我可能很直率,我建议您执行以下操作:

  1. 调试。尝试一下,但不要猜测。实验。对你的代码做一些小的改动,看看会发生什么。尝试一切你能想到的。搜索网络以获取更多信息。
  2. 如果这不能产生解决方案,请返回此处,并为我们提供所需的所有信息。这包括相关的代码片段、您正在使用的硬件的完整详细信息,以及您在第 1 步中尝试的内容的相关信息。

编辑:我没有代表来编辑问题,所以这是 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; } 
}

正如 Neil 和 Brooksmoses 在他们的回答中提到的,在嵌入式系统中,主函数永远不允许终止。因此,您要么需要将代码置于无限循环中(这可能是不经意间发生的事情),要么在最后添加无限循环,这样程序就会有效地停止。

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

所以试试这个(我还添加了一些 cmets 试图让代码更容易理解):

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

【讨论】:

  • 我正在使用 Xbee 模块,Steve,所以 PC 上的软件是 X-CTU。但是,我也尝试使用超级终端进行故障排除。发生同样的事情,即连续接收字符串。
  • 当然你可能很直率,史蒂夫! :) 任何有帮助的东西!你的代码成功了,非常感谢。附言TI=0 并不是完全禁用发射器。 TI 必须强制为零,因为在传输一个字符后,8051 会升高 TI 标志以表示它已准备好进行更多传输。
【解决方案2】:

您发布的代码在 main() 中没有循环,因此您需要确定当 main() 在发送“Y”后返回时,编译器的 C 运行时会做什么。鉴于您的问题,我想编译器会生成一些代码来进行一些清理,然后重新启动 micro(可能是硬件重置,可能只是重新启动 C 运行时)。看起来你的程序和你写的完全一样,但是你忽略了 main() 被调用之前和之后发生的事情。

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

请注意,如果您的微控制器有看门狗定时器,它可能会进行干预并强制进行意外重置。如果发生这种情况,您的字符串将在每次看门狗重置时发送一次(可能是每秒一次,速率取决于您的硬件)。

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

【讨论】:

  • 谢谢尼尔,你说得对。但是有没有办法让我在不涉及硬件的情况下退出空循环?
  • P.S.我认为我的微控制器没有看门狗定时器。
  • 我想简单的答案是:让循环做点什么。嵌入式固件通常有一个永远运行的主循环。该循环将轮询硬件以查看是否有一些工作要做,例如来自串行端口的新数据或更改的数字输入,然后调用适当的函数来处理该事件。
【解决方案3】:

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

通常在 8051 代码上必须显式发送每个字符,但我假设 C 运行时会为您处理这个问题。

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

【讨论】:

    【解决方案4】:

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

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

    在我工作过的一些系统中,exit() 根本没有真正实现——如果你不打算使用它,甚至不要在它上面浪费一个字节!结果是,当执行路径到达 main() 的末尾时,芯片只是徘徊在执行下一位内存中的任何内容的 lala 土地上,并且通常很快就会陷入循环或陷入困境错误的操作码非法。非法操作码故障的通常结果是……重新启动芯片。

    对于这里发生的事情,这似乎是一个合理的理论。

    【讨论】:

    • 谢谢布鲁克斯莫斯。你解释得真好!我认为这正是这里发生的事情。
    猜你喜欢
    • 1970-01-01
    • 2016-03-10
    • 2014-04-03
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    • 2017-12-15
    相关资源
    最近更新 更多