記事ディレクトリ
注: 私のコードは、Punctual Atoms によって提供された MPU6050 実験コードに基づいており、オイラー角を見つけるために dmp ライブラリを使用しています。
1. 質問 1: MPU6050 の初期化が失敗し、while ループに入らない
理由: MPU6050 は電源投入時の初期化中にセルフテストを実行する必要があります。ハードウェアが非常に傾いた状態にあるとスタックしてしまいます。平らに保つか、ランダムに振らないようにする必要があります。
2. 質問 2: MPU6050 を AD0 ピンに接続する必要がありますか?
回答: AD0 ピンがグランドに接続されている場合、ハードウェア アドレスは 0x68 です。3V3 に接続されている場合、アドレスは 0x69 です。ここに配線する必要はありません。アドレスはコードで定義されている 0x68 です。このとき、MPU6050 の初期化関数に AD0 を置くこともできます。ピンの初期化ステートメントはコメントアウトされています。
3. 質問 3: MPU6050 は 5V または 3V3 で電源を供給できますか?
回答: 私が購入した共通版は両方に接続できます。
4. 質問 4: MPU6050 の IIC 通信にはハードウェア IIC を使用するのとソフトウェア IIC を使用するのはどちらが良いですか?
A: 状況によるとしか言えません。MPU6050 の場合、ハードウェア IIC は高速であり、CPU 占有率が低くなります。ソフトウェア IIC 通信はより多くの CPU 時間と計算リソースを必要としますが、ハードウェア IIC はオンラインで不安定で問題が発生しやすいと言われており、必要な通信速度はそれほど高くないため、ここではソフトウェア IIC シミュレーションを使用する方が良いでしょう。より高速な伝送が必要な場合は、ハードウェア IIC を使用してください。
これはハードウェア IIC の初期化関数です。
void IIC_Init( u32 bound , u16 address )
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitTSturcture;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE );
// GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOB, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOB, &GPIO_InitStructure );
I2C_InitTSturcture.I2C_ClockSpeed = bound;
I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_16_9;
I2C_InitTSturcture.I2C_OwnAddress1 = address;
I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init( I2C2, &I2C_InitTSturcture );
I2C_Cmd( I2C2, ENABLE );
I2C_AcknowledgeConfig( I2C2, ENABLE );
}
これはソフトウェア IIC の初期化関数です。
//初始化IIC接口引脚
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_7|GPIO_Pin_6);
}
ハードウェア IIC の利便性は、通信、読み取り、書き込み操作のために既製のメンバー変数とライブラリ関数を呼び出すことができること、ソフトウェア IIC の利便性は、SCL ピンと SDA ピンをカスタマイズし、GPIO の高レベルと低レベルを使用できることです。 IIC 効果をシミュレートするには、start、stop、ack などの関数を記述する必要がありますが、関連するコードはオンラインで簡単に見つけることができます。
5. 質問 5: 変更が推奨されるコード
ソースコードは次のとおりです。
if(mpu_dmp_get_data(&Pitch, &Roll, &Yaw)==0){
//xxxxxx
}
次に、次のように変更します。
while(mpu_dmp_get_data(&Pitch, &Roll, &Yaw)!=0){
}
この変更後は、新しいデータがバッファに急速に入るために FIFO がオーバーフローするのを効果的に防止し、MPU6050 がスタックするのを防ぐことができます。
6. 質問 6: 非常に形而上学的な質問: 配線
問題の説明: 電源は正常にオンになり、MPU6050 が揺れていないときは正常にデータを印刷しますが、あまりにも速く揺れるとフリーズします。最初はケーブルの問題かと思い、ケーブルを交換しましたが、問題は依然として発生しました。そこでコードの問題かと思ったのですが、デバッグすると特定のプログラムに引っかかるのではなく、完全にランダムに中断されてしまいます。その後、VCC、GND、SCL、SDAポートとDuPontラインをホットグルーで接着しましたが、この問題は依然として存在します。非常に形而上学的です。
解決策: もっと形而上学を。数日間のテストの後、これはデュポンの製品ラインの長さに関係があることが判明しました。私は長さ 40cm の Dupont ワイヤーを使用していますが、常に問題が発生します。そして20cmの短いデュポンワイヤーに交換したところ、大丈夫でした!!!とんでもないことに、長いデュポン線は SCL と SDA には接続できるが、VCC と GND には接続できず、妨害なく正常に動作するには、VCC と GND の少なくとも一方を短い線に接続する必要があります。…
7. ソフトウェアIICのポート構成について
コードは以下のように表示されます。
//IO方向设置
#define SDA_IN() {
GPIOB->CFGLR&=0X0FFFFFFF;GPIOB->CFGLR|=(u32)8<<28;}
#define SDA_OUT() {
GPIOB->CFGLR&=0X0FFFFFFF;GPIOB->CFGLR|=(u32)3<<28;}
//IO操作函数
//#define IIC_SCL PBout(6)
//#define IIC_SDA PBout(7)
//#define READ_SDA PBin(9)
#define IIC_SCL_0 GPIO_ResetBits(GPIOB,GPIO_Pin_6)
#define IIC_SDA_0 GPIO_ResetBits(GPIOB,GPIO_Pin_7)
#define IIC_SCL_1 GPIO_SetBits(GPIOB,GPIO_Pin_6)
#define IIC_SDA_1 GPIO_SetBits(GPIOB,GPIO_Pin_7)
stm32 のビットバンド動作は他のプラットフォームへの移植に適していないため、書き換える必要があり、書き換え形式は上記の通りです。