欢迎光临散文网 会员登陆 & 注册

江科大学习笔记 _12.软件IIC

2023-06-28 19:53 作者:自闭选手的Z23  | 我要投稿

IIC硬件电路


IIC两条线(SCL/SDA)开漏输出        三极管导通时,接地,强下拉;截止时,浮空;

开漏加弱上拉模式

添加上拉电阻,阻值4.7KΩ

 

 

void MyIIC_W_SCL(uint8_t Bitvalue)//控制SCL电平  Bitvalue:0 or 1

{

    GPIO_WriteBit(IIC_Port,IIC_SCL,(BitAction)Bitvalue);

    Delay_us(10);

}

 

void MyIIC_W_SDA(uint8_t Bitvalue)//控制SDA电平  Bitvalue:0 or 1

{

    GPIO_WriteBit(IIC_Port,IIC_SDA,(BitAction)Bitvalue);

    Delay_us(10);

}

 

uint8_t MyIIC_R_SDA(void)//读SDA电平  返回:0 or 1

{

    uint8_t Bitvalue;

    Bitvalue = GPIO_ReadInputDataBit(IIC_Port,IIC_SDA);

    Delay_us(10);

 

    return Bitvalue;

}

 

IIC初始化

//初始化IIC:配置两个GPIO端口,开漏输出

void MyIIC_Init(void)

{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

 

    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出

    GPIO_InitStruct.GPIO_Pin = IIC_SCL|IIC_SDA;

    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(IIC_Port,&GPIO_InitStruct);

 

    GPIO_SetBits(IIC_Port,IIC_SCL|IIC_SDA);//置高电平,IIC中的空闲状态

}

 

 

IIC起始、结束

 

类型串口中的起始位停止位

void MyIIC_Start(void)

{

    MyIIC_W_SDA(1);

    MyIIC_W_SCL(1);

    

    MyIIC_W_SDA(0);

    MyIIC_W_SCL(0);

}


void MyIIC_Stop(void)

{

    MyIIC_W_SDA(0);

    //MyIIC_W_SCL(0);

 

    MyIIC_W_SCL(1);

    MyIIC_W_SDA(1);

}


 

SCL全程由主机控制

主机发送数据:

SCL低电平时,主机放置数据位到SDA线上,然后拉高SCL;经过一段时间(等待从机读取),继续拉低SCL传输下一位数据,重复8次即为一个字节。

从机在SCL高电平时(上升沿)读取SDA电平(数据);

 

低电平主机放数据,高电平从机读数据

 

void MyIIC_SendByte(uint8_t Byte)

{

    int8_t i;

    //写SDA时 默认SCL低电平

    for(i = 7; i >= 0; i--)

    {

        //一个字节分为 8位,从高到低一次发送

        MyIIC_W_SDA(Byte & (1 << i));

        MyIIC_W_SCL(1);//从机在SCL高电平时读走这个电平

        MyIIC_W_SCL(0);//拉低再写电平

    }  

}

 

主机接收数据:

 

主机需要释放SDA线的控制权,将控制权交给从机

在SCL低电平期间,从机将数据位放在SDA线上,SCL高电平时,主机读取SDA数据(电平)

低电平从机放数据,高电平主机读数据

 

uint8_t MyIIC_ReceiveByte(void)

{

    uint8_t Byte = 0x00;

    int8_t i;

 

    //主机读SDA时,默认SCL低电平

    MyIIC_W_SDA(1);//释放SDA

 

    for(i = 7; i >= 0; i--)

    {

        //这时从机写SDA电平

        MyIIC_W_SCL(1);//SCL置高,主机读

        if(MyIIC_R_SDA() == 1) {Byte |= (1 << i);}

 

        MyIIC_W_SCL(0);//读取完之后,继续把SCL拉低,等待从机写

    }

    return Byte;

}

 


应答机制

 


和发送一位数据的机制相同;

主机接收完一个字节,发送一个应答位,0为应答,1为非应答

 

void MyIIC_SendAck(uint8_t AckBit)

{

    MyIIC_W_SDA(AckBit);

    MyIIC_W_SCL(1);//从机在SCL高点平时读走这个电平

    MyIIC_W_SCL(0);//拉低再写电平

}

 

主机接收应答

主机发送完一个字节,接收一个应答位,0为应答,1为非应答

(判断从机是否应答)(需要释放SDA控制权给从机)

uint8_t MyIIC_ReceiveAck(void)

{

    uint8_t AckByte;

 

    MyIIC_W_SDA(1);//释放SDA

    //这时从机写SDA电平

    MyIIC_W_SCL(1);//SCL置高,主机读

    AckByte = MyIIC_R_SDA();

    MyIIC_W_SCL(0);//读取完之后,继续把SCL拉低,等待从机写

 

    return AckByte;

}

 

 

 

 


S:起始  从机地址7位 + 读写1位  应答位

      读取位:(0写入/1读入)

#define MPU6050_ADDRESS  0XD0 //芯片地址

//MPU6050 在寄存器地址上写数据时序

void MPU6050_WriteReg(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();

}

 

 

较少用,因为不能指定读地址,只能根据寄存器地址指针读数据

 

 

 


看图

 

先起始,第一个字节为地址(7位)加写(1位),一个应答位 ,

再发一个寄存器地址,寄存器地址指针这时指向了这个地址

重新起始,读当前位置,SDA交给从机写,应答,停止

uint8_t MPU6050_ReadReg(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);//只读一个字节,不给应答

    //如果要读取多个字节 for循环32 33 行,最后一个字节应答1,之前应答0

    MyIIC_Stop();

 

    return Data;

}

 

 

 

 

 

 

 

 

MPU6050参数

 


void MPU6050_Init()

{

    MyIIC_Init();

    //以下配置需要看芯片的寄存器手册

    MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//电源管理寄存器1,解除睡眠,选择X轴陀螺仪时钟

    MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//电源管理寄存器2,6轴均不待机

 

    MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//时钟分频 0x09  10分频

    MPU6050_WriteReg(MPU6050_CONFIG, 0x06);    //数字低通滤波器 , 最大滤波参数

    MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//陀螺仪配置寄存器 ,最大量程

    MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计配置寄存器 , 最大量程

}

 


获取数据全部封装在这个函数中

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;//uint8_t 左移8位 会自动类型转换 为uint16

    

    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;

 

}

 

 

uint8_t MPU6050_GetID(void)

{

    return (MPU6050_ReadReg(MPU6050_WHO_AM_I));

}

 


江科大学习笔记 _12.软件IIC的评论 (共 条)

分享到微博请遵守国家法律