STM32学习——软件I2C读写MPU6050
·
1.软件I2C读写MPU6050
1.基本要点
1.函数
(1)void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);//单独控制某一个 / 多个 GPIO 引脚输出高低电平,只修改指定引脚,不影响同端口其他引脚。
(2)uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读取指定 GPIO 端口的某个特定引脚当前的输入电平(高或低),返回一个 uint8_t 类型的值。
2.注意
(1)先将SDA拉高,再将SCL拉高,为了应对特殊情况下的SCL初始位低电平,SDA初始为低电平,这时如果先拉高SCL,再拉高SDA,此时的时序逻辑为终止条件。会让本来是下一次的的开始变为终止,在指定地址读的时序中,出现错误。
void MyI2C_Start(void)
{
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
MyI2C_W_SDA(0);
MyI2C_W_SCL(0);
}
(2)SCL在完成操作后,都会归于低电平,除了终止条件。所以这里的只需将SDA置位0。
void MyI2C_Stop(void)
{
MyI2C_W_SDA(0);
MyI2C_W_SCL(1);
MyI2C_W_SDA(1);
}
2.代码
1.MyI2C.h/c
#ifndef __MYI2C_H
#define __MYI2C_H
void MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);
#endif
#include "stm32f10x.h" // Device header
#include "Delay.h"
void MyI2C_W_SCL(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);
Delay_us(10);//给与足够的时间置位
}
void MyI2C_W_SDA(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);
Delay_us(10);//给与足够的时间置位
}
uint8_t MyI2C_R_SDA(void)
{
uint8_t BitValue;
BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
Delay_us(10);//给与足够的时间读取
return BitValue;
}
void MyI2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;//开漏输出
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11;//端口选择10,11
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);//GPIO口的配置,初始化
GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);
}
void MyI2C_Start(void)
{
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
MyI2C_W_SDA(0);
MyI2C_W_SCL(0);
}
void MyI2C_Stop(void)
{
MyI2C_W_SDA(0);
MyI2C_W_SCL(1);
MyI2C_W_SDA(1);
}
void MyI2C_SendByte(uint8_t Byte)
{
uint8_t i;
for(i=0;i<8;i++)
{
MyI2C_W_SDA(Byte&(0x80>>i));
MyI2C_W_SCL(1);
MyI2C_W_SCL(0);
}
}
uint8_t MyI2C_ReceiveByte(void)
{
uint8_t i,Byte=0x00;
MyI2C_W_SDA(1);
for(i=0;i<8;i++)
{
MyI2C_W_SCL(1);
if(MyI2C_R_SDA()==1)
{
Byte|=(0x80>>i);
}
MyI2C_W_SCL(0);
}
return Byte;
}
void MyI2C_SendAck(uint8_t AckBit)
{
MyI2C_W_SDA(AckBit);
MyI2C_W_SCL(1);
MyI2C_W_SCL(0);
}
uint8_t MyI2C_ReceiveAck(void)
{
uint8_t AckBit;
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
AckBit=MyI2C_R_SDA();
MyI2C_W_SCL(0);
return AckBit;
}
2.MPU6050.h/c
#ifndef __MPU6050_H
#define __MPU6050_H
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ);
#endif
#include "stm32f10x.h" // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"
#define MPU6050_ADDRESS 0xD0
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{
MyI2C_Start();
MyI2C_SendByte(MPU6050_ADDRESS);
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_SendByte(Data);
MyI2C_ReceiveAck();
MyI2C_Stop();
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
uint8_t Data;
MyI2C_Start();
MyI2C_SendByte(MPU6050_ADDRESS);//写入
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_Start();
MyI2C_SendByte(MPU6050_ADDRESS|0x01);//读取
MyI2C_ReceiveAck();
Data=MyI2C_ReceiveByte();
MyI2C_SendAck(1);
MyI2C_Stop();
return Data;
}
void MPU6050_Init(void)
{
MyI2C_Init();
MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);//电源寄存器1
MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//电源寄存器2
MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);//分频选择
MPU6050_WriteReg(MPU6050_CONFIG,0x06);//配置寄存器
MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);//陀螺仪量程配置
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);//加速度配置寄存器
}
uint8_t MPU6050_GetID(void)
{
return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ)
{
uint8_t DataH,DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
*AccX=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
*AccY=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
*AccZ=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
DataL=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
*GyroX=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
DataL=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
*GyroY=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
DataL=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
*GyroZ=(DataH<<8)|DataL;
}
3.MPU6050_Reg.h
#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H
// 采样率分频
#define MPU6050_SMPLRT_DIV 0x19
// 数字低通滤波/帧同步配置
#define MPU6050_CONFIG 0x1A
// 陀螺仪满量程/自测
#define MPU6050_GYRO_CONFIG 0x1B
// 加速度计满量程/高通滤波
#define MPU6050_ACCEL_CONFIG 0x1C
// 加速度计数据(高/低字节)
#define MPU6050_ACCEL_XOUT_H 0x3B
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
// 温度数据(高/低字节)
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
// 陀螺仪数据(高/低字节)
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48
// 电源管理
#define MPU6050_PWR_MGMT_1 0x6B // 唤醒/复位/时钟源
#define MPU6050_PWR_MGMT_2 0x6C // 各轴待机控制
// 器件ID(只读,通常 0x68)
#define MPU6050_WHO_AM_I 0x75
#endif
4.main.c
#include "stm32f10x.h" // Device header寄存器头文件
#include "Delay.h"
#include "OLED.H"
#include "MPU6050.h"
uint8_t ID;
int16_t AX,AY,AZ,GX,GY,GZ;
int main(void)
{
OLED_Init();
MPU6050_Init();
OLED_ShowString(1,1,"ID:");
ID=MPU6050_GetID();
OLED_ShowHexNum(1,4,ID,2);
while(1)
{
MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);
OLED_ShowSignedNum(2,1,AX,5);
OLED_ShowSignedNum(3,1,AY,5);
OLED_ShowSignedNum(4,1,AZ,5);
OLED_ShowSignedNum(2,8,GX,5);
OLED_ShowSignedNum(3,8,GY,5);
OLED_ShowSignedNum(4,8,GZ,5);
}
}
更多推荐

所有评论(0)