打印
[STM32F1]

STM32F103C8T6 软件IIC读取MPU6050

[复制链接]
127|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
g36xcv|  楼主 | 2024-1-31 14:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
软件IIC的引脚配置及六块时序单元

通过函数来间接设置SCL和SDA总线,方便加延时


//写 scl总线

void myiic_w_scl(uint8_t bitvalue)

{

        //Delay_us();

        GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)bitvalue);

        Delay_us(10); //方便修改延时

}

//写 sda总线

void myiic_w_sda(uint8_t bitvalue)

{

        GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)bitvalue);

        Delay_us(10); //方便修改延时

}

//读 sda总线

uint8_t myiic_r_sda(void)

{

        uint8_t bitvalue;

        bitvalue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);

        Delay_us(10); //方便修改延时

        return bitvalue;

}


使用特权

评论回复
沙发
g36xcv|  楼主 | 2024-1-31 14:05 | 只看该作者
引脚配置
void myiic_init(void)
{
        //开时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
       
        //配置GPIO SCL,SDA初始化为开漏输出,
        // 开漏模式既可以输出,又可以输入。 输入时,先输出1,再直接读取输入寄存器
        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_10MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
        //SCL和SDA置为高电平, 释放总线, 此时IIC总线处于空闲状态
        GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

使用特权

评论回复
板凳
g36xcv|  楼主 | 2024-1-31 14:06 | 只看该作者
起始信号

//起始信号需要注意:先拉高sda,再拉高scl, 防止和停止信号冲突
void myiic_start(void)
{
        myiic_w_sda(1);
        myiic_w_scl(1);
        myiic_w_sda(0);
        myiic_w_scl(0);        //结束再将时钟线拉低,方便下次使用
}

使用特权

评论回复
地板
g36xcv|  楼主 | 2024-1-31 14:06 | 只看该作者
停止信号
//停止信号:先拉低数据线,原理同上
void myiic_stop(void)
{
        myiic_w_sda(0);
        myiic_w_scl(1);
        myiic_w_sda(1);
}

使用特权

评论回复
5
g36xcv|  楼主 | 2024-1-31 14:06 | 只看该作者
发送一个字节
void myiic_sendbyte(uint8_t byte)
{
        uint8_t i;
        for(i = 0; i < 8; i++)
        {
        //设置最高位数据
                myiic_w_sda(byte & (0x80 >> i));
        //释放SCL        (释放SCL之后,从机就会立刻将SDA的数据读走)
                myiic_w_scl(1);       
        //拉低SCL        驱动时钟走一个脉冲(可以继续放下一位数据)
                myiic_w_scl(0);
        }
}

使用特权

评论回复
6
g36xcv|  楼主 | 2024-1-31 14:06 | 只看该作者
接收一个字节
//接收一个字节:SCL低电平,从机需要将数据放到SDA上,为了防止主机干扰从机写入数据,主机需要先释放SDA(切换为输入模式)
uint8_t myiic_ReceiveByte(void)
{
        uint8_t i, byte = 0x00;

        //主机释放SDA 从机使用,将数据放在SDA上
        myiic_w_sda(1);       
       
        for(i = 0; i < 8; i++)
        {
        //主机释放SCL 读取数据
                myiic_w_scl(1);       
        //如果是 1 置1,如果是 0 ,不用管,因为 byte初始化为 0x00;
                if(myiic_r_sda() == 1)       
                {
                        byte |= 0x80 >> i;
                }
        //读取一位数据后,拉低SCL,从机放下一位数据
                myiic_w_scl(0);
        }
        return byte;
}

使用特权

评论回复
7
g36xcv|  楼主 | 2024-1-31 14:07 | 只看该作者
发送应答
void myiic_SendAck(uint8_t ackBit)
{
        //函数进来时SCL低电平,主机将数据放在SDA上
        myiic_w_sda(ackBit);
        //SCL高电平,从机读取应答
        myiic_w_scl(1);
        //SCL低电平,进入下一个时序单元
        myiic_w_scl(0);
}

使用特权

评论回复
8
g36xcv|  楼主 | 2024-1-31 14:07 | 只看该作者
接收应答
uint8_t myiic_ReceiveAck(void)
{
        uint8_t ackBit;
        //函数进入时SCL低电平,主机释放SDA,防止从机干扰,同时从机将应答位放在SDA上
        myiic_w_sda(1);
        //SCL高电平,主机读取应答位
        myiic_w_scl(1);       
        ackBit = myiic_r_sda();
        //SCL低电平,进入下一个时序单元
        myiic_w_scl(0);
       
        return ackBit;
}

使用特权

评论回复
9
g36xcv|  楼主 | 2024-1-31 14:07 | 只看该作者
读写MPU6050
MPU6050命令的宏定义
//0xD0: 1101 0000(1101 000 是MPU6050的从机地址, 最后一位读写位,0 代表写入操作)
#define MPU6050_ADDRESS 0xD0 //写地址 读地址,需要或上 0x01

#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

使用特权

评论回复
10
g36xcv|  楼主 | 2024-1-31 14:07 | 只看该作者
MPU6050初始化

void MPU6050_Init(void)
{
        myiic_init();
       
        //对MPU6050硬件电路进行初始化配置
        //芯片的写寄存器功能,需要解除芯片的睡眠模式,否则写入是无效的
        //睡眠模式 是电源管理寄存器1 的SLEEP控制的,写入0x00,解除睡眠模式,该寄存器地址为 0x6B;
    //解除睡眠,选择陀螺仪时钟
        MPU6050_Write_Reg(MPU6050_PWR_MGMT_1, 0x01);
    //6 轴均不待机
        MPU6050_Write_Reg(MPU6050_PWR_MGMT_2, 0x00);
    //采样分频为 10       
        MPU6050_Write_Reg(MPU6050_SMPLRT_DIV, 0x09);
    //滤波参数给最大       
        MPU6050_Write_Reg(MPU6050_CONFIG, 0x06);
    //陀螺仪和下面加速度计都选择最大量程               
        MPU6050_Write_Reg(MPU6050_GYRO_CONFIG, 0x18);       
        MPU6050_Write_Reg(MPU6050_ACCEL_CONFIG, 0x18);
}

使用特权

评论回复
11
g36xcv|  楼主 | 2024-1-31 14:08 | 只看该作者
MPU6050指定地址写一个字节
void MPU6050_Write_Reg(uint8_t regAddress, uint8_t data)
{
        myiic_start();
        myiic_sendbyte(MPU6050_ADDRESS);
        myiic_ReceiveAck();

        myiic_sendbyte(regAddress);
        myiic_ReceiveAck();

        myiic_sendbyte(data);
        myiic_ReceiveAck();

        myiic_stop();
}

使用特权

评论回复
12
g36xcv|  楼主 | 2024-1-31 14:08 | 只看该作者
MPU6050指定地址读一个字节
uint8_t MPU6050_Read_Reg(uint8_t regAddress)
{
        uint8_t data;
        myiic_start();
        myiic_sendbyte(MPU6050_ADDRESS);
        myiic_ReceiveAck();

        myiic_sendbyte(regAddress);
        myiic_ReceiveAck();

        myiic_start();
        myiic_sendbyte(MPU6050_ADDRESS | 0x01);
        myiic_ReceiveAck();
        data = myiic_ReceiveByte();
        myiic_SendAck(1);
        myiic_stop();

        return data;
}

使用特权

评论回复
13
g36xcv|  楼主 | 2024-1-31 14:08 | 只看该作者
获取ID号
uint8_t MPU6050_GetID(void)
{
        return MPU6050_Read_Reg(MPU6050_WHO_AM_I);
}

使用特权

评论回复
14
g36xcv|  楼主 | 2024-1-31 14:08 | 只看该作者
获取加速度、陀螺仪

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_Read_Reg(MPU6050_ACCEL_XOUT_H);
        dataL = MPU6050_Read_Reg(MPU6050_ACCEL_XOUT_L);
        *accX = (dataH << 8) | dataL;
       
        dataH = MPU6050_Read_Reg(MPU6050_ACCEL_YOUT_H);
        dataL = MPU6050_Read_Reg(MPU6050_ACCEL_YOUT_L);
        *accY = (dataH << 8) | dataL;
       
        dataH = MPU6050_Read_Reg(MPU6050_ACCEL_ZOUT_H);
        dataL = MPU6050_Read_Reg(MPU6050_ACCEL_ZOUT_L);
        *accZ = (dataH << 8) | dataL;
       
        dataH = MPU6050_Read_Reg(MPU6050_GYRO_XOUT_H);
        dataL = MPU6050_Read_Reg(MPU6050_GYRO_XOUT_L);
        *gyroX = (dataH << 8) | dataL;
       
        dataH = MPU6050_Read_Reg(MPU6050_GYRO_YOUT_H);
        dataL = MPU6050_Read_Reg(MPU6050_GYRO_YOUT_L);
        *gyroY = (dataH << 8) | dataL;

        dataH = MPU6050_Read_Reg(MPU6050_GYRO_ZOUT_H);
        dataL = MPU6050_Read_Reg(MPU6050_GYRO_ZOUT_L);
        *gyroZ = (dataH << 8) | dataL;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

194

帖子

0

粉丝