I2C实战——STM32与EEPROM通信

一,EEPROM

        这里用的EEPROM是AT24C02芯片,  02 代表2K个位 , 那么总容量就是:256(2K/8)个字节。接口:IIC.

        

         

        AT24C02字节写时序图:

                

         AT24C02字节读时序图:

              

        AT24C02与STM32的连接:

        例如:24C02 的 SCL 和 SDA 分别连在 STM32 的 PB6 和 PB7 上的,连接关系如图所示:

                             

 二,代码实现

        I2C驱动与通信协议代码实现:


// 根据原理图设置IO
#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

// 初始化IIC
void IIC_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //PB 时钟使能
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIO
	GPIO_SetBits(GPIOB, GPIO_Pin_6|GPIO_Pin_7); // PB6, PB7 输出高,空闲状态
}

// 产生IIC的起始信号
void IIC_Start(void)
{
	SDA_OUT();  //sda 线输出
	IIC_SDA = 1;    
	IIC_SCL = 1;  // 空闲状态需要将2根线拉高
	delay_us(4);
	IIC_SDA = 0;	// START: 当SCL高电平时, SDA 由高拉低.
	delay_us(4);
	IIC_SCL = 0;  // SCL拉低,钳住I2C总线,准备发送或接收数据
}

// 产生IIC的停止信号
void IIC_Stop(void)
{
	SDA_OUT();  //sda 线输出
	IIC_SCL = 0;
	IIC_SDA = 0; 
	delay_us(4);
	IIC_SCL = 1;   // 发送I2C总线结束信号
	IIC_SDA = 1;    // STOP: 当SCL高电平时, SDA 由低拉高.
	delay_us(4);
}

// IIC发送一个字节数据
void IIC_Send_Byte(u8 txd)
{
	u8 t;
	SDA_OUT();
	IIC_SCL = 0; // 拉低时钟开始数据传输
	for(t=0; t<8; t++) {
		if ((txd & 0x80)>>7)  //最高位是1,SDA 拉高,否则拉低。
			IIC_SDA = 1;
		else
			IIC_SDA = 0;
		
		txd <<= 1;  // 依次从高地址到低地址发送数据。
		delay_us(2);
		IIC_SCL = 1; // SDA数据准备之后,将SCL 拉高。
		delay_us(2);
		IIC_SCL = 0; // 再将SCL 拉低。
		delay_us(2);
	}
}
// IIC读取一个字节数据
// ack=1时,发送ack,ack=0时,发送nack。
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i, receive=0;
	SDA_IN(); // SDA 设置为输入
	for(i=0;i<8;i++) {
		IIC_SCL = 0;
		delay_us(2);
		IIC_SCL = 1;  // 拉高SCL, 为高电平时,读取数据,
		receive <<= 1;  // 读数据保存在高位
		if(READ_SDA) receive++;  // 如果是输入模式,低位+1,否则不加
		delay_us(1);
	}
	
	if(!ack) 
		IIC_NAck(); // 发送nack
	else 
		IIC_Ack(); // 发送ack
	
	return receive;
}

// 等待应答信号的到来
// 返回值: 1, 接收应答失败
// 			0, 接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime = 0;
	SDA_IN(); // SDA 设置为输入
	IIC_SDA=1;delay_us(1);
	IIC_SCL=1;delay_us(1);
	
	while(READ_SDA) {
		ucErrTime++;
		if (ucErrTime > 250) {
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL = 0; // 时钟输出 0
	return 0;
}

// 产生IIC的应答信号
void IIC_Ack(void)
{
	IIC_SCL = 0;
	SDA_OUT();
	IIC_SDA = 0;
	delay_us(2);
	IIC_SCL = 1;
	delay_us(2);
	IIC_SCL = 0;
}

// 不产生IIC的应答信号
void IIC_NAck(void)
{
	IIC_SCL = 0;
	SDA_OUT();
	IIC_SDA = 1;
	delay_us(2);
	IIC_SCL = 1;
	delay_us(2);
	IIC_SCL = 0;
}

         AT24C02驱动与I2C接口实现

//初始化IIC接口
void AT24C02_Init(void)
{
	IIC_Init();
}

//ReadAddr:开始读数的地址  
//返回值  :读到的数据
u8 AT24C02_ReadOneByte(u16 ReadAddr)
{
	u8 temp = 0;

    // dummy write
	IIC_Start();
	IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据
	IIC_Wait_Ack(); 
    IIC_Send_Byte(ReadAddr%256);   //发送低地址
	IIC_Wait_Ack();	    
	
    //real write
	IIC_Start();  	 	   
	IIC_Send_Byte(0XA1);           //进入接收模式			   
	IIC_Wait_Ack();	 
	
    temp=IIC_Read_Byte(0);		   
    IIC_Stop();//产生一个停止条件	    
	return temp;
}

// WriteAddr  :写入数据的目的地址    
// DataToWrite:要写入的数据
void AT24C02_WriteOneByte(u16 WriteAddr, u8 DataToWrite)
{
    // write device addresss
	IIC_Start();  
	IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据  
	IIC_Wait_Ack();
	
    // write word address
    IIC_Send_Byte(WriteAddr%256);   //发送低地址
	IIC_Wait_Ack(); 	 										  		   
	// write data
	IIC_Send_Byte(DataToWrite);     //发送字节							   
	IIC_Wait_Ack();  		    	   
    
	IIC_Stop();//产生一个停止条件 
	delay_ms(10);	 
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值