单片机IO口模拟I2C时序驱动AT24C32

AT24C32和驱动和AT24C02基本一致。由于容量增加了,数据地址的地址由原来的8位也相应的增加到16位。

芯片 容量
AT24C01 128字节
AT24C02 256字节
AT24C04 512字节
AT24C08 1K字节
AT24C016 2K字节
AT24C0132 4K字节
AT24C064 8K字节
AT24C0128 16K字节
AT24C0256 32K字节
AT24C0512 64K字节

1字节 = 1 Byte

以下程序适用于上面型号的EEPROM芯片
使用22.1184MHz晶振、读出的数据送P0口显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#include "reg52.h" 
#include "intrins.h"

#define uchar unsigned char
#define uint unsigned int

sbit sda=P3^7;//;模拟I2C 数据
sbit scl=P3^6;//;模拟I2C 时钟

void delay1(uint z)//延时为 1ms

{
unsigned char a,b,i;
for(i=0;i<z;i++)
for(b=80;b>0;b--)
for(a=10;a>0;a--);
}


void delay()//5us延时
//22.1184误差 -0.1171875us
{
unsigned char a;
for(a=3;a>0;a--);
}
void star()//开始
{
sda=1;
delay();//5us延时
scl=1;
delay();//5us延时
sda=0;
delay();//5us延时

}

void stop()//停止
{
sda=0;
delay();//5us延时
scl=1;
delay();//5us延时
sda=1;
delay();//5us延时

}

void ack()//应答
{
uchar z=0;
while((sda==1)&&(z<50))z++;//条件判断, sda=1,则没有应答。如果没有应答则延时:z<50,z++;后返回
scl=0;
delay();//5us延时
}


void write(uchar slave_write_address,uchar byte_High_address,uchar byte_Low_address,uchar data_data)//写一个数据
{
uchar temp,temp1,i,ii;

star();//开始

for(ii=0;ii<4;ii++)//根据 24CXX文档资料,和时序图,按顺序送:器件写地址,字节地址,数据
{
if(ii==0)
{
temp=slave_write_address;//送 器件写地址
temp1=slave_write_address;
}
else if(ii==1)
{
temp=byte_High_address;//送 字节高地址
temp1=byte_High_address;
}
else if(ii==2)
{
temp=byte_Low_address;//送 字节低地址
temp1=byte_Low_address;
}
else if(ii==3)
{
temp=data_data;//送 数据
temp1=data_data;
}


for(i=0;i<8;i++)
{
scl=0;
delay();//5us延时
temp=temp1;
temp=temp&0x80;// 相 与 后,把不相关的位清零

if(temp==0x80)//根据前面 相 与 后,判断 temp是否等于0x80,是则该位为 1

sda=1;
else
sda=0;

delay();//5us延时
scl=1;
delay();//5us延时
scl=0;
delay();//5us延时
temp1=temp1<<1;//向左移出1位

}
sda=1;
delay();//5us延时
scl=1;
delay();//5us延时
ack();
}
stop();//停止
}



read(uchar slave_write_address,byte_High_address,byte_Low_address,uchar slave_read_address)//读一个数据
{
uchar temp,temp1,i,ii,x,data_data;

star();//开始

for(ii=0;ii<4;ii++)//根据 24CXX文档资料,和时序图,按顺序送:器件写地址,字节地址,器件读地址
{
if(ii==0)
{
temp=slave_write_address;//送 器件写地址
temp1=slave_write_address;
}
else if(ii==1)
{
temp=byte_High_address;//送 字节高地址
temp1=byte_High_address;
}
else if(ii==2)
{
temp=byte_Low_address;//送 字节低地址
temp1=byte_Low_address;
}
else if(ii==3)
{
star();//开始

temp=slave_read_address;//送 器件读地址
temp1=slave_read_address;
}



for(i=0;i<8;i++)//开始读数据
{
scl=0;
delay();//5us延时
temp=temp1;
temp=temp&0x80;// 相 与 后,把不相关的位清零

if(temp==0x80)//根据前面 相 与 后,判断 temp是否等于0x80,是则该位为 1

sda=1;
else
sda=0;

delay();//5us延时
scl=1;
delay();//5us延时
scl=0;
delay();//5us延时
temp1=temp1<<1;//向左移出1位
}
sda=1;
delay();//5us延时
scl=1;
delay();//5us延时
ack();//应答
}

for(x=0;x<8;x++)
{
data_data=data_data<<1;//向左移入1位

sda=1;
delay();//5us延时
scl=0;
delay();//5us延时
scl=1;
delay();//5us延时

if(sda==1)//判断 数据线是否是高电平
data_data|=0x01;//把读到的数据 或 0X01
//else
//data_data|=0x00;
}
ack();//应答
stop();//停止
return data_data;//返回读到的数据

}

void main()
{

write(0xa0,0x00,0x01,0xaa);//向器件写一个数据:
//(0xa0 是器件写地址;0x00 是字节高地址;0x01 是字节低地址;0x66 是待写入的数据)

delay1(5);//写与读的时间间隔应大于5ms,取决于器件 24C02的响应速度

//向器件读一个数据
//把读出的数据送 P1口显示
P0=read(0xa0,0x00,0x01,0xa1);//向器件读一个数据:
//(0xa0 是器件写地址;0x00 是字节高地址;0x01 是字节低地址;0xa1 是器件读地址)

while(1);//跳转,相当于汇编指令 JUMP $
}