
一、概述



二、信号概念

三、AT24C02(EEPROM电可擦除ROM)--配合单片机存贮掉电前需要保存的数据,类似单片机的硬盘

1、写时序

2、读时序

思考题2:在24c02控制时钟的时候,为什么要进行5us的延时,小于5us延时或许大于5us的延时是否可以,示例代码如下:
//设置SCL高电平
SCL=1;
delay_us(5);
//设置SCL低电平
SCL=0;
delay_us(5);回答:大于5us是可以的,如果使用5ms是可以的。但是延时是不能低于1.2us,详细描述如下图。


3、起始信号和停止信号

//sda输入输出模式切换函数
void OLED_SDA_Mode(GPIOMode_TypeDef IOMode)
{
//PB9初始化设置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN; //9号引脚
GPIO_InitStructure.GPIO_Mode = IOMode; //输出模式/输入模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,驱动LED需要电流驱动
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(OLED_GPIO_PORT, &GPIO_InitStructure); //初始化GPIOB,把配置的数据写入寄存器
}
/**********************************************
//IIC Start
**********************************************/
void IIC_Start(void)
{
//保证SDA引脚为输出模式
OLED_SDA_Mode(GPIO_Mode_OUT);
OLED_SCLK = 1;
OLED_SDA_W = 1;
/*注:原版代码是没有加延时的,这里一定要延时,因为M4是高速芯片,3.3MHz通信速率,所以一个时钟周 期约为0.3us,有与我们处理器是168MHz,执行一条指令比这个时间快很多所以我们需要加至少1us的延时,
但是在频率较低的处理器中我们可以不加延时
*/
delay_us(1);
OLED_SDA_W = 0; //数据线先拉低,时钟线后拉低,即为启动信号
delay_us(1);
OLED_SCLK = 0;
delay_us(1);
}
/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop(void)
{
//保证SDA引脚为输出模式
OLED_SDA_Mode(GPIO_Mode_OUT);
OLED_SCLK = 1; //时钟线先拉高,数据线后拉高,即为停止信号
OLED_SDA_W = 0;
delay_us(1);
OLED_SDA_W = 1;
delay_us(1);
}
uint8_t IIC_Wait_Ack(void)
{
uint8_t ack=0;
//保证SDA引脚为输入模式
OLED_SDA_Mode(GPIO_Mode_IN);
OLED_SCLK = 1;
delay_us(1);
//有应答为低电平,无应答为高电平
if(OLED_SDA_R) //无应答
{
ack=1;
IIC_Stop();
}
else //有应答
ack=0;
OLED_SCLK = 0;
delay_us(1);
return ack;
}/**********************************************// IIC Read byte
**********************************************/uint8_t i2c_recv_byte(void){
uint8_t byte=0;
uint32_t i=0;
//保证SDA引脚为输出模式
i2c_sda_mode(GPIO_Mode_OUT);
//设置为低电平
SCL=0;
SDA_W=0;
delay_us(5);
//保证SDA引脚为输入模式
i2c_sda_mode(GPIO_Mode_IN);
for(i=0; i<8; i++)
{
//设置时钟为高电平,告诉从机,可以对SDA引脚进行控制
SCL=1;
delay_us(5);
//读取SDA引脚的电平
if(SDA_R)
byte|=1<<(7-i);
//设置时钟为低电平,告诉从机,不可以对SDA引脚进行控制
SCL=0;
delay_us(5);
}
return byte;
}
void at24c02_read(uint8_t addr,uint8_t *pbuf,uint32_t len) //从机读取数据
{
uint32_t ack=0;
//发送起始信号
i2c_start();
//发送寻址地址
i2c_send_byte(0xA0);
//等待应答
ack=i2c_wait_ack();
if(ack)
{
printf("i2c ack device address fail\r\n");
return ;
}
printf("i2c ack device address ok\r\n");
//发送24c02的数据存储地址
i2c_send_byte(addr);
//等待应答
ack=i2c_wait_ack();
if(ack)
{
printf("i2c ack word address fail\r\n");
return ;
}
printf("i2c ack word address ok\r\n");
//再一次发送起始信号
i2c_start();
//发送寻址地址,读访问操作
i2c_send_byte(0xA1);
//等待应答
ack=i2c_wait_ack();
if(ack)
{
printf("i2c ack device address_r fail\r\n");
return ;
}
printf("i2c ack device address_r ok\r\n");
len=len-1;
while(len--)
{
*pbuf++=i2c_recv_byte();
i2c_ack(0);
}
*pbuf=i2c_recv_byte();
i2c_ack(1);
//发送停止信号
i2c_stop();
printf("i2c ack read data ok\r\n");
}
/**********************************************
// IIC Write byte
**********************************************/
void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
//保证SDA引脚为输出模式
OLED_SDA_Mode(GPIO_Mode_OUT);
OLED_SCLK = 0;
delay_us(1);
for(i=0;i<8;i++)
{
if(IIC_Byte&(1<<(7-i))) MSB
OLED_SDA_W = 1;
else
OLED_SDA_W = 0;
delay_us(1);
OLED_SCLK = 1;
delay_us(1);
OLED_SCLK = 0;
delay_us(1);
}
}
本文介绍了STM32中I2C协议的基础知识,包括信号概念和AT24C02 EEPROM的使用。在配合单片机存储数据时,详细阐述了AT24C02的写入和读取时序,并针对控制时钟时的5us延时进行了讨论,指出延时至少需1.2us,但大于5us也是可行的。
-------I2C协议&spm=1001.2101.3001.5002&articleId=79659815&d=1&t=3&u=f3973d3eaf864b33b6985d7e122565cb)
4万+

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



