网上少有STM32与MPC-6050通讯的介绍,可以用的代码就更少了。辛苦了几天,终于将其调通,共享出来与大家分享。
什么都不说了,直接上代码,大家看注释就行了:
i2c.h
#ifndef __I2C_H
#define __I2C_H
#include "sys.h"
//IO方向设置
#define SDA_IN() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}
#define SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}
//IO操作函数
#define IIC_SCL PBout(10) //SCL
#define IIC_SDA PBout(11) //SDA
#define READ_SDA PBin(11) //输入SDA
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
#endif
i2c.c
#include "i2c.h"
#include "delay.h"
//初始化IIC
void IIC_Init(void)
{
RCC->APB2ENR|=1<<3;//先使能外设IO PORTB时钟
GPIOB->CRH&=0XFFFF00FF;//PB10/11 推挽输出
GPIOB->CRH|=0X00003300;
GPIOB->ODR|=3<<10; //PB10/11 输出高
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(5);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(5);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(5);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(5);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(5);
IIC_SCL=1;delay_us(5);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(5);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(5);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(5); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
delay_us(5);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(5);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(5);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
mpc6050.h
#ifndef __MPU6050_H
#define __MPU6050_H
#include "sys.h"
//****************************************
// 定义MPU6050内部地址
//****************************************
#define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)
#define SlaveAddress 0xD0 //IIC写入时的地址字节数据,+1为读取
#define MPU_60X0_PWR_MGMT_1_REG_ADDR 0x6B
#define MPU_60X0_USER_CTRL_REG_ADDR 0x6A
#define MPU_60X0_SMPLRT_DIV_REG_ADDR 0x19
#define MPU_60X0_CONFIG_REG_ADDR 0x1A
#define MPU_60X0_GYRO_CONFIG_REG_ADDR 0x1B
#define MPU_60X0_ACCEL_CONFIG_REG_ADDR 0x1C
#define MPU_60X0_FIFO_EN_REG_ADDR 0x23
#define MPU_60X0_RESET_REG_VALU 0x80
#define MPU_60X0_PWR_MGMT_1_REG_VALU 0x09 // Disable temperature sensor, PLL with X axis gyroscope reference
#define MPU_60X0_USER_CTRL_REG_VALU 0x45 // Enable FIFO. Reset FIFO and signal paths for all sensors
#define MPU_60X0_SMPLRT_DIV_REG_VALU 0x00 // DLPF_CFG is 0x01, so Gyroscope Output Rate = 1kHz, divided by 1, still 1kHz
#define MPU_60X0_CONFIG_REG_VALU 0x03 // 184Hz 2.0ms 188Hz 1.9ms 1kHz. So there will be 6x2 bytes new data in FIFO every 1ms
#define MPU_60X0_GYRO_CONFIG_REG_VALU 0x08 // Gyroscope works at 500dps. If selftest is needed, REMEMBER to put this to 250dps
#define MPU_60X0_ACCEL_CONFIG_REG_VALU 0x08 // Accelerometer works at 4g range. If selftest is needed, REMEMBER to put this to 8g range
#define MPU_60X0_FIFO_EN_REG_VALU 0x78 // Only enable accel and gyro
extern u16 delayTime;
void Single_WriteI2C(u8 REG_Address,u8 REG_data);
u8 Single_ReadI2C(u8 REG_Address);
void InitMPU6050(void);
u16 GetData(u8 REG_Address);
void I2C1_WriteByte(u8 REG_Address,u8 REG_data);
u8 I2C1_ReadByte(u8 DataAddr);
void SetDelayTime(u16 delayMs);
#endif
mpc6050.c
#include "delay.h"
#include "mpu6050.h"
#include "i2c.h"
u16 delayTime = 1000;
//**************************************
//向I2C设备写入一个字节数据
//**************************************
void Single_WriteI2C(u8 REG_Address,u8 REG_data)
{
IIC_Start(); //起始信号
IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号
IIC_Wait_Ack();
IIC_Send_Byte(REG_Address); //内部寄存器地址,
IIC_Wait_Ack();
IIC_Send_Byte(REG_data); //内部寄存器数据,
IIC_Wait_Ack();
IIC_Stop(); //发送停止信号
}
//**************************************
//从I2C设备读取一个字节数据
//**************************************
u8 Single_ReadI2C(u8 REG_Address)
{
u8 REG_data;
IIC_Start(); //起始信号
IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号
IIC_Wait_Ack();
IIC_Send_Byte(REG_Address); //发送存储单元地址,从0开始
IIC_Wait_Ack();
IIC_Start(); //起始信号
IIC_Send_Byte(SlaveAddress+1); //发送设备地址+读信号
IIC_Wait_Ack();
REG_data=IIC_Read_Byte(0); //读出寄存器数据
//IIC_SendAck(); //接收应答信号
IIC_Stop(); //停止信号
return REG_data;
}
//**************************************
//初始化MPU6050
//**************************************
void InitMPU6050()
{
/*
Single_WriteI2C(PWR_MGMT_1, 0x00); //解除休眠状态
Single_WriteI2C(SMPLRT_DIV, 0x07);
Single_WriteI2C(CONFIG, 0x06);
Single_WriteI2C(GYRO_CONFIG, 0x18);
Single_WriteI2C(ACCEL_CONFIG, 0x01);
*/
u32 i;
Single_WriteI2C(MPU_60X0_PWR_MGMT_1_REG_ADDR, MPU_60X0_RESET_REG_VALU);
for (i = 0; i < 20000; i++)
{
delay_us(5); //上电延时
}
Single_WriteI2C(MPU_60X0_PWR_MGMT_1_REG_ADDR, MPU_60X0_PWR_MGMT_1_REG_VALU);
Single_WriteI2C(MPU_60X0_USER_CTRL_REG_ADDR, MPU_60X0_USER_CTRL_REG_VALU);
Single_WriteI2C(MPU_60X0_SMPLRT_DIV_REG_ADDR, MPU_60X0_SMPLRT_DIV_REG_VALU);
Single_WriteI2C(MPU_60X0_CONFIG_REG_ADDR, MPU_60X0_CONFIG_REG_VALU);
Single_WriteI2C(MPU_60X0_GYRO_CONFIG_REG_ADDR, MPU_60X0_GYRO_CONFIG_REG_VALU);
Single_WriteI2C(MPU_60X0_ACCEL_CONFIG_REG_ADDR, MPU_60X0_ACCEL_CONFIG_REG_VALU);
Single_WriteI2C(MPU_60X0_FIFO_EN_REG_ADDR, MPU_60X0_FIFO_EN_REG_VALU);
}
//**************************************
//合成数据
//**************************************
u16 GetData(u8 REG_Address)
{
u8 H,L;
H=Single_ReadI2C(REG_Address);
L=Single_ReadI2C(REG_Address+1);
return (H<<8)+L; //合成数据
}
void SetDelayTime(u16 delayMs)
{
delayTime = delayMs;
}
本文分享了一种STM32与MPC-6050通过I2C通讯的方法,提供了详细的代码实现。包括I2C的初始化、起始与停止信号的产生、数据的发送与接收等关键步骤。
1236

被折叠的 条评论
为什么被折叠?



