I2C

开发平台

  • 野火开发板 F429
  • 标准库
    一提到I2C就会想到是通信协议,两个设备遵守这个协议便可以进行通讯
  • 一个I2C总线上可以挂在多个I2C设备,一个I2C总线上有SCL(时钟线)和SDA(数据线)

I2C时序

  • I2C的时序,如下图:
    在这里插入图片描述
    1.SCL(时钟线)高电平有效。
    在SCL高电平时,SDA(数据线)由高电平被拉低,表示已经有了起始信号,可以开始通讯
    2.数据在SCL为高电平时有效,SCL为低电平时无效,在SCL为低电平时,SDA可切换高低电平。每次传输八位数据
    3收发数据后等待应答
    4.在SCL高电平时,SDA由低电平被拉高,表示通讯停止

I2C通讯过程

  • 主发送器序列
    在这里插入图片描述
    STM32作为主设备,每完成一个动作后都会产生相应的事件
    1.STM32发送起始信号
    2.发送I2C从设备地址
    3.发送I2C从设备内存地址
    4.发送数据(可多个)
    5.停止信号
  • 主接收器序列
    在这里插入图片描述1.STM32发送起始信号
    2.发送I2C从设备地址
    3.发送I2C从设备内存地址
    4.第二次发送起始信号
    5.发送I2C从设备地址(告知从设备要读取他的数据)
    6.读取数据(可多个)
    7.停止信号

I2C架构框图

直接操作寄存器,要看架构框图
在这里插入图片描述
1.时钟线和数据线
2.时钟控制寄存器(I2C主模式选择、快速模式占空比、CCR的值)
控制寄存器(使能应答、产生停止位、产生起始位等)
状态寄存器(通讯过程产生事件标志位)
在这里插入图片描述3.传输数据会用到(DR寄存器、OAR寄存器)
4.逻辑控制(涉及到中断、使用DMA等)

I2C读写EEPROM

在这里插入图片描述
EEPROM设备地址为7位,前4位地址固定为:1010,后三位看原理图000,最后一位由读操作或写操作决定,读为1,写为0。读地址为:0xA1,写地址为;0xA0

1.配置引脚,复用为I2C,注意一定是开漏输出
2.配置I2C的参数
3.编写接收、发送数据函数(要用到上述的通讯过程)

  • 注意:通讯过程产生的事件要看清,很多时候会写错事件标志而导致I2C不通

代码如下:

#include "i2c.h"

void I2C_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    /*使能时钟*/
    RCC_AHB1PeriphClockCmd(I2C_CLK_CLOCK|
                           I2C_SDA_CLOCK,ENABLE);
    /*引脚复用为I2C1*/
    GPIO_PinAFConfig(I2C_CLK_PORT,I2C_CLK_PINSOURCE,GPIO_AF_I2C1);
    GPIO_PinAFConfig(I2C_SDA_PORT,I2C_SDA_PINSOURCE,GPIO_AF_I2C1);
    /*
    **复用模式
    **开漏输出
    **不上拉不下拉
    **100MHZ
    **PB6 PB7
    */
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType=GPIO_OType_OD;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;

    GPIO_InitStruct.GPIO_Pin=I2C_CLK_PIN;
    GPIO_Init(I2C_CLK_PORT,&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin=I2C_SDA_PIN;
    GPIO_Init(I2C_SDA_PORT,&GPIO_InitStruct);
}

void I2C_Config(void)
{
    I2C_InitTypeDef I2C_InitStruct;
    /*使能时钟*/
    RCC_APB1PeriphClockCmd(I2C_CLOCK,ENABLE);
    I2C_GPIO_Config();
    /*
    **I2C模式
    **通信速率400K
    **STM32的I2C设备地址
    **占空比16:9
    **应答使能
    **地址长度7位
    */
    I2C_InitStruct.I2C_Mode=I2C_Mode_I2C;
    I2C_InitStruct.I2C_ClockSpeed=I2C_CLOCK_SPEED;
    I2C_InitStruct.I2C_OwnAddress1=I2C_OWNADDRESS;
    I2C_InitStruct.I2C_DutyCycle=I2C_DutyCycle_16_9;
    I2C_InitStruct.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
    I2C_InitStruct.I2C_Ack=I2C_Ack_Enable;
    I2C_Init(I2C_PORT,&I2C_InitStruct);
    /*使能I2C*/
    I2C_Cmd(I2C_PORT,ENABLE);
}

uint8_t I2C_Writebyte(uint8_t addr,uint8_t *data)
{
    /*I2C起始信号*/
    I2C_GenerateSTART(I2C_PORT,ENABLE);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
    /*I2C设备地址*/
    I2C_Send7bitAddress(I2C_PORT,I2C_ADDRESS_WRITE1,I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);
    /*发送内存地址*/
    I2C_SendData(I2C_PORT,addr);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);
    /*写入数据*/
    I2C_SendData(I2C_PORT,*data);
    /*I2C结束信号*/
    I2C_GenerateSTOP(I2C_PORT,ENABLE);
    return 1;
}

uint8_t I2C_Readbyte(uint8_t addr)
{
    uint8_t data;
    /*I2C起始信号*/
    I2C_GenerateSTART(I2C_PORT,ENABLE);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
    /*I2C设备地址写*/
    I2C_Send7bitAddress(I2C_PORT,I2C_ADDRESS_WRITE1,I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);
    /*发送内存地址*/
    I2C_SendData(I2C_PORT,addr);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);
    /*重新发送起始信号*/
    I2C_GenerateSTART(I2C_PORT,ENABLE);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
    /*I2C设备地址读*/
    I2C_Send7bitAddress(I2C_PORT,I2C_ADDRESS_READ1,I2C_Direction_Receiver);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS);
    /*读取数据*/
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS);
    data=I2C_ReceiveData(I2C_PORT);
    /*失能应答*/
    I2C_AcknowledgeConfig(I2C_PORT,DISABLE);
    /*停止信号*/
    I2C_GenerateSTOP(I2C_PORT,ENABLE);
    /*使能应答,为下一次读取做准备*/
    I2C_AcknowledgeConfig(I2C_PORT,ENABLE);
    return data;
}

uint8_t I2C_Writepbuffer(uint8_t addr,uint8_t *data,uint8_t num)
{
    /*I2C起始信号*/
    I2C_GenerateSTART(I2C_PORT,ENABLE);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
    /*I2C设备地址*/
    I2C_Send7bitAddress(I2C_PORT,I2C_ADDRESS_WRITE1,I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);
    /*发送内存地址*/
    I2C_SendData(I2C_PORT,addr);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);
    while(num)
    {
        /*写入数据*/
        I2C_SendData(I2C_PORT,*data);
        while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);
        data++;
        num--;
    }
    /*停止信号*/
    I2C_GenerateSTOP(I2C_PORT,ENABLE);
    return 1;
}

uint8_t I2C_Readpbuffer(uint8_t addr,uint8_t num,uint8_t *pbuffer)
{
    /*起始信号*/
    I2C_GenerateSTART(I2C_PORT,ENABLE);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
    /*设备地址*/
    I2C_Send7bitAddress(I2C_PORT,I2C_ADDRESS_WRITE1,I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);
    /*内存地址*/
    I2C_SendData(I2C_PORT,addr);
    /*第二次起始信号*/
    I2C_GenerateSTART(I2C_PORT,ENABLE);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
    /*发送设备地址为读*/
    I2C_Send7bitAddress(I2C_PORT,I2C_ADDRESS_READ1,I2C_Direction_Receiver);
    while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS);
    while(num)
    {
        if(num==1)
        {
            I2C_AcknowledgeConfig(I2C_PORT,DISABLE);
            I2C_GenerateSTOP(I2C_PORT,ENABLE);
        }
        while(I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS);
        {
            
            *pbuffer=I2C_ReceiveData(I2C_PORT);
            pbuffer++;
            num--;
        }
        I2C_AcknowledgeConfig(I2C_PORT,ENABLE);
    }
    return 1;

}
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值