17_I2C通信外设
I2C通信外设
I2C外设简介
固定多主机:固定多个主机和多个从机
可变多主机:没用固定的主机和从机,任何从机都可以变成主机,通信完成后变回从机
10位地址模式:使用第一二个字节当地址,第一个字节是11110开头就是10位地址模式(除了11110之后的2位+第二个字节的8位)
I2C框图
I2C基本结构
复用开漏/推挽输出
主机发送
主机->数据寄存器->移位寄存器->从机
主机接收
当前地址接收
指定地址接收
主机发送+当前地址接收
软件/硬件波形对比
上软件,下硬件
硬件I2C读写MPU6050
代码
MPU6050.c
#include "stm32f10x.h" // Device header
#include "MPU6050_Reg.h"
#include "MPU6050.h"
#define MPU6050_ADDRESS 0xD0 //AD0接高电平地址为:0xD2
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
uint32_t Timeout;
while(I2C_CheckEvent(I2Cx,I2C_EVENT)!=SUCCESS)
{
Timeout--;
if(Timeout==0)
{
break;
}
}
}
void MPU6050_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_OD; //复用开漏模式
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
I2C_InitTypeDef I2C_InitStruct;
I2C_InitStruct.I2C_Ack=I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_ClockSpeed=200000;
I2C_InitStruct.I2C_DutyCycle=I2C_DutyCycle_2;
I2C_InitStruct.I2C_Mode=I2C_Mode_I2C;
I2C_InitStruct.I2C_OwnAddress1=0x00;
I2C_Init(I2C2,&I2C_InitStruct);
I2C_Cmd(I2C2,ENABLE);
MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01); //解除睡眠模式,使用x轴陀螺仪时钟
MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00); //六个轴均不待机
MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09); //采样率分频:10分频
MPU6050_WriteReg(MPU6050_CONFIG,0x06); //配置寄存器
MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18); //陀螺仪配置寄存器
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18); //加速度计配置寄存器
}
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{
//硬件实现不需要接收应答
I2C_GenerateSTART(I2C2,ENABLE); //START
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5
I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter); //发送从机地址
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //发送EV6
I2C_SendData(I2C2,RegAddress); //发送寄存器地址
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING); //EV8
I2C_SendData(I2C2,Data); //发送数据
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2
I2C_GenerateSTOP(I2C2,ENABLE); //STOP
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress) //读一个字节
{
uint8_t Data;
I2C_GenerateSTART(I2C2,ENABLE); //START
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5
I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter); //发送从机地址
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //发送EV6
I2C_SendData(I2C2,RegAddress); //发送寄存器地址
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2
I2C_GenerateSTART(I2C2,ENABLE); //START
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5
I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver); //接收从机地址
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //接收EV6
I2C_AcknowledgeConfig(I2C2,DISABLE); //设置ACK=0,清除应答
I2C_GenerateSTOP(I2C2,ENABLE); //STOP
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED); //EV7
Data=I2C_ReceiveData(I2C2); //接收数据
I2C_AcknowledgeConfig(I2C2,ENABLE); //恢复应答
return Data;
}
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); //加速度X轴寄存器高八位
DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L); //加速度X轴寄存器低八位
*AccX=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H); //加速度Y轴寄存器高八位
DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L); //加速度Y轴寄存器低八位
*AccY=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H); //加速度Z轴寄存器高八位
DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L); //加速度Z轴寄存器低八位
*AccZ=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //陀螺仪X轴寄存器高八位
DataL=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //陀螺仪X轴寄存器低八位
*GyroX=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //陀螺仪Y轴寄存器高八位
DataL=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //陀螺仪Y轴寄存器低八位
*GyroY=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //陀螺仪Z轴寄存器高八位
DataL=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //陀螺仪Z轴寄存器低八位
*GyroZ=(DataH<<8)|DataL;
}
MPU6050.h
#ifndef __MPU6050_H__
#define __MPU6050_H__
void MPU6050_Init(void);
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
void MPU6050_WriteMulReg(uint8_t RegAddress,uint8_t *Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_ReadMulReg(uint8_t RegAddress, uint8_t* result);
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ);
#endif
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"
int16_t AX,AY,AZ,GX,GY,GZ;
int main(void)
{
OLED_Init();
MPU6050_Init();
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);
}
}