I2C总线与AT24C02

目录

I2C总线

I2C总线介绍

I2C电路规范

I2C时序结构

起始与终止

代码理解

发送字节

代码理解

接收字节

代码理解

数据应答

代码理解

I2C的数据据帧

发送数据帧

接收数据帧

发送接收数据帧

AT24C02芯片

AT24C02介绍

引脚及应用电路

内部结构图

AT24C02数据帧

字节写

代码理解

随机读

代码理解

注意:

仿真案例

电路图

keil文件

I2C总线

I2C总线介绍

  • I2C(inter IC BUS)是由Philips公司开发的一种通用数据总线
  • 两根通信线:SCL(Serial Clock)SDK(Serial Data)
  • 同步(有同步时钟线)、半双工(一根串行数据线),带数据应答
  • 通用的I2C总线可以使各种设备的通信标准统一,对于厂家来说,使用成熟的方案可以缩短芯片的设计周期、提高稳定性,对于应用者来说使用通用的通信协议可以避免学习各种各样的自定义协议,降低了学习和应用的难度

I2C电路规范

  • 所有的I2C设备的SCL连在一起,SDA连在一起
  • 设备的SCL和SDA均要配置成开漏输出模式
  • SCL和SDA各添加一个上拉电阻,阻值一般为4.7K欧左右
  • 开漏输出和上拉电阻共同作用实现了“线与的功能”,同时此设计主要是为了解决多机通信互相干扰的问题

理解:

  • CPU让引脚想发0的时候,就把他拉到低电平,CPU让引脚想发1的时候,就让NOMS关闭,那么引脚就会被外部的电源自动拉到高电平。
  • 若所有设备都开漏(都不接地)那么就由两个电阻承担上拉的能力。

I2C时序结构

起始与终止

  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平。
  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平。

代码理解
//I2C的start阶段
void I2C_Start(){
	SDA=1;
	SCL=1;
	SDA=0;
	SCL=0;
}
//I2C的stop阶段
void I2C_Stop(){
	SDA=0;
	SCL=1;
	SDA=1;
}

发送字节

理解:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前)然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。

注意:时序中SDA为数据,所以才可以看到电平的两种状态(电平可高可低)

代码理解
//I2C的发送一个字节s数据(先发高位)
void I2C_SendByte(unsigned char byte){
	unsigned char i=0;
    SCL=0;
	for(i=0;i<8;i++){
		SDA=byte&(0x80>>i);
		SCL=1;
		SCL=0;
	}
}

接收字节

理解:SCL低电平期间,从机将数据位依次放到SDA线上(高位在前)然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL在高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接受之前,需要释放SDA)

注意:紫色的线代表是从机控制的。

代码理解
//I2C的接收数据(先接收高位)
unsigned char I2C_ReceiveByte(){
	unsigned char byte=0,i=0;
	SCL=0;
	SDA=1; //主机释放SDA总线
	for(i=0;i<8;i++){
		SCL=1;
		if(SDA==1){
			byte=byte|(0x80>>i);
		}
	SCL=0;
	}
	return byte;
}

数据应答

  • 发送应答:主机在接收完一个字节后,其将在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
  • 接收应答:主机在发送完一个字节之后,其在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前需要释放SDA)

代码理解
//I2C发送应答
void I2C_SendAck(unsigned char ackBit){
	SDA=ackBit;
	SCL=1; //写入数据时拉高SCL
	SCL=0;
}
//I2C接收应答
unsigned char I2C_ReceiveAck(){
	unsigned char ackBit=0;
	SDA=1; //主机释放SDA总线
	SCL=1; //scl高电平期间就可以读取数据位了
	ackBit=SDA;
	SCL=0;
	return ackBit;
}

I2C的数据据帧

发送数据帧

前言:发送数据帧描述了要向谁发送什么。

理解:首先发送start起始,然后发送从机地址和读写位(确定是写)之后是从机的接收应答,再者就是主机发送的数据直到终止位。

注意:从机地址为前7位中,前4位是固定的,其他三位可配置,配置方式取决于AT24C02的对应三个引脚的接法;R/W中写数据该位为0,读数据为1。

接收数据帧

前言:接收数据帧描述了向谁收什么。

理解:首先发送start起始,然后发送从机地址和读写位(确定是读)之后是从机的接收应答,从机知道是读后就向主机发送数据了(主机释放SDA),然后就是主机接收数据后发送应答,直到终止位

发送接收数据帧

前言:发送接收数据帧描述了向谁收指定的什么。

理解:首先主机发送起始位,然后发送从机地址和读写位(确定是写)之后是从机的接收应答,接收应答后主机发送指定数据并接收应答,发送完毕后,主机发送起始位开始读,直到最后的终止位

AT24C02芯片

AT24C02介绍

  • AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息
  • 存储介质:E2PROM
  • 通讯接口:I2C总线
  • 容量:256字节

引脚及应用电路

内部结构图

理解:右边的最大模块就是我们的E2PROM,就是上面介绍的存储网格,左边跟个地址译码器(对应的线是地址线)下面就是数据的输入输出端(serial mux串行数据选择端数据通过Y译码器将数据一位一位输出出去)而E2PROM上面模块就是数据擦除模块;DATA WORD ADDR/COUNTER(数据字地址计数器)用来设置具体地址的,里面有存储地址的寄存器,我们每写入或读出一个数据,该寄存器会自动加1;左上三个分别为开始结束逻辑,器件地址比较器,串行控制逻辑。

AT24C02数据帧

字节写

前言:在word address处写入数据data。

代码理解
#define AT24C02_ADDRESS 0xA0
//字节写
void AT24C02_WriteByte(unsigned char wordAddress,unsigned char dat){
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(dat);
	I2C_ReceiveAck();
	I2C_Stop();
}

随机读

前言:读出在word address处的数据data

代码理解
#define AT24C02_ADDRESS 0xA0
//随机读
unsigned char AT24C02_ReadByte(unsigned char wordAddress){
	unsigned char dat;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	dat=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return dat;
}

注意:

  • AT24C02的slave address中前4位固定为1010,可配置地址在开发板上为000,所以slave address+w的地址为0xA0;slave address+r地址为0xA1。
  • word address为要发送或读取的芯片内部地址。

仿真案例

需求:将236存储在AT24C02中地址1处,并读出来。

电路图

注意:当在某个地址写入数据后,掉电以后再次开启单片机还可以读出该地址的数据(掉电以后数据不会丢失)

keil文件

#include "reg51.h"
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
void delay(unsigned int n){
	unsigned int i=0,j=0;
	for(i=0;i<n;i++){
		for(j=0;j<120;j++);
	}
}
//写指令
void writecom(unsigned char com){
	//写指令
	RS=0;
	RW=0;
	E=0;
	P2=com;
	delay(5);
	E=1;
	E=0;
}
//写数据
void writedat(unsigned char dat){
	//写指令
	RS=1;
	RW=0;
	E=0;
	P2=dat;
	delay(5);
	E=1;
	E=0;
}
//初始化液晶屏
void initlcd(){
	writecom(0x38);
	writecom(0x0c);
	writecom(0x06);
	writecom(0x01);
}
int LCD_Pow(int X,int Y){
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++){
		Result*=X;
	}
	return Result;
}
//展示数字
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length){
	unsigned char i;
	if(Line==1){
		writecom(0x80|(Column-1));
	}else{
		writecom(0x80|(Column-1)+0x40);
	}
	for(i=Length;i>0;i--){
		writedat('0'+Number/LCD_Pow(10,i-1)%10);
	}
}
//I2C部分
sbit SCL=P3^3;
sbit SDA=P3^4;
//I2C的start阶段
void I2C_Start(){
	SDA=1;
	SCL=1;
	SDA=0;
	SCL=0;
}
//I2C的stop阶段
void I2C_Stop(){
	SDA=0;
	SCL=1;
	SDA=1;
}
//I2C的发送一个字节s数据(先发高位)
void I2C_SendByte(unsigned char byte){
	unsigned char i=0;
	SCL=0;
	for(i=0;i<8;i++){
		SDA=byte&(0x80>>i);
		SCL=1;
		SCL=0;
	}
}
//I2C的接收数据(先接收高位)
unsigned char I2C_ReceiveByte(){
	unsigned char byte=0,i=0;
	SCL=0;
	SDA=1; //主机释放SDA总线
	for(i=0;i<8;i++){
		SCL=1;
		if(SDA==1){
			byte=byte|(0x80>>i);
		}
	SCL=0;
	}
	return byte;
}
//I2C发送应答
void I2C_SendAck(unsigned char ackBit){
	SDA=ackBit;
	SCL=1;
	SCL=0;
}
//I2C接收应答
unsigned char I2C_ReceiveAck(){
	unsigned char ackBit=0;
	SDA=1; //主机释放SDA总线
	SCL=1; //scl高电平期间就可以读取数据位了
	ackBit=SDA;
	SCL=0;
	return ackBit;
}
//AT24C02部分
#define AT24C02_ADDRESS 0xA0
//字节写
void AT24C02_WriteByte(unsigned char wordAddress,unsigned char dat){
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(dat);
	I2C_ReceiveAck();
	I2C_Stop();
}
//随机读
unsigned char AT24C02_ReadByte(unsigned char wordAddress){
	unsigned char dat;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	dat=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return dat;
}
unsigned char redat=0;
void main(){
	initlcd();
	AT24C02_WriteByte(1,236);
	delay(5);	//每次写完后需要延时5ms
	redat=AT24C02_ReadByte(1);
	LCD_ShowNum(2,1,redat,3);
	while(1);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值