天天看點

linux序列槽讀取mpu9250資料,模拟 I2C 讀取 MPU9250 資料的測試筆記

硬體:STM32F103ZET6 + GY9250

軟體:Keil MDK(v5.27)+ STM32CUBEMX(v5.2.1)

這裡我在使用STM32CUBEMX最新版本(v5.5.0)生成Keil工程時出現了“MDK-ARM v5.27 project generation have a problem.”的問題(并不是路徑問題)。換用了較低的v5.2.1版本後順利生成工程。

STM32CUBEMX使用HAL庫建立工程。

在方法完全相同的情況下(STM32CUBEMX工程配置相同,main.c檔案代碼相同),使用IAR(v8.32.4)建立的工程無法順利讀取磁力計資料。(???)

由于MPU9250内部采用I2C與磁力計通信,使用I2C讀取會相對簡單。

Here we go!

1、使用STM32CubeMX配置工程

(1)RCC選取HSE:Crystal/Ceramic Resonator(石英/陶瓷 晶振);

(2)在Clock Configuration中設定HCLK為72(MHz);

(3)配置USART1的MODE為Asynchronous,用來向上位機發送接收到的資料;

(4)配置PB6、PB7為GPIO_Output,修改GPIO mode為Output Open Drain(開漏輸出),将Maximum output speed設定為Medium(10MHz);

其餘設定保持預設,記得勾選“Generate peripheral initialization as a pair of '.c/.h' files per peripheral”,然後生成代碼。

2、USART1發送

#define usart1_print(...) HAL_UART_Transmit(&huart1, u_buf, sprintf((char *)u_buf, __VA_ARGS__), 0xffff);

在使用前需要包含頭檔案“stdio.h”并且定義緩沖區。

#include "stdio.h"

uint8_t u_buf[0xff];

3、宏定義GPIO操作

#define SCL_H GPIOB->BSRR = 0x0040 //GPIO_Pin_6

#define SCL_L GPIOB->BRR = 0x0040 //GPIO_Pin_6

#define SDA_H GPIOB->BSRR = 0x0080 //GPIO_Pin_7

#define SDA_L GPIOB->BRR = 0x0080 //GPIO_Pin_7

#define SCL_read GPIOB->IDR & 0x0040 //GPIO_Pin_6

#define SDA_read GPIOB->IDR & 0x0080 //GPIO_Pin_7

4、模拟I2C

函數聲明

void I2C_Delay(void);

int I2C_Start(void);

void I2C_Stop(void);

void I2C_Ack(void);

void I2C_NoAck(void);

int I2C_WaitAck(void);

void I2C_SendByte(uint8_t SendByte);

unsigned char I2C_ReadByte(void);

int Single_Write(unsigned char SlaveAddress, unsigned char REG_Address, unsigned char REG_data);

unsigned char Single_Read(unsigned char SlaveAddress, unsigned char REG_Address);

函數定義

void I2C_Delay(void)

{

uint8_t i=20; //可以适當調整

while(i)

{

i--;

}

}

int I2C_Start(void)

{

SDA_H;

SCL_H;

I2C_Delay();

if(!SDA_read)return 0; //SDA線為低電平則總線忙,退出

SDA_L;

I2C_Delay();

if(SDA_read)return 0; //SDA線為高電平則總線出錯,退出

SDA_L;

I2C_Delay();

return 1;

}

void I2C_Stop(void)

{

SCL_L;

I2C_Delay();

SDA_L;

I2C_Delay();

SCL_H;

I2C_Delay();

SDA_H;

I2C_Delay();

}

void I2C_Ack(void)

{

SCL_L;

I2C_Delay();

SDA_L;

I2C_Delay();

SCL_H;

I2C_Delay();

SCL_L;

I2C_Delay();

}

void I2C_NoAck(void)

{

SCL_L;

I2C_Delay();

SDA_H;

I2C_Delay();

SCL_H;

I2C_Delay();

SCL_L;

I2C_Delay();

}

int I2C_WaitAck(void)

{

SCL_L;

I2C_Delay();

SDA_H;

I2C_Delay();

SCL_H;

I2C_Delay();

if(SDA_read)

{

SCL_L;

I2C_Delay();

return 0;

}

SCL_L;

I2C_Delay();

return 1;

}

void I2C_SendByte(uint8_t SendByte)

{

uint8_t i = 8;

while(i--)

{

SCL_L;

I2C_Delay();

if(SendByte & 0x80)

SDA_H;

else

SDA_L;

SendByte<<=1;

I2C_Delay();

SCL_H;

I2C_Delay();

}

SCL_L;

}

unsigned char I2C_ReadByte(void)

{

uint8_t i = 8;

uint8_t ReceiveByte = 0;

SDA_H;

while(i--)

{

ReceiveByte<<=1;

SCL_L;

I2C_Delay();

SCL_H;

I2C_Delay();

if(SDA_read)

{

ReceiveByte | = 0x01;

}

}

SCL_L;

return ReceiveByte;

}

int Single_Write(unsigned char SlaveAddress, unsigned char REG_Address, unsigned char REG_data)

{

if(!I2C_Start())return 0;

I2C_SendByte(SlaveAddress);

if(!I2C_WaitAck()){I2C_Stop();return 0;}

I2C_SendByte(REG_Address);

I2C_WaitAck();

I2C_SendByte(REG_data);

I2C_WaitAck();

I2C_Stop();

HAL_Delay(2);

return 1;

}

unsigned char Single_Read(unsigned char SlaveAddress, unsigned char REG_Address)

{

unsigned char REG_data;

if(!I2C_Start())return 0;

I2C_SendByte(SlaveAddress);

if(!I2C_WaitAck()){I2C_Stop(); return 0;}

I2C_SendByte((uint8_t) REG_Address);

I2C_WaitAck();

I2C_Start();

I2C_SendByte(SlaveAddress+1);

I2C_WaitAck();

REG_data=I2C_ReadByte();

I2C_NoAck();

I2C_Stop();

return REG_data;

}

5、根據 MPU9250 的 Register Map and Descriptions 宏定義

#define SMPLRT_DIV 0x19 //陀螺儀采樣率,典型值:0x07(125Hz)

#define GYRO_CONFIG 0x1B //陀螺儀自檢及測量範圍,典型值:0x18(不自檢,2000deg/s)

#define ACCEL_CONFIG 0x1C //加速計自檢、測量範圍及高通濾波頻率,典型值:0x01(不自檢,2G,5Hz)

#define PWR_MGMT_1 0x6B //電源管理,典型值:0x00(正常啟用)

#define WHO_AM_I 0x75 //IIC位址寄存器(預設數值0x68,隻讀)

#define ACCEL_XOUT_H 0x3B

#define ACCEL_XOUT_L 0x3C

#define ACCEL_YOUT_H 0x3D

#define ACCEL_YOUT_L 0x3E

#define ACCEL_ZOUT_H 0x3F

#define ACCEL_ZOUT_L 0x40

#define TEMP_OUT_H 0x41

#define TEMP_OUT_L 0x42

#define GYRO_XOUT_H 0x43

#define GYRO_XOUT_L 0x44

#define GYRO_YOUT_H 0x45

#define GYRO_YOUT_L 0x46

#define GYRO_ZOUT_H 0x47

#define GYRO_ZOUT_L 0x48

#define MAG_XOUT_L 0x03

#define MAG_XOUT_H 0x04

#define MAG_YOUT_L 0x05

#define MAG_YOUT_H 0x06

#define MAG_ZOUT_L 0x07

#define MAG_ZOUT_H 0x08

#define GYRO_ADDRESS 0xD0

#define MAG_ADDRESS 0x18

#define ACCEL_ADDRESS 0xD0

6、MPU9250的相關操作

void Init_MPU9250(void)

{

Single_Write(GYRO_ADDRESS,PWR_MGMT_1,0x00);

Single_Write(GYRO_ADDRESS,SMPLRT_DIV,0x07);

Single_Write(GYRO_ADDRESS,CONFIG,0x06);

Single_Write(GYRO_ADDRESS,GYRO_CONFIG,0x18);

Single_Write(GYRO_ADDRESS,ACCEL_CONFIG,0x01);

}

void READ_MPU9250_ACCEL(void)

{

BUF[0]=Single_Read(ACCEL_ADDRESS,ACCEL_XOUT_L);

BUF[1]=Single_Read(ACCEL_ADDRESS,ACCEL_XOUT_H);

T_X=(BUF[1]<<8)|BUF[0];

T_X/=164;

BUF[2]=Single_Read(ACCEL_ADDRESS,ACCEL_YOUT_L);

BUF[3]=Single_Read(ACCEL_ADDRESS,ACCEL_YOUT_H);

T_Y=(BUF[3]<<8)|BUF[2];

T_Y/=164;

BUF[4]=Single_Read(ACCEL_ADDRESS,ACCEL_ZOUT_L);

BUF[5]=Single_Read(ACCEL_ADDRESS,ACCEL_ZOUT_H);

T_Z=(BUF[5]<<8)|BUF[4];

T_Z/=164;

}

void READ_MPU9250_GYRO(void)

{

BUF[0]=Single_Read(GYRO_ADDRESS,GYRO_XOUT_L);

BUF[1]=Single_Read(GYRO_ADDRESS,GYRO_XOUT_H);

T_X=(BUF[1]<<8)|BUF[0];

T_X/=16.4;

BUF[2]=Single_Read(GYRO_ADDRESS,GYRO_YOUT_L);

BUF[3]=Single_Read(GYRO_ADDRESS,GYRO_YOUT_H);

T_Y=(BUF[3]<<8)|BUF[2];

T_Y/=16.4;

BUF[4]=Single_Read(GYRO_ADDRESS,GYRO_ZOUT_L);

BUF[5]=Single_Read(GYRO_ADDRESS,GYRO_ZOUT_H);

T_Z=(BUF[5]<<8)|BUF[4];

T_Z/=16.4;

BUF[6]=Single_Read(GYRO_ADDRESS,TEMP_OUT_L);

BUF[7]=Single_Read(GYRO_ADDRESS,TEMP_OUT_H);

T_T=(BUF[7]<<8)|BUF[6];

T_T=(T_T-21)/333.87 +21; //順便讀溫度

}

void READ_MPU9250_MAG(void)

{

Single_Write(GYRO_ADDRESS,0x37,0x02); //turn on Bypass Mode

HAL_Delay(20);

Single_Write(MAG_ADDRESS,0x0A,0x01);

HAL_Delay(20);

BUF[0]=Single_Read(MAG_ADDRESS,MAG_XOUT_L);

BUF[1]=Single_Read(MAG_ADDRESS,MAG_XOUT_H);

T_X=(BUF[1]<<8)|BUF[0];

BUF[2]=Single_Read(MAG_ADDRESS,MAG_YOUT_L);

BUF[3]=Single_Read(MAG_ADDRESS,MAG_YOUT_H);

T_Y=(BUF[3]<<8)|BUF[2];

BUF[4]=Single_Read(MAG_ADDRESS,MAG_ZOUT_L);

BUF[5]=Single_Read(MAG_ADDRESS,MAG_ZOUT_H);

T_Z=(BUF[5]<<8)|BUF[4];

}

7、格式化處理資料

void Format(unsigned char *s,short temp_data)

{

if(temp_data<0)

{

temp_data=-temp_data;

*s++='-';

}

else *s=' ';

*s++=temp_data/100+0x30;

temp_data=temp_data%100;

*s++=temp_data/10+0x30;

temp_data=temp_data%10;

*s++=temp_data+0x30;

*s=0;

}

8、Private variables

unsigned char BUF[20]; //接收資料緩存區

unsigned char TX_DATA[8]; //顯示資料緩存區

short T_X, T_Y, T_Z, T_T; //X、Y、Z軸資料,時間

9、在主循環開始前初始化

Init_MPU9250();

10、主循環中的代碼

READ_MPU9250_ACCEL(); //加速度計

Format(TX_DATA,T_X);

usart1_print("AX:%s\t", TX_DATA);

Format(TX_DATA,T_Y);

usart1_print("AY:%s\t", TX_DATA);

Format(TX_DATA,T_Z);

usart1_print("AZ:%s\t", TX_DATA);

usart1_print("\n");

READ_MPU9250_GYRO(); //陀螺儀

Format(TX_DATA,T_X);

usart1_print("GX:%s\t", TX_DATA);

Format(TX_DATA,T_Y);

usart1_print("GY:%s\t", TX_DATA);

Format(TX_DATA,T_Z);

usart1_print("GZ:%s\t", TX_DATA);

usart1_print("\n");

READ_MPU9250_MAG(); //磁力計

Format(TX_DATA,T_X);

usart1_print("MX:%s\t", TX_DATA);

Format(TX_DATA,T_Y);

usart1_print("MY:%s\t", TX_DATA);

Format(TX_DATA,T_Z);

usart1_print("MZ:%s\t", TX_DATA);

usart1_print("\n");

Format(TX_DATA,T_T);

usart1_print("T:%s\t", TX_DATA);

usart1_print("\n");

HAL_Delay(200);