STM32 printf 和 RTC

3

* 更新 *

这是我发现的情况。每当我在代码中使用那个函数时,它不会真正使代码锁定。它实际上会使读取RTC I²C函数执行变得非常缓慢,但代码仍然可以正常运行,只是每次读取RTC时需要等待很长时间。

因此,RTC有一个闹钟中断,这会触发ISR内部的其他I²C交互,因此看起来它正在尝试同时进行两个I²C通信,从而减慢了进程速度。我删除了ISR中的函数,现在它可以正常工作了。我将继续调查。


我在使用IAR 5.40编程STM32F103微控制器时遇到了这个问题。如果我尝试printf一个本地变量,它会导致代码在甚至到达该函数之前的另一点处冻结。

可能是什么原因导致这种情况?

这是该函数:

u8 GSM_Telit_ReadSms(u8 bSmsIndex)
{
  char bTmpSms[3] = {0};

  itoa(bSmsIndex, bTmpSms, 10); // Converts the smsindex into a string

  printf("index = %s\n", bTmpSms); // This printf caused the code to get stuck in the RTC // byte read function!

  GSM_Telit_RequestModem("AT+CMGR=""1", 10, "CMGR", 5, 0);
  return 1;
}

我也尝试过这个方法,但并没有导致我遇到的锁定问题:

u8 GSM_Telit_ReadSms(u8 bSmsIndex)
{
  char bTmpSms[3] = {0};

  itoa(bSmsIndex, bTmpSms, 10);
  printf("index = 2\n");


  GSM_Telit_RequestModem("AT+CMGR=""1", 10, "CMGR", 5, 0);
  return 1;
}

没有任何优化启用,当尝试从我的I²C RTC读取一个字节时,代码会卡住,但是一旦我删除这个printf("index = %s\n", bTmpSms);或者使用这个printf("index = 2\n");,那么一切都很顺利。有什么想法吗?
实际上,bSmsIndex永远不会超过30,即使在调用此函数之前锁定也会发生。

你是说即使这个函数还没有被执行过,锁定也会发生吗? - The Archetypal Paul
是的,那正是它! - jramirez
哦,这是一个非常有趣的方面,直到现在我才意识到。当您卡在I2C RTC读取中时,堆栈跟踪是否显示任何有趣的内容? 您是否在使用多任务处理? - Michael Burr
@jramirez,如果你的答案是正确的,请接受它 ;) - Colin Hebert
@Colin 我知道,但是它说“您需要等待2天才能接受自己的答案”,我想我只能等待了,抱歉。 - jramirez
7个回答

2

char bTmpSms[3] 只能存储"99"。如果你的bSmsIndex大于等于100,那么你将尝试写入不属于你的内存。


更新后的编辑

我在本地机器上没有itoa的参考资料,但我找到了这个(http://www.cplusplus.com/reference/clibrary/cstdlib/itoa/)。根据该参考文献,目标数组必须足够长以存储任何可能的值。检查你的文档:你特定的itoa可能会有所不同。

或者使用sprintfsnprintf或一些由标准描述的函数。


正确,但导致问题的不是写入(因为第二段代码可以工作),而是printf读取字符串时引发的。然而,写入也可能在某个时候会导致问题,所以它也是一个问题。 - The Archetypal Paul
@Paul - 但谁知道这个错误的写入可能会破坏什么? - Michael Burr
1
就我而言,向不属于你的内存写入数据可能会导致你的程序将钱从你的银行账户转移到我的账户 :-) - pmg

1

看起来如果我不将变量bTmpSms初始化为某些值,问题就会出现。

我也意识到问题不在printf上。而是在itoa函数上。这让我检查了一下,即使我认为那不是问题,当我注释掉itoa函数时,整个代码就可以工作了。

所以最终我做了这个:

u8 GSM_Telit_ReadSms(u8 bSmsIndex)
{
  char bTmpSms[4] = "aaa";    // I still need to find out why this is !!!

  itoa(bSmsIndex, bTmpSms, 10); // Converts the smsindex into a string

  printf("index = %s\n", bTmpSms); // This printf caused the code to get stuck in the RTC // byte read function!

  GSM_Telit_RequestModem("AT+CMGR=""1", 10, "CMGR", 5, 0);
  return 1;
}

这是我得到的itoa函数:
char itoa(int value, char* result, int base)
{
  // Check that the base if valid
  if (base < 2 || base > 36) {
      *result = '\0';
      return 0;
  }

  char* ptr = result, *ptr1 = result, tmp_char;
  int tmp_value;

  do
  {
    tmp_value = value;
    value /= base;
    *ptr++ = "zyxwvutsr

qponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; } while (value);

  // Apply negative sign
  if (tmp_value < 0)
      *ptr++ = '-';
  *ptr-- = '\0';
  while(ptr1 < ptr)
  {
    tmp_char = *ptr;
    *ptr--= *ptr1;
    *ptr1++ = tmp_char;
  }
  return 1;
}

看看我的回答。我不认为你解决了问题,我认为你掩盖了它。它将在以后回来找麻烦。 - Mark Ransom
我同意你的看法。这就是为什么我说我稍后会检查这个函数。但至少我知道问题的大部分所在。 - jramirez
我希望我没有误解你 - 听起来问题甚至在调用atoi函数之前就已经出现了,因此错误也不可能在那里。你并不真正知道问题出在哪里。 - Mark Ransom
只有当atoi函数出现时才会出现问题,并且函数并没有执行到那里。当该函数被注释掉时,代码可以正确运行,这给了我们一些关于问题所在的想法。此外,我将使用sprintf(bTmpSms,“%d”,bSmsIndex),这似乎是有效的。再次说明,这是嵌入式编程,因此需要我一些时间来逐步查找问题的真正原因,我会更新任何进展。 - jramirez

1
一些想法:
如果 itoa() 没有正确地以 NUL 结尾字符串,那么对 printf 的调用可能会导致机器永远寻找 NUL。 pmg 说得很好。
此外,请考虑 itoa() 的第一个参数的类型。如果它是有符号的,并且您传入了一个无符号整数,则 bTmpSms 中可能会出现意外的减号。请改用 sprintf()

itoa是以空字符结尾的,我已经检查过了。 - jramirez

1

代码的更改会将内存中其余部分的代码移动。我猜测,代码的其他部分(未在此处列出)正在破坏某个随机位置;在第一种情况下,该位置包含关键内容,在第二种情况下则不包含。

这些是最难追踪的问题之一。祝你好运。

*也许不是最糟糕的 - 如果多个线程之间存在竞争条件,只有一周才会显现出来,那么情况可能会更糟。但仍然不是我最喜欢的错误类型。


0
bSmsIndex 的值是多少?

如果大于99,则转换为字符串时将成为三位数。当以零终止时,它将成为四个字符,但您仅为 bTmpSms 分配了三个字符,因此 null 可能会被覆盖,并且 printf 将尝试打印 bTmpSms 后面的任何内容直到下一个 null。这可能真的会访问任何东西。


0

你试图打印的bSmsIndex的值是多少?

如果它大于99,那么你就会超出bTmpSms数组的范围。

如果这没有帮助,那么使用IAR的非常好的调试器-我会在调用printf()的地方进入汇编窗口,并单步执行,直到出现问题。这可能会清楚地说明问题所在。

或者作为快速排除故障的方法,尝试将数组大小调整为较大的值(可能为8),然后查看发生了什么。


我尝试过将数组扩大,但是仍然出现了同样的问题。 - jramirez
@jramirez:我认为你可能需要卷起袖子,开始踏入运行时深渊... - Michael Burr

0

尝试将此区域与索引 = 2 与索引 = %s 进行分解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接