This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] EK-TM4C1294XL:接收和比较字符串时出现问题

Guru**** 2478765 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/689789/ek-tm4c1294xl-trouble-receiving-and-comparing-strings

器件型号:EK-TM4C1294XL

大家好、我必须为我的项目使用多个 UART 端口-其中一个端口将等待一个关键字并使用相应的字符串进行响应。 我有两个主要问题:

我的接收功能只能接收6个字符而不会混乱-我可以解决这个问题、并且使所有关键字最多只能包含6个字符、但我认为存在一个更大的潜在问题、我需要注意。 我有点卡、我不确定我的错误是什么、如果有任何建议、帮助或指向某个方向、我会非常感激

void EnableUART0 (void)
{
//
//启用 GPIO 和 UART 0
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
SysCtlPeripheralEnable (SYSCTL_Periph_UART0);

//
//为 UART 模式配置 UART 引脚
//
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);


UARTClockSourceSet (UART0_BASE、UART_CLOCK_SYSTEM);
UARTConfigSetExpClk (UART0_BASE、g_ui32SysClock、115200、UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE);

内部寄存器(INT_UART0、UART0Get);
IntEnable (INT_UART0);
UARTIntEnable (UART0_BASE、UART_INT_RX | UART_INT_RT);

}

void UART0print (const char* text)
{
const char* p;

//迭代`文本`的每个字符,
//直到我们到达 NUL 终端器
对于(p =文本;*p!='\0';p++)
{

//将每个字符传递给某个函数
UARTCharPut (UART0_BASE、*p);
}
}

空 UART0Get (空)
{
int i = 0;
// if (UARTCharsAvail (UART0_BASE)== true)
while (UARTCharsAvail (UART0_BASE))
{
Incoming1[i]= UARTCharGetNonBlocking (UART0_BASE);
++I;
// int i;
// for (i=0;i<21;i++)//可能会将21更改为将来更真实的内容>>>
// {
// Incoming1[i]= UARTCharGetNonBlocking (UART0_BASE);
//}
}

我所提到的问题与 UART0Get 函数有关、该函数最多只能使用6个字符、没有问题、例如7、略超过6个字符、 它将消除第一个字符并打印最后6个字符、例如、如果我发送"1234567"、它将仅存储"234567"。 如果我发送大于6的内容、那么它会非常随机地运行、我不明白发生了什么。

在我的主函数中、我尝试使其识别我发送的"Temp"一词、它应使用我目前在测试期间使用的任意字符串值进行回复:

int
main (void)
{
G_ui32SysClock = MAP_SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480)、120000000);

FPUEnable();
//FPURoundingModeSet (FPU_ROUND POS_INF);

IntMasterEnable();//使处理器能够响应中断。



//configureUARTTesting();
EnableUART0();

while (1)
{
UART0print (Incoming1);
if (strcmp (Incoming1、"Temp")=0)
{
UART0print (TempValue);
// UART0print (Incoming1);
}
// UART0print (测试);
// UART0print (行);
// UART0print (Incoming1);
// UART0print (行);
// UART0print (电感);
// UART0print (行);
// UART0print (频率);
// UART0print (行);
}
} 

TempValue 只是我之前保存过的一个字符串变量、其外观如下所示

字符 TempValue[]="50 Deg";

Incoming1只是一个字符数组、用于存储通过 UART 发送的传入字符、定义如下

字符 Incoming1[15];

起初、我尝试将 Incoming1保留为一个没有设置空间数的数组、但这会导致更多问题、当我在 Incoming1中键入值(例如在本例中为15)时、这似乎会消失。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Hisham、您好!

    我看不到任何令人惊讶的错误、因为您至少能够接收一些数据。

    关于调试的想法很少。

    1) 1)是否可以跟踪重新进入 UART0Get 函数是否可能导致数据被覆盖?

    2) 2)您是否曾尝试降低 UART 速度、以便不会像这样快速地接收数据、并为代码提供更多处理时间?

    3) 3)您可能希望通过将增量作为缓冲存储函数的一部分来删除额外的代码行、如下所示:

    Incoming1[i++]= UARTCharGetNonBlocking (UART0_BASE); 

    4) 4)调试时、您能否在退出 UART0Get 后立即暂停代码并查看缓冲区中的内容? (不确定这是您确定存储内容的方式)。 此外、当查看缓冲区时、您可以看到哪些索引具有您期望的数据、尤其是在您将其初始化为0时。

    另外、关于在最初将缓冲区保留为未定义空间的注释、是的、这很有道理、会导致问题。 在几乎任何情况下、您都需要为缓冲器保留空间。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Ralph、
    我会尝试回答您的问题-我不熟悉这一点、我的方法可能会很愚蠢、因此如果我错了或误解了、请纠正我的问题。

    1) 1)是否可以跟踪重新进入 UART0Get 函数是否可能导致数据被覆盖?

    每次通过 UART 传输某个数据时、UART 中断都会调用 UART0Get 函数。该函数应使用新文本替换 Incoming1并将其覆盖、 这样做是因为我正在与之通信的器件应该查询所需的值、例如"temp"应该使用 TempValue 进行回复、TempValue 会存储该值、如果它向我发送"example"、我应该使用电感值等进行回复

    2) 2)您是否曾尝试降低 UART 速度、以便不会像这样快速地接收数据、并为代码提供更多处理时间?

    我尝试使用9600 buadrate 而不是115200、但同样的问题仍然存在-这使我认为速度可能不是问题、但我可以再次尝试、因为我自那时以来已经做了几个更改。

    3) 3)您可能希望通过将增量作为缓冲存储函数的一部分来删除额外的代码行、如下所示:
    Incoming1[i++]= UARTCharGetNonBlocking (UART0_BASE);

    我没有尝试过这种方法、我认为您建议这样做是为了保存一行代码、我认为它不会/打算解决我的问题、但我现在还是会尝试一下(我可能错了)

    4) 4)调试时、您能否在退出 UART0Get 后立即暂停代码并查看缓冲区中的内容? (不确定这是您确定存储内容的方式)。 此外、当查看缓冲区时、您可以看到哪些索引具有您期望的数据、尤其是在您将其初始化为0时。

    我不确定如何做到这一点、也许您可以提供更多的解释。 我一直在使用 PuTTy 之类的东西进行检查、因此如果查看主函数、我会在 if 语句之前打印 Incoming1变量。 因此、我使用 Putty 发送"Temp"、并在比较之前将其打印回我。 但是、它只是不断输出"Temp"、因此 if 语句永远不会经过。 到目前为止、这是我的调试方法、也许您可以解释一种更具说服力的方法。 出于某种原因、我无法获取 CCS 来显示 Incoming1变量的值。

    此外、您是否还想知道、如果我的传入文本大于6个字符、为什么它的行为如此怪异?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Hisham、您好!

    我对3)的评论是按照优化的思路、以防速度成为一个问题、此外、这只是 C 语言编码的一般更好的做法。

    感谢您的进一步详细介绍、UART0Get 的命名使我错过了它是一个 ISR。

    通过暂停、我的意思是使用断点、以便您可以在调试期间暂停代码并自行查看缓冲区。 使用 Putty RIGHT 可能无法为我们提供完整的图片。 如果在索引方面有些内容是关闭的、那么您将会丢失该内容、而 Putty 可能会包含其他终止字符。 在 CCS 上软件仍处于调试模式时、通过在 Putty 上发送字符串后暂停代码、您可以将缓冲区作为变量添加到"Watch Expressions"列表、然后浏览其内容。 这样、您就可以看到您正在接收或未接收的数据。

    查看您的 while 循环、您注意到它总是打印出 Temp、我想知道您是否应该在打印之间设置延迟、以便有时间接收新的数据包? "Temp"消息的发送速度有多快? 它是否可以使 UART 总线一直处于忙状态?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嘿 Ralph、我正在尝试查看缓冲区的值、但我不知道在哪里找到它。 它不在我的变量位置。 我包含了一张图片、以便您可以看到我看到的内容。 我还使用了缓冲区值、并且根据我必须允许断点恢复的次数、似乎至少有2个终止字符。 我不确定它们是什么。 我确实注意到、一旦它经过"Temp"、就会用新的一行打印、因此我认为可能会有/n 和其他一些东西、但我不确定可能会是什么。

    请告诉我我如何观察到缓冲区中的内容?

    我知道我没有使用 Putty、我只说 Putty、因为它比我使用的更受欢迎、但我认为它们是相同的。 串行通讯设备中显示的"Temp"是我输入的用来启动中断的"Temp"。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Hisham、您好!

    这不是我的意思、我是说在 CCS 中使用 Expressions 视图直接从内存中查看变量、该变量利用了 CCS 和 JTAG 的调试功能。 您可以在 CCS 帮助中搜索"Expressions view"以了解有关该视图的更多详细信息。

    可以通过转到"View"菜单并选择"Expressions"来显示它、然后您可以通过在中键入名称或右键单击它并选择"Add Watch Expression..."将缓冲区添加到它。

    如果您要在中键入名称、您可以在此处看到一个简单的演示(忽略断点部分): www.youtube.com/watch

    为了设置给定程序设置方式的断点、您可能需要在 ISR 中放置一个标志、以指示何时收到数据、 然后、您可以中断主代码中设置的标志、以便当您通过 UART 发送消息时、可以立即中断以查看接收后缓冲区中的数据。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    好的、Ralph 我得到了它、感谢您的帮助、还有一个'\x0d'、它仅在我创建一个变量来与 char var[]="Temp\x0d"进行比较时才有效。
    再次感谢你。
    我还有一个问题、您知道为什么我可以保存的字符数量有字符限制? 如果我发送一个超过6个字符的字符串、但它未将它们正确保存在我的 Incoming1变量中、我们将会感谢您的任何建议。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Hisham、您好!

    发送超过6个字符的字符串时、您会发现什么行为? 您是否未收到其他字符? 第一个是否被覆盖? 还有事吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    第一个被覆盖。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Hisham、

    这让我怀疑 ISR 可能会退出、然后重新进入。 测试这种情况的一种简单方法是将 GPIO 设置为在每个 ISR 条目上进行切换、然后在发送6字节与更大字节的数据包后监视 GPIO、并查看是否有一个或多个切换。 如果是多个、则表示 UART 数据的速度不够快、无法保持在 ISR 内、问题是 ISR 内的计数器复位。

    我假设测试的另一种方法是使 index 变量成为易失性全局变量、然后处理应用程序代码内部的索引重置、 虽然需要对应用程序进行设置、以了解它应该接收到多少字节、因此它不会是一个灵活的修复、但如果这是问题、它将有助于快速调试。

    如果我们确认情况确实如此、则可以讨论如何处理这种情况。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    好的、我尝试对其进行测试、并让您知道我发现了什么。
    谢谢!
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您说得对、中断退出太快、被召回、我在 for 循环中添加了一个延迟、我的问题得到了解决、我想知道您是否有任何想法、除了延迟之外、我还可以如何解决这个问题?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Hisham、您好!

    不确定延迟是一种很好的使用方法、尤其是在中断中。

    一种方法是让部分消息包含将发送的字节数。 例如、如果您认为不需要超过255个字节、则将缓冲区设置为以255个字节进行最大容量传输、然后将数据包的第一个字节作为"标头"发送、这是数据包其余部分的字节计数。 因此、如果发送50个字节、则发送0x32 (十六进制为50)作为第一个字节。 在代码中、跟踪您是否收到初始字节以及是否收到标志。 如果您得到一个初始字节、请将其存储为最大索引计数器(全局变量)、并且索引计数器也是全局变量(确保它们都是易失性的)。 然后、每当您接收到字节时、请检查索引与最大索引之间的关系、如果该关系较小、请添加到缓冲区并递增。 如果它相等、您可以完成最后一个事务并忽略更多字节、并选择性地设置第二个标志、向应用程序代码指示您已完全接收到一个字节。 然后、在您的应用中、当您准备好接收更多数据时、您可以重置最大索引和"初始字节"标志。

    一种简单得多的方法与我最初描述的第二个调试想法相同、即只需将索引设为全局变量并在应用程序中对其进行重置、 但是、了解变量何时需要重置会给应用带来负担、这就是我建议在接收到的数据包中设置标头字节的原因、因为这样、应用程序就可以知道每次需要什么。 如果您认为您的最大大小(如10或15字节)较低、并且您确信仅在应用程序中处理该数据、或者每次都有固定大小的传输、那么更简单的方法可能是可行的。

    我相信我没有想到的其他方法是、虽然我有很多软件经验、但我没有为软件系统做过很多详细的架构、但希望这能为您提供一些有用的想法。