前面讲了IIC协议的介绍和IIC协议的编程实现,接下来我们来做一个关于IIC的小项目。
一、项目的实现功能:
1、使用STM32单片机用IIC协议对AT24C02进行数据写入。
2、使用STM32单片机用IIC协议对MPU6050、AT24C02进行数据的循环读取。
我们将分三章对本项目进行详细阐述。本章是第二章主要是实现功能:
1、使用STM32单片机用IIC协议对MPU6050进行数据读取。
二、本章使用模块简介:
1、MPU6050模块简介
本章实验使用的是正点原子家的ATK-MPU6050六轴传感器模块。实物图片如下:
原理图如下:
从图 2.1.2 可以看出, 模块自带了 3.3V 超低压差稳压芯片,给 MPU6050 供电,因此外
部供电可以选择: 3.3V / 5V 都可以。 模块通过 P1 排针与外部连接,引出了 VCC、 GND、
IIC_SDA、 IIC_SCL、 MPU_INT 和 MPU_AD0 等信号,其中, IIC_SDA 和 IIC_SCL 带了 4.7K
上拉电阻,外部可以不用再加上拉电阻了,另外 MPU_AD0 自带了 10K 下拉电阻,当 AD0
悬空时,默认 IIC 地址为(0X68)。
ATK-MPU6050 六轴传感器模块通过一个 1*6 的排针(P1)同外部电路连接,各引脚的
详细描述如表 2.1.1 所示:
模块仅通过一个 IIC 接口与外部通信,并可以通过 MPU_AD0 设置模块的 IIC 地址,当 MPU_AD0 悬空/接 GND 的时候,模块的 IIC 从机地址为:0X68;当 MPU_AD0 接 VCC的时候,模块的 IIC 从机地址为:0X69。
2、MPU6050重要寄存器简介
MPU6050 内部总共有好几十个寄存器, 这里,我们仅介绍 MPU6050 使用时的几个重要寄存器,其他的请大家参考: MPU-6000 and MPU-6050 Register Map and Descriptions.pdf这个文档。
我们使用的寄存器有:
设置参数使用的寄存器:
(1)电源管理寄存器1、(2)陀螺仪配置寄存器、(3)加速度传感器配置寄存器、(4)FIFO 使能寄存器、(5)陀螺仪采样率分频寄存器、(6)配置寄存器、(7)电源管理寄存器2
读取数据使用的寄存器:(8)温度输出寄存器、(9)陀螺仪输出寄存器、(10)加速度输出寄存器。
(1)电源管理寄存器1
(2)陀螺仪配置寄存器
(3)加速度传感器配置寄存器
(4)FIFO 使能寄存器
(5)陀螺仪采样率分频寄存器
(6)配置寄存器
(7)电源管理寄存器2
(8)温度输出寄存器
(9)陀螺仪输出寄存器
(10)加速度输出寄存器
三、编程实现
编程主要实现的是5个部分,如下:
序列 | ||
---|---|---|
1 | MPU6050 IIC接口驱动 | |
2 | MPU_Init函数 | |
3 | 读取数据 | |
3.1 | MPU_Get_Gyroscope函数 | |
3.2 | MPU_Get_Accelerometer函数 | |
3.3 | MPU_Get_Temperature函数 |
1、MPU6050 IIC接口驱动
这个部分可参照之前几章IIC协议编程实现和IIC协议实战项目(一)
2、MPU6050的初始化
(1)MPU6050的初始化过程:
(2)在各步骤使用的寄存器
寄存器种类 | 功能 | 地址 | 对应的步骤 |
---|---|---|---|
电源管理寄存器1 | 复位MPU6050 | 0X6B | 2 |
陀螺仪配置寄存器 | 设置角速度传感器的满量程范围 | 0X1B | 3 |
加速度传感器配置寄存器 | 设置加速度传感器的满量程范围 | 0X1C | 3 |
中断使能寄存器 | 配置中断 | 0X38 | 4 |
用户控制寄存器 | 设置AUX IIC接口 | 0X6A | 4 |
FIFO使能寄存器 | 设置FIFO | 0X23 | 4 |
采样率分频寄存器 | 陀螺仪采样率 | 0X19 | 4 |
配置寄存器 | 设置数字低通滤波器 | 0X1A | 4 |
电源管理寄存器1 | 设置系统时钟 | 0X6B | 5 |
电源管理寄存器2 | 使能角速度传感器(陀螺仪)和加速度传感器 | 0X6C | 6 |
(3)程序与流程对应
(4)对各个寄存器进行写入(以设置陀螺传感器满量量程为例)
实现原理还是和前两张IIC原理类似,如下图:
//IIC写一个字节
//reg:寄存器地址
//data:数据
//返回值:0,正常
// 其他,错误代码
u8 MPU_Write_Byte(u8 reg,u8 data)
{
MPU_IIC_Start();
MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令
if(MPU_IIC_Wait_Ack()) //等待应答
{
MPU_IIC_Stop();
return 1;
}
MPU_IIC_Send_Byte(reg); //写寄存器地址
MPU_IIC_Wait_Ack(); //等待应答
MPU_IIC_Send_Byte(data);//发送数据
if(MPU_IIC_Wait_Ack()) //等待ACK
{
MPU_IIC_Stop();
return 1;
}
MPU_IIC_Stop();
return 0;
}
//IIC连续写
//addr:器件地址
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
// 其他,错误代码
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
u8 i;
MPU_IIC_Start();
MPU_IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令
if(MPU_IIC_Wait_Ack()) //等待应答
{
MPU_IIC_Stop();
return 1;
}
MPU_IIC_Send_Byte(reg); //写寄存器地址
MPU_IIC_Wait_Ack(); //等待应答
for(i=0;i<len;i++)
{
MPU_IIC_Send_Byte(buf[i]); //发送数据
if(MPU_IIC_Wait_Ack()) //等待ACK
{
MPU_IIC_Stop();
return 1;
}
}
MPU_IIC_Stop();
return 0;
}
3、读取数据
温度值、陀螺仪值(原始值)、加速度值(原始值)都被分别被存储在对应的寄存器中。分别是温度输出寄存器、陀螺仪输出寄存器、加速度输出寄存器。
(1)IIC读一个字节
//IIC读一个字节
//reg:寄存器地址
//返回值:读到的数据
u8 MPU_Read_Byte(u8 reg)
{
u8 res;
MPU_IIC_Start();
MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令
MPU_IIC_Wait_Ack(); //等待应答
MPU_IIC_Send_Byte(reg); //写寄存器地址
MPU_IIC_Wait_Ack(); //等待应答
MPU_IIC_Start();
MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);//发送器件地址+读命令
MPU_IIC_Wait_Ack(); //等待应答
res=MPU_IIC_Read_Byte(0);//读取数据,发送nACK
MPU_IIC_Stop(); //产生一个停止条件
return res;
}
(2)IIC连续读函数
因为温度值、陀螺仪值(原始值)、加速度值(原始值)都是十六位数据(分程两个相邻的8位寄存器存储)故读取数据使用的函数返回值为16位数据。
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
// 其他,错误代码
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
MPU_IIC_Start();
MPU_IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令
if(MPU_IIC_Wait_Ack()) //等待应答
{
MPU_IIC_Stop();
return 1;
}
MPU_IIC_Send_Byte(reg); //写寄存器地址
MPU_IIC_Wait_Ack(); //等待应答
MPU_IIC_Start();
MPU_IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令
MPU_IIC_Wait_Ack(); //等待应答
while(len)
{
if(len==1)*buf=MPU_IIC_Read_Byte(0);//读数据,发送nACK
else *buf=MPU_IIC_Read_Byte(1); //读数据,发送ACK
len--;
buf++;
}
MPU_IIC_Stop(); //产生一个停止条件
return 0;
}
(3)温度输出
温度读取需要将0X41(高8位)和0X42(低8位)寄存器的数据组合。
//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)/*short 16位*/
{
u8 buf[2];
short raw;
float temp;
MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf);
raw=((u16)buf[0]<<8)|buf[1];
temp=36.53+((double)raw)/340;
return temp*100;;
}
(4)陀螺仪输出
陀螺仪输出X/Y/Z三个轴的陀螺仪传感器数据,高字节在前,低字节在后,每个轴的数据也是16位。
//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
// 其他,错误代码
short MPU_Get_Temperature(void)/*short 16位*/
{
u8 buf[2];
short raw;
float temp;
MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf);
raw=((u16)buf[0]<<8)|buf[1];
temp=36.53+((double)raw)/340;
return temp*100;;
}
(5)加速度输出
输出X/Y/Z三个轴的加速度传感器值,高字节在前,低字节在后,每个轴的数据也是16位。
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
// 其他,错误代码
u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
u8 buf[6],res;
res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
if(res==0)
{
*ax=((u16)buf[0]<<8)|buf[1];
*ay=((u16)buf[2]<<8)|buf[3];
*az=((u16)buf[4]<<8)|buf[5];
}
return res;;
}