00. 目录
文章目录
- 00. 目录
- 01. I2C简介
- 02. MPU6050参数
- 03. 软件I2C接线图
- 04. I2C模拟应答时序示例
- 05. I2C读取MPU6050程序示例
- 06. 程序下载
- 07. 附录
01. I2C简介
I2C(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。
串行的 8 位双向数据传输位速率在标准模式下可达 100kbit/s,快速模式下可达 400kbit/s,高速模式下可达 3.4Mbit/s。
I2C是一个多主机的总线,每个设备既可以当主控器或被控器,又可作为发送器或接收器,一条总线上可以有多个主机,但同一时刻只允许一个主机工作。
02. MPU6050参数
- 16位ADC采集传感器的模拟信号,量化范围:-32768~32767
- 加速度计满量程选择:±2、±4、±8、±16(g)
- 陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)
- 可配置的数字低通滤波器
- 可配置的时钟源
- 可配置的采样分频
- I2C从机地址:1101000(AD0=0) 1101001(AD0=1)
03. 软件I2C接线图
04. I2C模拟应答时序示例
i2c.h
#ifndef __I2C_H__
#define __I2C_H__
#include "stm32f10x.h"
#include "i2c.h"
#include "delay.h"
void i2c_W_SCL(uint8_t value);
void i2c_W_SDA(uint8_t value);
uint8_t i2c_R_SDA(void);
//I2C初始化
void i2c_init(void);
//起始条件
void i2c_start(void);
//结束条件
void i2c_stop(void);
//发送一个字节
void i2c_send_byte(uint8_t value);
//接收一个字节
uint8_t i2c_recv_byte(void);
//发送ACK
void i2c_send_ACK(uint8_t ack);
//接收一个字节
uint8_t i2c_recv_ACK(void);
#endif /*__I2C_H__*/
i2c.c
#include "i2c.h"
#include "delay.h"
void i2c_W_SCL(uint8_t value)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)value);
delay_us(10);
}
void i2c_W_SDA(uint8_t value)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)value);
delay_us(10);
}
uint8_t i2c_R_SDA(void)
{
uint8_t value;
value = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
delay_us(10);
return value;
}
//I2C初始化
void i2c_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//SCL B10 SDA B11
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
//初始状态为高电平
GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}
//起始条件
void i2c_start(void)
{
i2c_W_SDA(1);
i2c_W_SCL(1);
i2c_W_SDA(0);
i2c_W_SCL(0);
}
//结束条件
void i2c_stop(void)
{
i2c_W_SDA(0);
i2c_W_SCL(1);
i2c_W_SDA(1);
}
//发送一个字节
void i2c_send_byte(uint8_t value)
{
uint8_t i = 0;
for (i = 0; i < 8; i++)
{
i2c_W_SDA(value & (0x80 >> i));
i2c_W_SCL(1);
//delay_us(5);
i2c_W_SCL(0);
}
}
//接收一个字节
uint8_t i2c_recv_byte(void)
{
uint8_t i = 0;
uint8_t value = 0;
//主设备释放SDL
i2c_W_SDA(1);
for (i = 0; i < 8; i++)
{
i2c_W_SCL(1);
if (i2c_R_SDA() == 1)
{
value = value | 0x80 >> i;
}
i2c_W_SCL(0);
}
return value;
}
//发送ACK
void i2c_send_ACK(uint8_t ack)
{
i2c_W_SDA(ack);
i2c_W_SCL(1);
//delay_us(5);
i2c_W_SCL(0);
}
//接收一个字节
uint8_t i2c_recv_ACK(void)
{
uint8_t value = 0;
//主设备释放SDL
i2c_W_SDA(1);
i2c_W_SCL(1);
value = i2c_R_SDA();
i2c_W_SCL(0);
return value;
}
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "i2c.h"
int main(void)
{
uint8_t ack;
//初始化
OLED_Init();
i2c_init();
i2c_start();
i2c_send_byte(0xD0);
ack = i2c_recv_ACK();
i2c_stop();
OLED_ShowNum(1, 1, ack, 2);
while(1)
{
}
return 0;
}
05. I2C读取MPU6050程序示例
i2c.h
#ifndef __I2C_H__
#define __I2C_H__
#include "stm32f10x.h"
#include "i2c.h"
#include "delay.h"
void i2c_W_SCL(uint8_t value);
void i2c_W_SDA(uint8_t value);
uint8_t i2c_R_SDA(void);
//I2C初始化
void i2c_init(void);
//起始条件
void i2c_start(void);
//结束条件
void i2c_stop(void);
//发送一个字节
void i2c_send_byte(uint8_t value);
//接收一个字节
uint8_t i2c_recv_byte(void);
//发送ACK
void i2c_send_ACK(uint8_t ack);
//接收一个字节
uint8_t i2c_recv_ACK(void);
#endif /*__I2C_H__*/
i2c.c
#include "i2c.h"
#include "delay.h"
void i2c_W_SCL(uint8_t value)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)value);
delay_us(10);
}
void i2c_W_SDA(uint8_t value)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)value);
delay_us(10);
}
uint8_t i2c_R_SDA(void)
{
uint8_t value;
value = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
delay_us(10);
return value;
}
//I2C初始化
void i2c_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//SCL B10 SDA B11
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
//初始状态为高电平
GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}
//起始条件
void i2c_start(void)
{
i2c_W_SDA(1);
i2c_W_SCL(1);
i2c_W_SDA(0);
i2c_W_SCL(0);
}
//结束条件
void i2c_stop(void)
{
i2c_W_SDA(0);
i2c_W_SCL(1);
i2c_W_SDA(1);
}
//发送一个字节
void i2c_send_byte(uint8_t value)
{
uint8_t i = 0;
for (i = 0; i < 8; i++)
{
i2c_W_SDA(value & (0x80 >> i));
i2c_W_SCL(1);
//delay_us(5);
i2c_W_SCL(0);
}
}
//接收一个字节
uint8_t i2c_recv_byte(void)
{
uint8_t i = 0;
uint8_t value = 0;
//主设备释放SDL
i2c_W_SDA(1);
for (i = 0; i < 8; i++)
{
i2c_W_SCL(1);
if (i2c_R_SDA() == 1)
{
value = value | 0x80 >> i;
}
i2c_W_SCL(0);
}
return value;
}
//发送ACK
void i2c_send_ACK(uint8_t ack)
{
i2c_W_SDA(ack);
i2c_W_SCL(1);
//delay_us(5);
i2c_W_SCL(0);
}
//接收一个字节
uint8_t i2c_recv_ACK(void)
{
uint8_t value = 0;
//主设备释放SDL
i2c_W_SDA(1);
i2c_W_SCL(1);
value = i2c_R_SDA();
i2c_W_SCL(0);
return value;
}
MPU6050.h
#ifndef __MPU6050_H__
#define __MPU6050_H__
#include "mpu6050.h"
#include "i2c.h"
#define MPU6050_ADDRESS 0xD0
#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
#define MPU6050_WHO_AM_I 0x75
void MPU6050_WriteReg(uint8_t regAddr, uint8_t data);
uint8_t MPU6050_ReadReg(uint8_t regAddr);
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 /*__MPU6050_H__*/
MPU6050.c
#include "mpu6050.h"
#include "i2c.h"
void MPU6050_WriteReg(uint8_t regAddr, uint8_t data)
{
i2c_start();
i2c_send_byte(MPU6050_ADDRESS);
i2c_recv_ACK();
i2c_send_byte(regAddr);
i2c_recv_ACK();
i2c_send_byte(data);
i2c_recv_ACK();
i2c_stop();
}
uint8_t MPU6050_ReadReg(uint8_t regAddr)
{
uint8_t data = 0;
i2c_start();
i2c_send_byte(MPU6050_ADDRESS);
i2c_recv_ACK();
i2c_send_byte(regAddr);
i2c_recv_ACK();
i2c_start();
i2c_send_byte(MPU6050_ADDRESS | 0x1);
i2c_recv_ACK();
data = i2c_recv_byte();
i2c_send_ACK(1);
i2c_stop();
return data;
}
void MPU6050_init(void)
{
i2c_init();
MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
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);
}
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_L);
*GyroX = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
*GyroY = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
*GyroZ = (DataH << 8) | DataL;
}
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "mpu6050.h"
int main(void)
{
uint8_t data = 0;
int16_t AX, AY, AZ, GX, GY, GZ;
//初始化
OLED_Init();
MPU6050_init();
data = MPU6050_getId();
OLED_ShowString(1, 1, "ID: ");
OLED_ShowHexNum(1, 5, data, 3);
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);
delay_ms(100);
}
return 0;
}
06. 程序下载
27-软件I2C时序模拟.rar
28-软件I2C.rar
07. 附录
参考: 【STM32】江科大STM32学习笔记汇总