基于【软件I2C驱动】增加【MPU6050】模块驱动代码
1、完成MPU6050驱动文件导入操作和编写驱动程序基本代码(参考之前文章)
//将【MPU6050】驱动文件放在【Hardware】文件夹中
2、在MPU6050.c中初始化函数MPU6050_Init及读/写寄存器函数
#include "stm32f10x.h" // Device header
#include "MyI2C.h"
#define MPU6050_ADDRESS 0xD0 //宏定义从机地址
//指定地址写寄存器
/*
参数1:8位寄存器地址
参数2:8位数据
*/
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{
//调用Start产生起始条件开始传输
MyI2C_Start();
//第一个字节时序(必须是发送)——字节内容:从机地址(7位)+读写位(1位)
MyI2C_SendByte(MPU6050_ADDRESS); //1101 000 0 (0代表即将进行写入操作)
//【接收应答】
MyI2C_ReceiveAck();
//第二个字节时序——指定具体读写的寄存器地址
MyI2C_SendByte(RegAddress);
//这个字节存放在MPU6050的当前地址指针里
//【接收应答】
MyI2C_ReceiveAck();
//第三个字节时序——指定主机写入指定寄存器地址的内容
MyI2C_SendByte(Data);
//【接收应答】
MyI2C_ReceiveAck();
//调用Stop产生终止条件结束传输
MyI2C_Stop();
}
//指定地址读寄存器
/*
参数:指定主机读取的地址
*/
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
//定义变量存储主机读取的数据
uint8_t Data;
//调用Start产生起始条件开始传输
MyI2C_Start();
//第一个字节时序(必须是发送)——字节内容:从机地址(7位)+读写位(1位)
MyI2C_SendByte(MPU6050_ADDRESS); //1101 000 0 (0代表即将进行写入操作)
//【接收应答】
MyI2C_ReceiveAck();
//第二个字节时序——指定具体读写的寄存器地址
MyI2C_SendByte(RegAddress);
//这个字节存放在MPU6050的当前地址指针里
//【接收应答】
MyI2C_ReceiveAck();
//转入【读取】时序
//调用Start产生【重复起始】(重新指定读写位)
MyI2C_Start();
//第三个字节时序——字节内容:从机地址(7位)+读写位(1位)
MyI2C_SendByte(MPU6050_ADDRESS | 0xD1); //1101 000 1 (1代表即将进行读取操作)
//【接收应答】
MyI2C_ReceiveAck();
//第四个字节时序——从机得到主机赋予的SDA控制权
//从机发送一个字节,主机接收一个字节
Data = MyI2C_ReceiveByte();
//【发送应答】
MyI2C_SendAck(1);
//调用Stop产生终止条件结束传输
MyI2C_Stop();
return Data;
}
void MPU6050_Init(void)
{
//本模块基于【MyI2C】底层函数
MyI2C_Init();
}
3、在MPU6050.h中声明初始化函数初始化函数MPU6050_Init及读/写寄存器函数
void MPU6050_Init(void);
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
4、在主程序main.c中#include "MPU6050.h"
#include "MPU6050.h"
5、在主循环中编写程序主体
#include "MPU6050.h"
int main(void)
{
//MPU6050_Init为上层模块,已调用底层的MyI2C_Init
MPU6050_Init();
OLED_Init();
//读取芯片ID号函数的【WHO_AM_I】寄存器(地址0x75)
uint8_t ID = MPU6050_ReadReg(0x75);
OLED_ShowHexNum(1,1,ID,2);
while(1)
{
}
}
实现功能:上电后初始化I2C和OLED模块,通过软件I2C读取从机指定地址【0x75】(芯片ID号函数的【WHO_AM_I】寄存器),通过OLED显示芯片ID号为【68】
上一个程序验证了【读寄存器】功能正常,现在进行验证【写寄存器】功能
1、解除芯片睡眠模式(否则写入无效)
//在电源管理寄存器1【0x6B】写入【0x00】,解除睡眠模式
MPU6050_WriteReg(0x6B,0x00);
2、在主循环中编写程序主体
int main(void)
{
//MPU6050_Init为上层模块,已调用底层的MyI2C_Init
MPU6050_Init();
OLED_Init();
//在电源管理寄存器1【0x6B】写入【0x00】,解除睡眠模式
MPU6050_WriteReg(0x6B,0x00);
//向【0x19】寄存器写入【0xAA】
MPU6050_WriteReg(0x19,0xAA);
//读取【0x19】寄存器(地址0x19)
uint8_t ID = MPU6050_ReadReg(0x19);
OLED_ShowHexNum(1,1,ID,2);
while(1)
{
}
}
实现功能:上电后初始化I2C和OLED模块,解除睡眠模式以开启写入功能,通过软件I2C在从机指定地址【0x19】写入【0xAA】并通过OLED显示该寄存器值为【0xAA】
完善MPU6050模块初始化程序
1、完成MPU6050寄存器宏定义文件导入操作和编写宏定义寄存器代码(参考之前文章)
//将【MPU6050_Reg.h】宏定义文件放在【Hardware】文件夹中
2、完善MPU6050.c中初始化函数MPU6050_Init和获取数据寄存器函数MPU6050_GetData
void MPU6050_Init(void)
{
//本模块基于【MyI2C】底层函数
MyI2C_Init();
//配置电源管理寄存器1
MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);
//配置电源管理寄存器2
MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);
//采样率分频
MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);
//配置寄存器
MPU6050_WriteReg(MPU6050_CONFIG,0x06);
//陀螺仪配置寄存器
MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);
//加速度计配置寄存器
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);
//配置之后陀螺仪内部开始连续不断地进行数据转换
//输出的数据存放在对应的数据寄存器中
}
//获取数据寄存器
/*返回6个int16_t的数据,分别表示XYZ的【加速度值】和【陀螺仪值】
参数均为int16_t的指针类型,之后在主函数里定义变量【数据高/低8位】
通过指针把主函数变量的地址传递到子函数
子函数中通过传递过来的地址操作主函数的变量
子函数结束后,主函数变量的值就是子函数想要返回的值
程序逻辑:分别读取6个轴数据寄存器的高/低位,拼接成16位数据并通过指针变量返回
*/
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;
//读取高/低8位的值放在DataH/L中
DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
*AccX = (DataH << 8) | DataL;
//高8位左移8位或上低8位=【加速度计X轴的16位数据】
//用指针引用传递进来的地址,把读到的数据通过指针返回回去
//读取高/低8位的值放在DataH/L中
DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
*AccY = (DataH << 8) | DataL;
//高8位左移8位或上低8位=【加速度计Y轴的16位数据】
//用指针引用传递进来的地址,把读到的数据通过指针返回回去
//读取高/低8位的值放在DataH/L中
DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
*AccZ = (DataH << 8) | DataL;
//高8位左移8位或上低8位=【加速度计Z轴的16位数据】
//用指针引用传递进来的地址,把读到的数据通过指针返回回去
//读取高/低8位的值放在DataH/L中
DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
*GyroX = (DataH << 8) | DataL;
//高8位左移8位或上低8位=【陀螺仪X轴的16位数据】
//用指针引用传递进来的地址,把读到的数据通过指针返回回去
//读取高/低8位的值放在DataH/L中
DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
*GyroY = (DataH << 8) | DataL;
//高8位左移8位或上低8位=【陀螺仪Y轴的16位数据】
//用指针引用传递进来的地址,把读到的数据通过指针返回回去
//读取高/低8位的值放在DataH/L中
DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
*GyroZ = (DataH << 8) | DataL;
//高8位左移8位或上低8位=【陀螺仪Z轴的16位数据】
//用指针引用传递进来的地址,把读到的数据通过指针返回回去
}
3、在MPU6050.h中声明初始化函数MPU6050_Init和获取数据寄存器函数MPU6050_GetData
void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ);
4、在主程序main.c中#include "MPU6050.h"
#include "MPU6050.h"
5、在主循环中编写程序主体
//定义变量用于接受XZY轴的加速度值和陀螺仪值
int16_t AX,AY,AZ,GX,GY,GZ;
uint8_t ID;
int main(void)
{
//MPU6050_Init为上层模块,已调用底层的MyI2C_Init
MPU6050_Init();
OLED_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);
}
}
实现功能:上电后初始化I2C和OLED模块,显示芯片ID号,在循环中通过软件I2C不断读取加速度计和陀螺仪数据寄存器,并通过OLED显示对应XYZ轴数值