私は困惑しています。同じプログラムを2つの異なるArduinoボードにアップロードしています。それはC++です。
これははるかに大きなプログラムですが、問題のある部分だけに切り詰めています。基本的に、私には「ホスト」Arduinoと「ローバー」Arduinoがワイヤレスで通信しています。複数のローバーユニットがありますが、問題はそのうちの1つでのみ発生しています。ローバーにはキャリブレーションが必要なモーターがあるため、Motor
名前空間にこれらのキャリブレーション値を保持する静的変数があります。ソースコードでこれらの値を変更する必要がないように、キャリブレーションを行うたびに再コンパイルして再アップロードするために、ワイヤレスシステムを使用して、ホストが実行時にキャリブレーション値をローバーに送信できるようにしています。
問題は次のとおりです。あるローバーでは、ChangeSpeed
メソッドを呼び出しても値は更新されませんが、変数を直接変更すると値は更新されます。
5つのローバーのうち4つで正常に機能することを強調しておきます。問題はちょうど1台のローバーで起こっています。各ローバーにアップロードされるコードは同じです。
次のコードが問題を引き起こしています。
Motor.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:
不良ローバーでは、ホストがを呼び出してUpdateSpeedValuesBad(5, 5)
から、を呼び出しますReturnSpeedValues
。出力は次のとおりです。
Change speed: 5, 5
Motor write: 5, 5
Motor read: 0, 0
ケース2:
不良ローバーでは、ホストがを呼び出してUpdateSpeedValuesGood(5, 5)
から、を呼び出しますReturnSpeedValues
。出力は次のとおりです。
Motor write: 5, 5
Motor read: 5, 5
ケース3:
優れたローバーでは、ホストはを呼び出しUpdateSpeedValuesBad(5, 5)
てから、を呼び出しますReturnSpeedValues
。出力は次のとおりです。
Change speed: 5, 5
Motor write: 5, 5
Motor read: 5, 5
私は根本的に間違ったことをしていますか?私はC#のバックグラウンドを持っているので、C++は私にはかなり異質です。未定義の振る舞いをしているのかどうかわかりません。
編集:すべてを1つのファイルにまとめると、正常に機能します。ヘッダーファイルと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