首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >同一代码在不同设备上的不同行为

同一代码在不同设备上的不同行为
EN

Stack Overflow用户
提问于 2012-07-15 19:15:49
回答 2查看 142关注 0票数 1

我很困惑。我有一个相同的程序被上传到两个不同的Arduino板。在C++里。

这是一个大得多的程序,但我要把它缩减到有问题的部分。基本上,我有一个“主机”Arduino和一个“漫游者”Arduino无线通信。有多个漫游者单位,但问题只发生在其中一个。漫游者有需要校准的马达,所以我的Motor命名空间中有静态变量来保存这些校准值。为了避免在源代码中更改这些值,每次我想校准它时都要重新编译和重新上传,我使用无线系统允许主机在运行时将校准值发送给漫游者。

问题是:在一个漫游者上,如果我调用ChangeSpeed方法,这些值不会被更新,但是如果我直接修改变量,它们就会得到更新。

让我强调,在五分之四的火星车上,它工作得很好。问题就发生在一个漫游者身上。上传到每个漫游者的代码是相同的。

以下代码造成了问题:

汽车.h:

代码语言:javascript
复制
namespace Motor
{
    static unsigned char left_speed = 0;
    static unsigned char right_speed = 0;

    void ChangeSpeed(unsigned char, unsigned char);
}

Motor.cpp:

代码语言:javascript
复制
void Motor::ChangeSpeed(unsigned char l_speed, unsigned char r_speed)
{
    left_speed = l_speed;
    right_speed = r_speed; 

    soft.println("Change speed: " + String(left_speed) + ", " + String(right_speed));
}

Main.cpp:

代码语言:javascript
复制
void UpdateSpeedValuesBad(unsigned char l_speed, unsigned char r_speed)
{
    Motor::ChangeSpeed(l_speed, r_speed);
    soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}

void UpdateSpeedValuesGood(unsigned char l_speed, unsigned char r_speed)
{
    Motor::left_speed = l_speed;
    Motor::right_speed = r_speed;
    soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}

void ReturnSpeedValues()
{
    soft.println("Motor read: " + String(Motor::left_speed) + ", " + String(Motor::right_speed));
}

案例1:

bad漫游者上,主机调用UpdateSpeedValuesBad(5, 5),然后调用ReturnSpeedValues。产出如下:

代码语言:javascript
复制
Change speed: 5, 5
Motor write: 5, 5
Motor read: 0, 0

案例2:

bad漫游者上,主机调用UpdateSpeedValuesGood(5, 5),然后调用ReturnSpeedValues。产出如下:

代码语言:javascript
复制
Motor write: 5, 5
Motor read: 5, 5

案例3:

good漫游者上,主机调用UpdateSpeedValuesBad(5, 5),然后调用ReturnSpeedValues。产出如下:

代码语言:javascript
复制
Change speed: 5, 5
Motor write: 5, 5
Motor read: 5, 5

我做了什么根本不对的事吗?我来自C#背景,所以C++对我来说非常陌生。我不知道我是否在做一些行为不明确的事情。

编辑:,如果我把所有东西都塞进一个文件中,它就能正常工作。只有当我将其拆分成一个头文件和一个cpp文件时,它才会失败。

Main.cpp:

代码语言:javascript
复制
#include <SoftwareSerial.h>

SoftwareSerial soft(9, 10);

namespace Motor
{
  static int left_speed = 0;

  void ChangeSpeed(unsigned char);
}

void Motor::ChangeSpeed(unsigned char l_speed)
{
  left_speed = l_speed;
  soft.println("Change speed: " + String(left_speed));
}

void setup()
{
  soft.begin(9600);

  soft.println("Before: " + String(Motor::left_speed));

  Motor::ChangeSpeed(5);
  soft.println("Bad attempt: " + String(Motor::left_speed));

  Motor::left_speed = 5;
  soft.println("Good attempt: " + String(Motor::left_speed));
}

void loop()
{
}

输出:

代码语言:javascript
复制
Before: 0
Change speed: 5
Bad attempt: 5
Good attempt: 5

编辑2: --我深入到程序集中,发现这是针对坏情况的。它根据我是调用ChangeSpeed还是直接更新值来使用不同的内存地址。有人知道为什么吗?这是一个编译器错误,还是它没有保证地址将是相同的?

代码语言:javascript
复制
000000a8 <setup>:
{ 
    Motor::ChangeSpeed(5, 6);
  a8:   85 e0           ldi r24, 0x05   ; 5
  aa:   66 e0           ldi r22, 0x06   ; 6
  ac:   0e 94 5f 00     call    0xbe    ; 0xbe <_ZN5Motor11ChangeSpeedEhh>

    Motor::left_speed = 5;
  b0:   85 e0           ldi r24, 0x05   ; 5
  b2:   80 93 00 01     sts 0x0100, r24

    Motor::right_speed = 6;
  b6:   86 e0           ldi r24, 0x06   ; 6
  b8:   80 93 01 01     sts 0x0101, r24
}
  bc:   08 95           ret

000000be <_ZN5Motor11ChangeSpeedEhh>:

void Motor::ChangeSpeed( unsigned char l_speed, unsigned char r_speed )
{
    left_speed = l_speed;
  be:   80 93 02 01     sts 0x0102, r24
    right_speed = r_speed; 
  c2:   60 93 03 01     sts 0x0103, r22
  c6:   08 95           ret
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-15 20:12:07

不应该使这些变量是静态的。静态全局变量意味着该变量是编译单元的本地变量(通常是正在编译的.cpp文件),因此如果您在头文件中声明了静态变量,并将该头文件包含在单独编译的3个不同的.cpp文件中,那么您将拥有该变量的3个独立版本,每个.cpp文件一个。

相反,在头文件中将它们声明为

代码语言:javascript
复制
namespace Motor {
  extern unsigned char left_speed;
  extern unsigned char right_speed;

  void ChangeSpeed(unsigned char, unsigned char);
}

这告诉编译器,某个文件将为这些变量提供一个定义,并使用该公共共享定义。

然后,由于需要精确定义变量一次(这称为一种定义规则),所以应该将该定义添加到Motor.cpp

代码语言:javascript
复制
unsigned char Motor::left_speed = 0;
unsigned char Motor::right_speed = 0;

我选择Motor.cpp来保存定义,因为这是ChangeSpeed函数的定义所在。

在C++中,static关键字的工作方式与C#大不相同。在类定义中使用时,它可能有点类似,但这就是相似之处所在。

票数 5
EN

Stack Overflow用户

发布于 2012-07-15 20:06:58

通过声明变量static,可以将变量的范围限制在当前的代码单元上。换句话说,通过在您的static中包含.h变量,可以使Motor.cppMain.cpp拥有这两个变量的单独副本。

您的案例1修改这些变量的Motor.cpp副本,同时输出来自Main.cpp的变量。案例2只在Main.cpp副本上工作,因此它按预期工作。如果你把所有的东西都塞进一个文件里,你只会得到这些变量的一个副本。

你应该要么:

  1. 在头文件中将变量声明为extern unsigned char left_speed, right_speed;,然后在其中一个.cpp文件中将值声明为unsigned char left_speed = 0;
  2. 在一个.cpp文件中直接声明静态变量(例如,Rotor.cpp),并使用函数获取它们的值,就像使用一个函数来设置它们一样。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11494827

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档