2016-11-27 180 views
1

我对Arduino和C/C++非常陌生,所以请和我一起裸照。实际上,值得注意的是,虽然我使用的是Arduino IDE,但运行代码的设备是ESP8266。使用回调函数打破while循环的最佳方式是什么?

我确定我错误地构建了我的代码,但我不确定最好的方法,希望有人能指出我朝着正确的方向。

为了我的情况可以归结为一个简单的例子:

我的主循环()函数只是运行在各个循环中的回调()函数(PubSubClient MQTT)。这个回调函数首先设置一个全局布尔变量“跑”为false,然后会做1 3件事:

  1. 如果“1”被接收它会运行一个函数调用动作1()。
  2. 如果收到'2',它将运行一个名为action2()的函数。
  3. 如果接收到'3',它将打印一行到Serial。
  4. 如果收到其他东西或没有收到任何东西,它什么都不会做。

两个动作1()和动作2()函数是看起来像这样的循环:

void action1() { 
    run = true;    // Do this once to start the loop 
    while (run == true) { 
    // Do some stuff 
    callback();   // To check for new messages 
    } 
} 

这里的问题:

如果动作1(运行)和回调( )收到'3'一切正常。回调会将“run”变量设置为false,将行打印到Serial,然后返回到action1()循环,该循环将中断并且整个事件返回到loop()。如果action1()正在运行,并且callback()接收到启动action2()的命令,则action2()将启动,action1()将暂停等待返回。

因此,我认为在action1()和action2()之间来回切换可能会导致内存问题,因为循环堆叠在一起。我看到设备崩溃,如果我足够做到这一点。我可能会回调()需要'排队'action1()或action2(),然后让主循环()运行它们吗?这样我们总是会回到主循环(),从而结束所有其他的循环。但我确定有更好的解决方案。

任何帮助,将不胜感激。

+0

似乎'main'应该只有一个循环。回调应该返回一个介于0和3之间的值,让'main'处理剩下的部分。 – user3386109

回答

2

你的代码结构确实是不正确:

  • 调用回调会堆积起来。如果您有很多回调事件,则可能会导致堆栈溢出。
  • 使用全局变量run使得callback()不可重入,这可能会导致处理提前结束。

事实上,你最好选择一个事件循环,这将是你已经指出的基础上的队列:

  • 当收到AI项目项目callback()将只叫它会排队项目并返回。
  • 您的主循环会在每次迭代时从队列中读取某些内容(如果可用)并调用正确的操作。
  • 如果需要,您也可以调用一些轮询函数。
  • 如果需要,您还可以调用输出函数来反映当前状态。

不清楚主循环是永远运行还是直到收到一些特殊输入或者直到队列为空。由你决定。

我不知道你的回调是如何在arduino模型中触发的。但是如果它中断正在运行的进程,则还需要确保队列上没有竞争条件,例如锁定。

0

while循环通常是一个糟糕的设计。有loop()函数,你应该使用它。

重新记录上次收到的有效命令并重复调用相应的action_x()。这个功能“做一些事情”并且返回速度非常快,所以你不需要那个callback()

如果action_x()返回一个状态来表示它已完成任务,通常很方便。

相关问题