c - Arduino EthernetServer read() 仅在 Serial 初始化并打印读取字符时有效

标签 c embedded serial-port arduino ethernet

我有一个 Arduino 项目,我从网络服务器读取数据。

我有一个 EthernetClient,它在回调函数中逐个字符地读取数据。

我的工作代码看起来像(只有相关部分):

void setup() {
  Serial.begin(9600);
  ...
}

void loop() {
  char* processedData = processData(callback); // this is in a external lib
}

boolean callback(char* buffer, int& i) {
  ...

  if (Client.available()) {
    char c      = client.read();
    buffer[i++] = c;

    Serial.print(c);
  }

  ...
}

这没有任何问题(读取和处理数据),但是当我删除 Serial.begin(9600);Serial.print(c); 时停止工作,我不知道为什么?唯一改变的是 char c 没有打印出来。可能是什么问题?

最佳答案

回调函数在看似不相关的代码被更改时改变其行为的一个常见原因是与优化器相关的错误。

许多嵌入式编译器无法理解程序中会调用回调函数(或中断服务例程)。他们看不到对该函数的显式调用,然后假设它从未被调用过。

当编译器做出这样的假设时,它会优化被回调函数改变的变量,因为它看不到变量在初始化点和访问点之间被程序改变了。

// Bad practice example:

int x; 

void main (void)
{
  x=5;
  ...

  if(x == 0) /* this whole if statement will get optimized away, 
                the compiler assumes that x has never been changed. */
  {
    do_stuff();
  }
}

void callback (void)
{
  x = 0;
}

当这个错误发生时,几乎不可能被发现,它会导致任何一种奇怪的症状。

解决方案是始终将 main() 和中断/回调/线程之间共享的所有文件范围(“全局”)变量声明为 volatile。这使得编译器不可能做出不正确的优化器假设。


(请注意,volatile 关键字不能用于实现同步,也不能保证任何内存障碍。这个答案与此类问题没有丝毫关系! )

关于c - Arduino EthernetServer read() 仅在 Serial 初始化并打印读取字符时有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13953346/

相关文章:

c - 我合并两个链表的功能无法正常工作

assembly - 他们如何如此快地将十进制转换为十六进制(记住)?

java - 如何以编程方式更改嵌入式 HornetQ 中的端口

filesystems - 适合嵌入式使用的强大文件系统

java - 从 JFrame 类调用串行端口类

c - C 有本地绑定(bind)吗?

c - 理解c中两个链表实现之间的区别

c - openMp:需要并行化具有数据依赖性问题的循环

serial-port - 串行端口上的 TCP/IP

c# - 串行端口第一个命令确定。第二个命令错误