简体   繁体   English

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

[英]Different behaviour of same code on different devices

I'm baffled. 我很困惑。 I have an identical program being uploaded to two different Arduino boards. 我有一个相同的程序被上载到两个不同的Arduino开发板上。 It's in C++. 在C ++中。

It's a much larger program, but I'm cutting it down to only the problematic part. 这是一个更大的程序,但我将其仅缩小到有问题的部分。 Basically, I have a "host" Arduino and a "rover" Arduino communicating wirelessly. 基本上,我有一个“主机” Arduino和一个“流动” Arduino进行无线通信。 There are multiple rover units, but the problem is only happening on one of them. 有多个流动站,但问题仅发生在其中一个上。 The rovers have motors that need to be calibrated, so I have static variables in my Motor namespace to hold those calibration values. 流动站具有需要校准的电机,因此我的Motor名称空间中有静态变量来保存这些校准值。 To prevent having to change these values in the source code, recompile and reupload every time I want to calibrate it, I'm using the wireless system to allow the host to send calibration values to the rover at runtime. 为了避免必须在源代码中更改这些值,每次我要对其进行校准时都重新编译并重新上传,我正在使用无线系统允许主机在运行时将校准值发送到流动站。

Here's the problem: on one rover, the values aren't being updated if I call the ChangeSpeed method, but they do get updated if I modify the variables directly. 这是问题所在:在一个流动站上,如果我调用ChangeSpeed方法,则不会更新这些值,但是如果我直接修改变量,它们的确会更新。

Let me stress that it works fine on four out of five rovers . 让我强调一下, 它在五分之四的流动车中效果很好 The problem is happening on exactly one rover. 问题恰好发生在一辆流动站上。 The code being uploaded to each rover is identical. 上载到每个流动站的代码是相同的。

The following code is causing a problem: 以下代码导致了问题:

Motor.h: Motor.h:

namespace Motor
{
    static unsigned char left_speed = 0;
    static unsigned char right_speed = 0;

    void ChangeSpeed(unsigned char, unsigned char);
}

Motor.cpp: Motor.cpp:

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: Main.cpp:

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));
}

Case 1: 情况1:

On the bad rover, the host invokes UpdateSpeedValuesBad(5, 5) , and then invokes ReturnSpeedValues . 车上,主机调用UpdateSpeedValuesBad(5, 5) ,然后调用ReturnSpeedValues The output is: 输出为:

Change speed: 5, 5
Motor write: 5, 5
Motor read: 0, 0

Case 2: 情况2:

On the bad rover, the host invokes UpdateSpeedValuesGood(5, 5) , and then invokes ReturnSpeedValues . 车上,主机调用UpdateSpeedValuesGood(5, 5) ,然后调用ReturnSpeedValues The output is: 输出为:

Motor write: 5, 5
Motor read: 5, 5

Case 3: 情况3:

On a good rover, the host invokes UpdateSpeedValuesBad(5, 5) , and then invokes ReturnSpeedValues . 良好的流动站上,主机调用UpdateSpeedValuesBad(5, 5) ,然后调用ReturnSpeedValues The output is: 输出为:

Change speed: 5, 5
Motor write: 5, 5
Motor read: 5, 5

Am I doing something fundamentally wrong? 我是从根本上做错了吗? I come from a C# background so C++ is pretty alien to me. 我来自C#背景,所以C ++对我来说很陌生。 I have no idea if I'm doing something that has undefined behaviour. 我不知道我是否正在做一些行为不确定的事情。


Edit: If I shove everything into one single file, it works fine. 编辑:如果我将所有内容都推送到一个文件中,则效果很好。 It only fails once I split it up across a header file and a cpp file. 只有在将其拆分为头文件和cpp文件后,它才会失败。

Main.cpp: Main.cpp:

#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()
{
}

Output: 输出:

Before: 0
Change speed: 5
Bad attempt: 5
Good attempt: 5

Edit 2: I dove into the assembly and found this for the bad case. 编辑2:我沉迷于程序集,发现这种情况不好。 It's using different memory addresses based on whether I call ChangeSpeed or I update the values directly. 根据我调用ChangeSpeed还是直接更新值,它使用不同的内存地址。 Anyone know why that would be? 有人知道为什么会这样吗? Is it a compiler bug or is it not guaranteed that the addresses will be the same? 是编译器错误,还是不能保证地址相同?

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

You should not make these variables static. 您不应将这些变量设为静态。 A static global variable means the variable is local to the compilation unit (generally, the .cpp file that is being compiled) so if you have the static variable declared in a header file and include that header file in 3 different .cpp files that are compiled separately then you will have 3 independent versions of that variable, one for each .cpp file. 静态全局变量表示该变量在编译单元(通常是正在编译的.cpp文件)中是本地变量,因此,如果您在头文件中声明了静态变量并将该头文件包含在3个不同的.cpp文件中,单独编译,则将具有该变量的3个独立版本,每个.cpp文件一个。

Instead, in the header file declare them as 相反,在头文件中将它们声明为

namespace Motor {
  extern unsigned char left_speed;
  extern unsigned char right_speed;

  void ChangeSpeed(unsigned char, unsigned char);
}

This tells the compiler that some file will provide a definition for these variables and to use that common shared definition. 这告诉编译器某些文件将提供这些变量的定义并使用该公共共享定义。

Then, since the variables need to be defined exactly once (this is called the one definition rule ) you should add the definition to Motor.cpp : 然后,由于变量需要精确定义一次(这被称为一个定义规则 ),因此应将定义添加到Motor.cpp

unsigned char Motor::left_speed = 0;
unsigned char Motor::right_speed = 0;

I chose Motor.cpp to hold the definition since this is where the definition of the ChangeSpeed function is. 我选择Motor.cpp持有的定义,因为这是其中的定义ChangeSpeed功能。

In C++, the static keyword works much differently than in C#. 在C ++中, static关键字的作用与C#不同。 It might be somewhat similar when used inside a class definition, but that is where the similarities end. 当在类定义中使用时,它可能有点相似,但这就是相似之处的终点。

By declaring the variables static , you limit their range to the current code unit. 通过将变量声明为static ,可以将它们的范围限制为当前代码单元。 In other words, by having static variables in your .h , you cause Motor.cpp and Main.cpp to have separate copies of those two variables. 换句话说,通过在.h中包含static变量,可以使Motor.cppMain.cpp具有这两个变量的单独副本。

Your case 1 modifies the Motor.cpp copies of those variables while outputs the ones from Main.cpp . 您的案例1修改了这些变量的Motor.cpp副本,同时从Main.cpp输出了这些副本。 Case 2 works only on Main.cpp copies so it works as expected. 情况2仅适用于Main.cpp副本,因此可以正常工作。 And if you shove everything into a single file, you just get one copy of those variables. 而且,如果将所有内容都推送到一个文件中,则只会得到这些变量的一个副本。

You should either: 您应该:

  1. Declare the variables as extern unsigned char left_speed, right_speed; 将变量声明为extern unsigned char left_speed, right_speed; in the header, and then declare the values as unsigned char left_speed = 0; 在标头中,然后将值声明为unsigned char left_speed = 0; in one of the .cpp files; 在一个.cpp文件中;
  2. Declare the static variables in one of the .cpp files directly (eg Rotor.cpp ) and use functions to get their values like you use one to set them. 直接在其中一个.cpp文件中声明静态变量(例如Rotor.cpp ),并使用函数来获取它们的值,就像使用一个来设置它们一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM