我很困惑。我有一个相同的程序被上传到两个不同的Arduino板。在C++里。
这是一个大得多的程序,但我要把它缩减到有问题的部分。基本上,我有一个“主机”Arduino和一个“漫游者”Arduino无线通信。有多个漫游者单位,但问题只发生在其中一个。漫游者有需要校准的马达,所以我的Motor命名空间中有静态变量来保存这些校准值。为了避免在源代码中更改这些值,每次我想校准它时都要重新编译和重新上传,我使用无线系统允许主机在运行时将校准值发送给漫游者。
问题是:在一个漫游者上,如果我调用ChangeSpeed方法,这些值不会被更新,但是如果我直接修改变量,它们就会得到更新。
让我强调,在五分之四的火星车上,它工作得很好。问题就发生在一个漫游者身上。上传到每个漫游者的代码是相同的。
以下代码造成了问题:
汽车.h:
namespace Motor
{
static unsigned char left_speed = 0;
static unsigned char right_speed = 0;
void ChangeSpeed(unsigned char, unsigned char);
}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:
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。产出如下:
Change speed: 5, 5
Motor write: 5, 5
Motor read: 0, 0案例2:
在bad漫游者上,主机调用UpdateSpeedValuesGood(5, 5),然后调用ReturnSpeedValues。产出如下:
Motor write: 5, 5
Motor read: 5, 5案例3:
在good漫游者上,主机调用UpdateSpeedValuesBad(5, 5),然后调用ReturnSpeedValues。产出如下:
Change speed: 5, 5
Motor write: 5, 5
Motor read: 5, 5我做了什么根本不对的事吗?我来自C#背景,所以C++对我来说非常陌生。我不知道我是否在做一些行为不明确的事情。
编辑:,如果我把所有东西都塞进一个文件中,它就能正常工作。只有当我将其拆分成一个头文件和一个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()
{
}输出:
Before: 0
Change speed: 5
Bad attempt: 5
Good attempt: 5编辑2: --我深入到程序集中,发现这是针对坏情况的。它根据我是调用ChangeSpeed还是直接更新值来使用不同的内存地址。有人知道为什么吗?这是一个编译器错误,还是它没有保证地址将是相同的?
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发布于 2012-07-15 20:12:07
不应该使这些变量是静态的。静态全局变量意味着该变量是编译单元的本地变量(通常是正在编译的.cpp文件),因此如果您在头文件中声明了静态变量,并将该头文件包含在单独编译的3个不同的.cpp文件中,那么您将拥有该变量的3个独立版本,每个.cpp文件一个。
相反,在头文件中将它们声明为
namespace Motor {
extern unsigned char left_speed;
extern unsigned char right_speed;
void ChangeSpeed(unsigned char, unsigned char);
}这告诉编译器,某个文件将为这些变量提供一个定义,并使用该公共共享定义。
然后,由于需要精确定义变量一次(这称为一种定义规则),所以应该将该定义添加到Motor.cpp中
unsigned char Motor::left_speed = 0;
unsigned char Motor::right_speed = 0;我选择Motor.cpp来保存定义,因为这是ChangeSpeed函数的定义所在。
在C++中,static关键字的工作方式与C#大不相同。在类定义中使用时,它可能有点类似,但这就是相似之处所在。
发布于 2012-07-15 20:06:58
通过声明变量static,可以将变量的范围限制在当前的代码单元上。换句话说,通过在您的static中包含.h变量,可以使Motor.cpp和Main.cpp拥有这两个变量的单独副本。
您的案例1修改这些变量的Motor.cpp副本,同时输出来自Main.cpp的变量。案例2只在Main.cpp副本上工作,因此它按预期工作。如果你把所有的东西都塞进一个文件里,你只会得到这些变量的一个副本。
你应该要么:
extern unsigned char left_speed, right_speed;,然后在其中一个.cpp文件中将值声明为unsigned char left_speed = 0;;.cpp文件中直接声明静态变量(例如,Rotor.cpp),并使用函数获取它们的值,就像使用一个函数来设置它们一样。https://stackoverflow.com/questions/11494827
复制相似问题