IIC总线通讯协议、EEPROM芯片
**EEPROM芯片:**掉电不会丢失数据,可以保存数据。IIC串行总线的组成及工作原理:
·
EEPROM芯片: 掉电不会丢失数据,可以保存数据。IIC串行总线的组成及工作原理:
IIC总线传输协议
IIC产生起始与终止信号:
IIC字节的传送与应答:
应答位作用:
数据帧格式:
总线寻址
软件模拟IIC通信时序
IIc通信代码示例(通过数码管显示单片机通过IIC通信接收到的数据):
#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define At24c02ADDR 0XA0 //AT24C02硬件地址
#define I2cRead 1 //I2C读方向位
#define I2cWrite 0 //I2C写方向位
sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管段选
sbit SCL = P2^1;//I2C时钟总线
sbit SDA = P2^0;//I2C数据总线
uchar num;//数码管显示的值
bit AckFlag;//应答标志位
//共阴数码管段选表0-9
uchar code SMGduan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
//数码管位选码
uchar code SMGwei[] = {0xfe, 0xfd, 0xfb};
void delay(uint z)
{
uint x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
void display(uchar i)
{
static uchar wei;
P0 = 0XFF;//清除断码
WE = 1;//打开位选锁存器
P0 = SMGwei[wei];
WE = 0;//锁存位选数据
switch(wei)
{
case 0: DU = 1; P0 = SMGduan[i / 100]; DU = 0; break;
case 1: DU = 1; P0 = SMGduan[i % 100 / 10]; DU = 0; break;
case 2: DU = 1; P0 = SMGduan[i % 10]; DU = 0; break;
}
wei++;
if(wei == 3)
wei = 0;
}
//定时器0初始化
void timer0Init()
{
EA = 1; //打开总中断
ET0 = 1;//打开定时器0中断
TR0 = 1; //启动定时器0
TMOD |= 0X01; //定时器工作模式1,16位定时模式
TH0 = 0xED;
TL0 = 0xFF; //定时5ms
}
/****************************************************
IIC通信代码
****************************************************/
//延时5us
void delay5us()
{
_nop_();//执行一次是一个机器周期,进入这个函数需要3个多机器周期
}
//时钟总线为高电平期间数据总线由高变低产生起始信号
void I2cStart()
{
SCL = 1;
SDA = 1;
delay5us();//状态保持5us
SDA = 0;
delay5us();//状态保持5us
//这个函数根据图像来写
}
//时钟总线为高电平期间,数据总线从高变低产生终止信号
void I2cStop()
{
SCL = 0;
SDA = 0;
SCL = 1;
delay5us();//状态保持5us
SDA = 1;
delay5us();//状态保持5us
//这个函数根据图像来写
}
bit ReadACK()
{
SCL = 0;//拉低时钟总线,允许从机控制SDA
SCL = 1;//拉高,读SDA
delay5us();
if(SDA)//非应答
{
SCL = 0;
return(1);//返回1
}
else//应答
{
SCL = 0;
return(0);//返回0
}
}
void SendACK(bit i)
{
SCL = 0;//拉低时钟总线,允许主机控制SDA
if(i) //发非应答
SDA = 1;
else //发应答
SDA = 0;
SCL = 1; //拉高总线,让从机读SDA
delay5us();//保持5us
SCL = 0; //拉低时钟总线,允许SDA释放
SDA = 1;//释放数据总线
}
void I2cSendByte(uchar DAT)
{
uchar i;
for(i=0; i<8; i++) //分别写8次,每次写1位
{
SCL = 0;//拉低时钟总线,允许SDA变化
if(DAT & 0x80)//先写数据最高位
SDA = 1; //写1
else
SDA = 0; //写0
SCL = 1; //拉高时钟,让从机读SDA
DAT <<= 1; //为发送下一位左移1位
}
SCL = 0; //拉低时钟总线,允许SDA释放
SDA = 1;//释放数据总线
}
void At24c02Write(uchar ADDR, DAT)
{
I2cStart();//I2C起始信号
I2cSendByte(At24c02ADDR + I2cWrite);//发送器件地址加读写方向位
if(ReadACK()) //读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(ADDR);//发送储存单元地址字节
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(DAT);//发送一字节数据
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cStop(); //I2C停止信号
}
uchar I2cReadByte()
{
uchar i, DAT;
for(i=0; i<8; i++)//分别读8次,每次读一位
{
DAT <<= 1; //数据左移1位,准备接收一位
SCL = 0; //拉低时钟总线,允许从机控制SDA变化
SCL = 1; //拉高时钟总线,读取SDA上的数据
if(SDA)
DAT |= 0X01;//为1则写1,否则不行执行写1,通过左移补0
}
return(DAT); //返回读出的数据
}
uchar At24c02Read(uchar ADDR)
{
uchar DAT;
I2cStart();//I2C起始信号
I2cSendByte(At24c02ADDR + I2cWrite);//发送器件地址加读写方向位
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(ADDR);//I2C发送一个字节
ReadACK();//读从机应答
I2cStart();//再次产生I2C起始信号
I2cSendByte(At24c02ADDR + I2cRead);//发送器件地址加读写方向位 读
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
DAT = I2cReadByte();//读一字节
SendACK(1);//主机发送非应答
I2cStop(); //I2C停止信号
return(DAT);//返回读出数据
}
void main()//main函数自身会循环
{
timer0Init();//定时器0初始化
EA = 0;//屏蔽中断
At24c02Write(3, 188);//给第3单元写入数据“188”
delay(2);//延时等待AT24C02处理
num = At24c02Read(3);//读出第3单元内数据送给显示变量
if(AckFlag)//当从机非应答
P1 = 0;//亮P1所有灯
else
P1 = 0XFF;//灭P1所有灯
EA = 1;//开中断
while(1);
}
//定时器0中断函数
void timer0() interrupt 1
{
TH0 = 0xED;
TL0 = 0xFF; //定时5ms
display(num); //数码管显示函数
}

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)