目录
- 一.I2C协议简介
- 二.I2C物理层
- 三.I2C协议层
-
- I2C 基本读写过程
- 1.空闲状态
- 2.起始信号和停止信号
- 3.数据有效性
- 4.地址和数据方向
- 5.应答和非应答信号
- 四.硬件I2C
-
- I2C外设功能框图(重点)
- 1.通信引脚
- 2.时钟控制逻辑
- 3.数据控制逻辑
- 4.整体控制逻辑
- 5.STM32的I2C外设通信过程(超级重要)
-
- 主发送器
- 主接收器
- 6.I2C结构体的初始化
- 五.EEPROM简介
-
- 1.STM32向从机EEPROM写字节
- 2.STM32向从机EEPROM多字节(页写入)
- 3.STM32随机读取EEPROM内部任何地址的数据
- 4.STM32随机顺序读取EEPROM内部任何地址的数据
- 六.硬件I2C读写EEPROM实验
-
- 实验目的
- 实验原理
- 源码
- 实验效果
- 七.软件模式I2C协议
-
- 实验目的
- 实验原理
- 源码
- 八.总结
一.I2C协议简介
芯片)等通信协议,目前广泛应用于系统中的多个集成电路(IC)间的通讯。
二.I2C物理层
三.I2C协议层
I2C规定通信时钟、起始信号和停止信号只能由主机产生
I2C 基本读写过程
1.空闲状态
2.起始信号与停止信号
。
起始信号和停止信号是在SCL 是高电平期间,SDA线电平切换的过程,而不是单纯的高低电平。
3.数据有效性
4.地址及数据方向
5.应答与非应答信号
四.硬件I2C
I2C外设功能框图(重点)
1.通信引脚
。
2.时钟控制逻辑
3.数据控制逻辑
-
移位寄存器以“数据寄存器”为数据源,把数据一位一位地通过SDA信号线发送出去;
4.整体控制逻辑
主机模式与从机模式
5.STM32的I2C外设通信过程(超级重要)
I2C主模式:
主发送器
主设备等待读SR1寄存器,紧跟着将从地址写入DR寄存器
-
。
主接收器
接收数据之前,判断数据寄存器是否有数据,也就数据寄存器非空(RNXE),CPU就可以读取数据寄存器中的数据啦。
-
主设备在从设备接收到最后一个字节后发送一个NACK
。接收到NACK后,从设备释放对SCL和SDA线的控制;主设备就可以发送一个停止/重起始条件。
硬件I2C写代码必须熟练掌握和理解主发送器和主接收器的过程,只要你理解了写代码还不是信手拈来,简简单单,然后写代码你会发送就是上面的过程一模一样
6.I2C初始化结构体
五.EEPROM简介
1.STM32向从机EEPROM写入一个字节
2.STM32向从机EEPROM写入多个字节(页写入)
总结:
3.STM32随机读取EEPROM内部任何地址的数据
4.STM32随机顺序读取EEPROM内部任何地址的数据
六.硬件I2C读写EEPROM实验
实验目的
实验原理
详情请看——>GPIO端口的八种工作模式
源码
i2c_ee.h
#ifndef __IIC_EE_H
#define __IIC_EE_H
#include "stm32f10x.h"
#include <stdio.h>
//IIC1
#define EEPROM_I2C I2C1
#define EEPROM_I2C_CLK RCC_APB1Periph_I2C1
#define EEPROM_I2C_APBxClkCmd RCC_APB1PeriphClockCmd
#define EEPROM_I2C_BAUDRATE 400000
// IIC1 GPIO 引脚宏定义
#define EEPROM_I2C_SCL_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define EEPROM_I2C_SDA_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define EEPROM_I2C_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define EEPROM_I2C_SCL_GPIO_PORT GPIOB
#define EEPROM_I2C_SCL_GPIO_PIN GPIO_Pin_6
#define EEPROM_I2C_SDA_GPIO_PORT GPIOB
#define EEPROM_I2C_SDA_GPIO_PIN GPIO_Pin_7
//STM32自身地址1 与从机设备地址不相同即可(7位地址)
#define STM32_I2C_OWN_ADDR 0x6f
//EEPROM设备地址
#define EEPROM_I2C_Address 0XA0
#define I2C_PageSize 8
//等待次数
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
/*信息输出*/
#define EEPROM_DEBUG_ON 0
#define EEPROM_INFO(fmt,arg...) printf("<<-EEPROM-INFO->> "fmt"\n",##arg)
#define EEPROM_ERROR(fmt,arg...) printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)
#define EEPROM_DEBUG(fmt,arg...) do{
\ if(EEPROM_DEBUG_ON)\ printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\ }while(0)
void I2C_EE_Config(void);
void EEPROM_Byte_Write(uint8_t addr,uint8_t data);
uint32_t EEPROM_WaitForWriteEnd(void);
uint32_t EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite);
uint32_t EEPROM_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead);
void I2C_EE_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite);
#endif /* __IIC_EE_H */
i2c_ee.c
#include "i2c_ee.h"
//设置等待时间
static __IO uint32_t I2CTimeout = I2CT_LONG_TIMEOUT;
//等待超时,打印错误信息
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);
void I2C_EE_Config(void)
{
GPIO_InitTypeDef GPIO_InitStuctrue;
I2C_InitTypeDef I2C_InitStuctrue;
//开启GPIO外设时钟
EEPROM_I2C_GPIO_APBxClkCmd(EEPROM_I2C_SCL_GPIO_CLK|EEPROM_I2C_SDA_GPIO_CLK,ENABLE);
//开启IIC外设时钟
EEPROM_I2C_APBxClkCmd(EEPROM_I2C_CLK,ENABLE);
//SCL引脚-复用开漏输出
GPIO_InitStuctrue.GPIO_Mode=GPIO_Mode_AF_OD;
GPIO_InitStuctrue.GPIO_Pin=EEPROM_I2C_SCL_GPIO_PIN;
GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT,&GPIO_InitStuctrue);
//SDA引脚-复用开漏输出
GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStuctrue.GPIO_Pin = EEPROM_I2C_SDA_GPIO_PIN;
GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(EEPROM_I2C_SDA_GPIO_PORT,&GPIO_InitStuctrue);
//IIC结构体成员配置
I2C_InitStuctrue.I2C_Ack=I2C_Ack_Enable;
I2C_InitStuctrue.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
I2C_InitStuctrue.I2C_ClockSpeed=EEPROM_I2C_BAUDRATE;
I2C_InitStuctrue.I2C_DutyCycle=I2C_DutyCycle_2;
I2C_InitStuctrue.I2C_Mode=I2C_Mode_I2C;
I2C_InitStuctrue.I2C_OwnAddress1=STM32_I2C_OWN_ADDR;
I2C_Init(EEPROM_I2C,&I2C_InitStuctrue);
I2C_Cmd(EEPROM_I2C,ENABLE);
}
//向EEPROM写入一个字节
void EEPROM_Byte_Write(uint8_t addr,uint8_t data)
{
//发送起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
//检测EV5事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
//发送设备写地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
//检测EV6事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
//发送要操作设备内部的地址
I2C_SendData(EEPROM_I2C,addr);
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR);
I2C_SendData(EEPROM_I2C,data);
//检测EV8_2事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
//发送停止信号
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
}
//向EEPROM写入多个字节
uint32_t EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
//判断IIC总线是否忙碌
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
}
//重新赋值
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
//检测EV5事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送设备写地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
//检测EV6事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送要操作设备内部的地址
I2C_SendData(EEPROM_I2C,addr);
//检测EV8事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
}
while(Num_ByteToWrite)
{
I2C_SendData(EEPROM_I2C,*data);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);
}
Num_ByteToWrite--;
data++;
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//检测EV8_2事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
}
//发送停止信号
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
return 1;
}
//向EEPROM读取多个字节
uint32_t EEPROM_Read(uint8_t *data,uint8_t addr,ui