MPU6050移植dmp库(二)

这集先写MPU6050的底层函数,为后面的移植做铺垫,在江科大的例程上修改

使用stm32f104c8t6的PB10和PB11作为SCL和SDA,首先进行初始化

void MyI2C_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);					//将PB10和PB11引脚初始化为开漏输出
	
	/*设置默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);			//设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
}
#define MPU_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)(x))
#define MPU_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(x))

引脚配置函数如上


  IIC读SDA引脚电平

#define DELAY_TIME 10

/**
  * 函    数:I2C读SDA引脚电平
  * 参    数:无
  * 返 回 值:协议层需要得到的当前SDA的电平,范围0~1
  * 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1
  */
uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);		//读取SDA电平
	Delay_us(DELAY_TIME);												//延时10us,防止时序频率超过要求
	return BitValue;											//返回SDA电平
}

IIC开始

void MyI2C_Start(void)
{
	MPU_W_SDA(1);							//释放SDA,确保SDA为高电平
	MPU_W_SCL(1);							//释放SCL,确保SCL为高电平
	Delay_us(DELAY_TIME);
	MPU_W_SDA(0);							//在SCL高电平期间,拉低SDA,产生起始信号
	Delay_us(DELAY_TIME);
	MPU_W_SCL(0);							//起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
	Delay_us(DELAY_TIME);
}


IIC停止

void MyI2C_Stop(void)
{
	MPU_W_SDA(0);							//拉低SDA,确保SDA为低电平
	Delay_us(DELAY_TIME);
	MPU_W_SCL(1);							//释放SCL,使SCL呈现高电平
	Delay_us(DELAY_TIME);
	MPU_W_SDA(1);							//在SCL高电平期间,释放SDA,产生终止信号
	Delay_us(DELAY_TIME);
}

IIC发送一个字节

void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i ++)				//循环8次,主机依次发送数据的每一位
	{
		MPU_W_SDA(Byte & (0x80 >> i));	//使用掩码的方式取出Byte的指定一位数据并写入到SDA线
		Delay_us(DELAY_TIME);
		MPU_W_SCL(1);						//释放SCL,从机在SCL高电平期间读取SDA
		Delay_us(DELAY_TIME);
		MPU_W_SCL(0);						//拉低SCL,主机开始发送下一位数据
		Delay_us(DELAY_TIME);
	}
}

IIC读一个字节

uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;					//定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
	MPU_W_SDA(1);							//接收前,主机先确保释放SDA,避免干扰从机的数据发送
	Delay_us(DELAY_TIME);
	for (i = 0; i < 8; i ++)				//循环8次,主机依次接收数据的每一位
	{
		MPU_W_SCL(1);						//释放SCL,主机机在SCL高电平期间读取SDA
		Delay_us(DELAY_TIME);
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}	//读取SDA数据,并存储到Byte变量
														//当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
		MPU_W_SCL(0);						//拉低SCL,从机在SCL低电平期间写入SDA
		Delay_us(DELAY_TIME);
	}
	return Byte;							//返回接收到的一个字节数据
}

IIC发送应答

void MyI2C_SendAck(void)
{
	MPU_W_SDA(1);					//主机把应答位数据放到SDA线
	Delay_us(DELAY_TIME);
	MPU_W_SCL(1);							//释放SCL,从机在SCL高电平期间,读取应答位
	Delay_us(DELAY_TIME);
	MPU_W_SCL(0);							//拉低SCL,开始下一个时序模块
	Delay_us(DELAY_TIME);
}

IIC发送非应答

void MyI2C_SendNAck(void)
{
	MPU_W_SDA(0);					//主机把应答位数据放到SDA线
	Delay_us(DELAY_TIME);
	MPU_W_SCL(1);							//释放SCL,从机在SCL高电平期间,读取应答位
	Delay_us(DELAY_TIME);
	MPU_W_SCL(0);							//拉低SCL,开始下一个时序模块
	Delay_us(DELAY_TIME);
}

IIC接收应答

uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;							//定义应答位变量
	MPU_W_SDA(1);							//接收前,主机先确保释放SDA,避免干扰从机的数据发送
	Delay_us(DELAY_TIME);
	MPU_W_SCL(1);							//释放SCL,主机机在SCL高电平期间读取SDA
	Delay_us(DELAY_TIME);
	AckBit = MyI2C_R_SDA();					//将应答位存储到变量里
	MPU_W_SCL(0);							//拉低SCL,开始下一个时序模块
	Delay_us(DELAY_TIME);
	return AckBit;							//返回定义应答位变量
}

IIC连续写

/**
  * 函    数:IIC连续写
  * 参    数:
  *    addr - 设备地址
  *    reg - 寄存器地址
  *    len - 要写入的数据长度
  *    buf - 数据缓冲区
  * 返 回 值:0 - 正常
  *          其他 - 错误代码
  * 功能描述:向指定 I2C 设备的寄存器中连续写入多个字节的数据。
  */
u8 MPU_Write_Len(u8 addr, u8 reg, u8 len, u8 *buf)
{
    u8 i;
    MyI2C_Start(); // 产生开始信号
    MyI2C_SendByte((addr << 1) | 0); // 发送设备地址 + 写命令
    if (MyI2C_ReceiveAck()) // 等待应答
    {
        MyI2C_Stop(); // 产生停止信号
        return 1; // 错误:无应答
    }
    MyI2C_SendByte(reg); // 写入寄存器地址
    MyI2C_ReceiveAck(); // 等待应答

    for (i = 0; i < len; i++)
    {
        MyI2C_SendByte(buf[i]); // 发送数据
        if (MyI2C_ReceiveAck()) // 等待应答
        {
            MyI2C_Stop(); // 产生停止信号
            return 1; // 错误:无应答
        }
    }
    MyI2C_Stop(); // 产生停止信号
    return 0; // 成功
}

IIC连续读


/**
  * 函    数:IIC连续读
  * 参    数:
  *    addr - 设备地址
  *    reg - 要读取的寄存器地址
  *    len - 要读取的数据长度
  *    buf - 存储读取数据的缓冲区
  * 返 回 值:0 - 正常
  *          其他 - 错误代码
  * 功能描述:从指定 I2C 设备的寄存器中连续读取多个字节的数据。
  */
u8 MPU_Read_Len(u8 addr, u8 reg, u8 len, u8 *buf)
{
    MyI2C_Start(); // 产生开始信号
    MyI2C_SendByte((addr << 1) | 0); // 发送设备地址 + 写命令
    if (MyI2C_ReceiveAck()) // 等待应答
    {
        MyI2C_Stop(); // 产生停止信号
        return 1; // 错误:无应答
    }
    MyI2C_SendByte(reg); // 写入寄存器地址
    MyI2C_ReceiveAck(); // 等待应答

    MyI2C_Start(); // 再次产生开始信号
    MyI2C_SendByte((addr << 1) | 1); // 发送设备地址 + 读命令
    MyI2C_ReceiveAck(); // 等待应答

    while (len)
    {
        if (len == 1){
            *buf = MyI2C_ReceiveByte(); // 读取最后一个字节并发送nACK
			MyI2C_SendNAck();}
        else{
            *buf = MyI2C_ReceiveByte(); // 读取字节并发送ACK
			MyI2C_SendAck();}
        len--;
        buf++;
    }
    MyI2C_Stop(); // 产生停止信号
    return 0; // 成功
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值