📄 tt.c
字号:
/*
2.1 接口特性
I2C总线接口的数据线SDA和时钟线SCL必须经过上拉电阻接到正电源VDD上,各个I2C接口电路输出端必须是漏极开路或集电极
开路,以便完成“线与”的功能。I2C的SDA和SCL都是双向传输线,当总线空闲时,此两线都是“1”(高电平)。由于不同的器
件都会接到I2C总线,逻辑的“0”(低)及“1”(高)的信号电平取决于VDD的电压。总线上能连接的最大器件数取决于其电容
容限400PF。
2.2 I2C总线上的传输时序
I2C总线上每传输一位数据都有一个时钟脉冲相对应,在标准模式下可达100 kbit/s,高速模式下可达400kbit/s,总线上
依据器件功能不同可建立简单的主/从关系(master/slave),只有带CPU的器件才可成主控器。图1为I2C总线一次完整的数据
传输。SCL为高期间,SDA状态必须稳定,SCL为低时才允许SDA状态变化。SCL保持高电平期间,SDA出现由高至低的转换将启动I2C
总线,出现由低至高的转换将停止数据传输。起始和终止信号通常由主控器产生。I2C总线的信号时序有严格规定,本应用采用标
准模式,SCL低电平周期≥4.7μs,SCL高电平周期≥4.0μs,START和STOP之间的总线空闲时间≥4.7μs。
I2C 总线上传送的每个字节必须为8位,启动和停止之间可传输的数据字节数不受限制。采用串行传送,首先传送最高位,每
传送一个字节后必须跟一个应答位。主控器产生应答所需的时钟脉冲期间,发送器必须释放数据线(SDA为高),以便接收器输出
应答位。低电平为应答信号,高电平为非应答信号。非应答信号是当主控器作为接收器时,收到最后一个字节数据后,必须发送
一个非应答信号给被控发送器,使被控发送器释放数据线,以便主控器发停止信号,终止数据传送。当从器件不能再接收字节时
也会出现非应答信号这种情况。
I2C总线上的器件一般有两个地址:受控地址和通用广播访问地址,每个器件有唯一的受控地址用于定点通信,而相同的通用
广播访问地址则用于主控方同时对所有器件进行访问。如图1所示,起始信号后主控器发送的第一个字节就是被读器件的受控地址,
称作寻址字节。寻址字节由高7位地址和最低1位方向位组成,方向位为“0”表明主控器对被控器的写操作(W),方向位为 “1”
表明对被控器的读操作(R)。总线上每个器件在起始信号后都把自己的地址与寻址字节的前7位相比较,如相同则器件被选中,
产生应答,并根据读写位决定在数据传送中是接收还是发送。无论是主发、主收还是从发、从收,都是由主器件控制,数据传送完后,
主控器都必须发停止信号。
*/
#include<reg51.h>
#include <intrins.h>
#define unchar unsigned char
#define nop() _nop_()
sbit scl=P2^0;
sbit sda=P2^1;
sbit WP=P2^2;
void delayx(unchar x,unchar y)
{
unchar i,j,k;
if(y==0){for(i=0;i<x;i++);}
if(y==1)
{
for(i=0;i<x;i++)
{
for(j=0;j<40;j++)
for(k=0;k<100;k++);
}
}
}
void Start() //时钟线保持高,数据线从高到低一次跳变,I2C通信启动
{
sda=1;
scl=1; //SCL高电平周期≥4.0μs
nop();nop();nop();nop();nop();
sda=0;
nop();nop();
scl=0; // SCL低电平周期≥4.7μs
nop();nop();nop();nop();nop();
}
void Stop() //时钟线保持高,数据线从低到高一次跳变,I2C通信停止
{
sda=0;
scl=1;
nop();nop();nop();nop();nop();
sda=1;
nop();nop();nop();nop();
}
void writex(unchar j) //时钟线从高电平到低电平一次跳变则写入一个字节
{
unchar i,temp;
temp=j;
for (i=0;i<8;i++)
{
sda=temp&0x80;
temp=temp<<1;
scl=1;
nop();nop();nop();nop();nop();
scl=0;
nop();nop();nop();nop();nop();
}
}
unchar readx() //时钟线从低电平到高电平一次跳变则开始读取一个字节
{
unchar i,j,k=0;
for (i=0;i<8;i++)
{
scl=0;
nop();nop();nop();nop();nop();
scl=1;
nop();nop();nop();nop();nop();
if (sda==1) j=1;
else j=0;
k=(k<<1)|j;
//nop();nop();
//scl=0;
}
return(k);
}
/*//函数说明:私有函数,I2C专用,等待从器件接收方的应答
WaitAck(void)
{
unsigned char errtime=255;//因故障接收方无ACK,超时值为255。
SDA=1;
SCL=1;
SystemError=0x10;
while(SDA)
{
errtime--;
if(!errtime)
{
AD7416_I2CStop();
AD7416_SystemError=0x11; //出错后给全局变量赋值
return;
}
}
SCL=0;
}
//函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,应答信号。
void SendAck(void)
{
SDA=0; SomeNOP(); //数据线保持低,时钟线发生一次从高低的跳变 发送一个应答信号
SCL=1; SomeNOP();
SCL=0;
}
//函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,非应答信号。
void SendNotAck(void)
{
SDA=1; SomeNOP(); //数据线保持高,时钟线发生一次从高低的跳变 没有应答
SCL=1; SomeNOP();
SCL=0;
}*/
void ack() //I2C总线时钟
{
unchar i=0;
scl=1;
nop();nop();nop();nop();nop();
//while ((sda==1)&&(i<255))i++;
scl=0;
nop();nop();nop();nop();nop();
}
//数据块读取函数
void x24c02_read(unchar Data[],unchar Address,unchar Num)
{
unchar i;
unchar *PData;
PData=Data;
for(i=0;i<Num;i++)
{
Start();
writex(0xa0); //发送写信号
ack();
writex(Address+i);
ack();
Start();
writex(0xa1); //发送读信号
ack();
*(PData+i)=readx();
Stop();
}
}
//数据块写入函数
void x24c02_write(unchar Data[],unchar Address,unchar Num)
{
unchar i;
unchar *PData;
PData=Data;
for(i=0;i<Num;i++)
{
Start();
writex(0xa0);//发送写信号
ack();
writex(Address+i);//发送地址
ack();
writex(*(PData+i));
ack();
Stop();
delayx(50,0);
}
}
void main(void)
{
unchar n,AData[16],Number[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};//{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; //字形码0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
WP=0;
x24c02_write(Number,0,16);//参数格式:数据指针,存储地址,存储字节数
delayx(20,0);
x24c02_read(AData,0,16);//参数格式:数据指针,存储地址,存储字节数]
P0=0;delayx(50,1);
for(n=0;n<16;n++)
{
P0=AData[n];
delayx(50,1);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -