一、简介
(1)物理层

是一个支持多设备的总线。“总线”指多个设备共用的信号线。在一个I2C通信总线中,可连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机。
一个I2C总线只使用两条总线,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线用来传输数据,时钟线用于数据收发同步。
每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。
总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
具有三种传输模式:标准模式传输速率为100Kbit/s ; 快速模式传输速率为400Kbit/s ; 高速模式下可达3.4Mbit/s。但目前最常用的就是快速模式,而大多数I2C设备尚不支持高速模式。
(2)协议层
I2C的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。
1》I2C基本读写过程
主机写数据到从机:

主机由从机读数据:

通讯符合格式:

EEPROM有设备地址,内部有存储器地址,如果从EEPROM第2个存储单元格地址读取数据,则:
首先,往EEPROM写入要读取的存储单元格的地址;
然后,接收EEPROM返回来的第2个存储单元格的内容。
2》起始和停止信号

3》数据有效性

4》地址及数据方向

8位设备写地址 = (7位设备地址 << 1) | 0 ;
8位设备读地址 = (7位设备地址 << 1) | 1 。
5》响应

二、
三、固件库
(1)初始化结构体
typedef struct
{
uint32_t I2C_ClockSpeed; //设置SCL时钟频率,此值要低于40 0000。
uint16_t I2C_Mode; //指定工作模式。
I2C_Mode_I2C (I2C模式)
I2C_Mode_SMBusDevice(SMBUS从机模式)
I2C_Mode_SMBusHost (SMBUS主机模式)
uint16_t I2C_DutyCycle; //指定时钟占空比。
I2C_DutyCycle_16_9 (low/high = 16 :9)
I2C_DutyCycle_2 (low/high = 2 :1)
uint16_t I2C_OwnAddress1; //指定自身的I2C设备地址。
uint16_t I2C_Ack; //使能或关闭响应(一般使能)。
I2C_Ack_Enable (使能)
I2C_Ack_Disable(禁用)
uint16_t I2C_AcknowledgedAddress; //指定设备地址长度。
I2C_AcknowledgedAddress_7bit (7位设备地址)
I2C_AcknowledgedAddress_10bit(10位设备地址)
}I2C_InitTypeDef;
(2)常用固件库函数
1》产生起始信号
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
2》产生终止信号
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);
3》发送7位设备地址
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
参数:
I2C_Direction ---> I2C_Direction_Transmitter(发送方) ; I2C_Direction_Receiver(接收方)。
4》发送数据
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
5》接收数据
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);
6》获取状态标志
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
7》获取中断状态标志
ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT);
四、AT24C02介绍
容量为2048bits,256个字节,8个字节为一页,共32页。
设备地址:

写入数据时序图:
1》按字节写入

2》按页写入

读取数据时序图:
1》读取当前地址的数据(极少使用)

2》随机读取数据

3》顺序读取数据

五、程序
/*i2c.h文件*/
#ifndef __I2C_H__
#define __I2C_H__
#include "stm32l1xx.h"
#define EEPROM_PAGE_SIZE 8 //ÿҳ8¸ö×Ö½Ú
void I2C_Config(void);
uint8_t EEPROM_Write_Byte(uint8_t addr,uint8_t data);
uint8_t EEPROM_Read_Byte(uint8_t addr,uint8_t *data);
uint8_t EEPROM_Write_Page(uint8_t addr,uint8_t *data,uint8_t size);
uint8_t EEPROM_Read_Buff(uint8_t addr,uint8_t *data,uint16_t size);
uint8_t EEPROM_Write_Buff(uint8_t addr, uint8_t* data, uint16_t size);
#endif
/*i2c.c文件*/
#include "./I2C/i2c.h"
#define TIME_OUT 0x000FFFFF
uint32_t count_wait = TIME_OUT;
static uint8_t Wait_For_Standby(void);
/*
SCL --- PB8 ; SDA --- PB9
*/
void I2C_Config(void)
{
GPIO_InitTypeDef initValue;
I2C_InitTypeDef i2c1InitValue;
//打开时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
//配置GPIO的复用功能
initValue.GPIO_Mode = GPIO_Mode_AF;
initValue.GPIO_OType = GPIO_OType_OD;
initValue.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
initValue.GPIO_PuPd = GPIO_PuPd_NOPULL;
initValue.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Init(GPIOB,&initValue);
//选择复用引脚
GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_I2C1);
//初始化I2C串口
i2c1InitValue.I2C_Ack = I2C_Ack_Enable;
i2c1InitValue.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
i2c1InitValue.I2C_ClockSpeed = 400000;
i2c1InitValue.I2C_DutyCycle = I2C_DutyCycle_2;
i2c1InitValue.I2C_Mode = I2C_Mode_I2C;
i2c1InitValue.I2C_OwnAddress1 = 0x78;
I2C_Init(I2C1,&i2c1InitValue);
//使能I2C
I2C_Cmd(I2C1,ENABLE);
}
//往EEPROM写入一个字节的数据
//addr:要写入数据的单元格地址
//data:要写入的数据
uint8_t EEPROM_Write_Byte(uint8_t addr,uint8_t data)
{
//产生起始信号
I2C_GenerateSTART(I2C1,ENABLE);
//等待EV5事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 1;
}
}
//发送设备写地址
I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Transmitter);
//等待EV6事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 2;
}
}
//发送要写入数据的单元格地址
I2C_SendData(I2C1,addr);
//等待EV8_2事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 3;
}
}
//发送要写入的数据
I2C_SendData(I2C1,data);
//等待EV8_2事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 4;
}
}
//产生结束信号
I2C_GenerateSTOP(I2C1,ENABLE);
//等待接入完成
return Wait_For_Standby();
}
//读取一个字节数据
uint8_t EEPROM_Read_Byte(uint8_t addr,uint8_t *data)
{
//产生起始信号
I2C_GenerateSTART(I2C1,ENABLE);
//等待EV5事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 5;
}
}
//发送设备写地址·
I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Transmitter);
//等待EV6事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 6;
}
}
//发送要读取的单元格地址
I2C_SendData(I2C1,addr);
//等待V8_2事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 7;
}
}
//重新产生起始信号
I2C_GenerateSTART(I2C1,ENABLE);
//等待EV5事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 8;
}
}
//发送设备读地址
I2C_Send7bitAddress(I2C1,0xA1,I2C_Direction_Receiver);
//等待EV6事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 9;
}
}
//产生应答信号
I2C_AcknowledgeConfig(I2C1,DISABLE);
//等待EV7事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
{
count_wait--;
if(count_wait == 0)
{
return 10;
}
}
//接收读取到的数据
*data = I2C_ReceiveData(I2C1);
//产生停止信号
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
//页写入
//data:要写入的数据的指针
//addr:要写入的存储单元格首地址
//size:要写入多少个数据(size小于等于8)
uint8_t EEPROM_Write_Page(uint8_t addr,uint8_t *data,uint8_t size)
{
//产生起始信号
I2C_GenerateSTART(I2C1,ENABLE);
//等待EV5事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 12;
}
}
//发送设备写地址
I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Transmitter);
//等待EV6事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 13;
}
}
//发送单元格首地址
I2C_SendData(I2C1,addr);
//等待EV8_2事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 14;
}
}
//发送要写入的数据
while(size--)
{
I2C_SendData(I2C1,*data);
//等待EV8_2事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 15;
}
}
data++;
}
//产生终止信号
I2C_GenerateSTOP(I2C1,ENABLE);
//等待内部时序完成
return Wait_For_Standby();
}
//顺序读取数据
//addr:要读取的单元格首地址
//data:存放数据的指针
//size:要读取多少个数据
uint8_t EEPROM_Read_Buff(uint8_t addr,uint8_t *data,uint16_t size)
{
//产生起始信号
I2C_GenerateSTART(I2C1,ENABLE);
//等待EV5事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 16;
}
}
//发送设备写地址
I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Transmitter);
//等待EV6事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 17;
}
}
//发送要读取的单元格首地址
I2C_SendData(I2C1,addr);
//等待EV8_2事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 18;
}
}
//重新产生起始信号
I2C_GenerateSTART(I2C1,ENABLE);
//等待EV5事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 16;
}
}
//发送设备读地址
I2C_Send7bitAddress(I2C1,0xA1,I2C_Direction_Receiver);
//等待EV6事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 20;
}
}
//读取数据
while(size--)
{
if(size == 0)
{
//产生非应答信号
I2C_AcknowledgeConfig(I2C1,DISABLE);
}
else
{
//产生应答信号
I2C_AcknowledgeConfig(I2C1,ENABLE);
}
//等待EV7事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 21;
}
}
//读取数据
*data = I2C_ReceiveData(I2C1);
data++;
}
//产生终止信号
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
//分页写入
//addr:要写入数据的单元格首地址
//data:要写入的数据的指针
//size:要写入多少个数据
uint8_t EEPROM_Write_Buff(uint8_t addr, uint8_t* data, uint16_t size)
{
uint8_t single_adrr = addr%EEPROM_PAGE_SIZE;
if(single_adrr == 0)
{
uint8_t num_of_page = size/EEPROM_PAGE_SIZE;
uint8_t single_byte = size%EEPROM_PAGE_SIZE;
while(num_of_page--)
{
//调用页写入函数
EEPROM_Write_Page(addr, data, EEPROM_PAGE_SIZE);
//等待写入完成
Wait_For_Standby();
addr += EEPROM_PAGE_SIZE;
data += EEPROM_PAGE_SIZE;
}
//调用页写入函数
EEPROM_Write_Page(addr, data, single_byte);
//等待写入完成
Wait_For_Standby();
}
else //addr不对齐
{
uint8_t num_of_page,single_byte,sheng_yu;
//第一次写入
uint8_t first_size = EEPROM_PAGE_SIZE - single_adrr;
//调用页写入函数
EEPROM_Write_Page(addr, data, first_size);
//等待写入完成
Wait_For_Standby();
addr += first_size;
data += first_size;
//剩下要写入的数据
sheng_yu = size - first_size;
num_of_page = sheng_yu/EEPROM_PAGE_SIZE;
single_byte = sheng_yu%EEPROM_PAGE_SIZE;
while(num_of_page--)
{
//调用页写入函数
EEPROM_Write_Page(addr, data, EEPROM_PAGE_SIZE);
//等待写入完成
Wait_For_Standby();
addr += EEPROM_PAGE_SIZE;
data += EEPROM_PAGE_SIZE;
}
/调用页写入函数
EEPROM_Write_Page(addr, data, single_byte);
//等待写入完成
Wait_For_Standby();
}
return 0;
}
//等待EEPROM内部写入操作完成
//0表示正常等待完成,非0表示等待不到响应信号
uint8_t Wait_For_Standby(void)
{
uint32_t check_count = 0xFFFFF;
while(check_count--)
{
//产生起始信号
I2C_GenerateSTART(I2C1, ENABLE);
//等待EV5事件
count_wait = TIME_OUT;
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
{
count_wait--;
if(count_wait == 0 )
{
return 11;
}
}
//发送设备写地址
I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter);
//等待EV6事件
count_wait = TIME_OUT;
while(count_wait--)
{
//若检测到响应,说明内部写时序完成,跳出等待函数
if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == SUCCESS)
{
//退出前停止本次通讯
I2C_GenerateSTOP(I2C1, ENABLE);
return 0;
}
}
}
//退出前停止本次通讯
I2C_GenerateSTOP(I2C1, ENABLE);
return 1;
}
/*main.c文件*/
#include "stm32l1xx.h"
#include "./I2C/i2c.h"
uint8_t test[500*1024];
#define TEST_SIZE 256
int main(void)
{
uint16_t i;
uint8_t data[TEST_SIZE];
uint8_t buff[TEST_SIZE];
//给buff赋值
for(i=0;i<TEST_SIZE;i++)
{
buff[i]=i;
}
if(test[0])
{
//printf("\r\n页读写测试结束,读取到的数据为:\r\n");
}
I2C_Config();
//写入测试
EEPROM_Write_Byte(0x01,0x12);
EEPROM_Read_Byte(0x01,data);
//printf("\r\n单字节读写测试结束,data=0x%x\n",data[0]);
EEPROM_Write_Buff(0x00, buff, TEST_SIZE);
EEPROM_Read_Buff(0x00,data, TEST_SIZE);
//printf("\r\n页写入测试结束,读取到的数据为:\r\n");
for(i=0;i<TEST_SIZE;i++)
{
//printf("0x%02x ",data[i]);
}
while(1)
{
}
}
1707

被折叠的 条评论
为什么被折叠?



