[51单片机] EEPROM AT24c02 [存储\读取一个字节]
1 /*----------------------------------------------- 2 名称:IIC协议 EEPROM24c02 存数读取数据 3 内容:此程序用于检测EEPROM性能,测试方法如下:写入24c02一个数据,然后在内存中改变这些数据, 4 掉电后主内存将失去这些信息,然后从24c02中调入这些数据。看是否与写入的相同。这里用8个LED演示 5 函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作 一定的修改....(本例是1us机器 6 周期,即晶振频率要小于12MHZ) 7 ------------------------------------------------*/ 8 #include <reg52.h> //头文件的包含 9 #include <intrins.h> 10 11 #define _Nop() _nop_() //定义空指令 12 // 常,变量定义区 13 sbit SDA=P2^1; //模拟I2C数据传送位 14 sbit SCL=P2^0; //模拟I2C时钟控制位 15 16 bit ack; //应答标志位 17 18 void DelayUs2x(unsigned char t);//函数声明 19 void DelayMs(unsigned char t); 20 /*------------------------------------------------ 21 uS延时函数,含有输入参数 unsigned char t,无返回值 22 unsigned char 是定义无符号字符变量,其值的范围是 23 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时 24 长度如下 T=tx2+5 uS 25 ------------------------------------------------*/ 26 void DelayUs2x(unsigned char t) 27 { 28 while(--t); 29 } 30 /*------------------------------------------------ 31 mS延时函数,含有输入参数 unsigned char t,无返回值 32 unsigned char 是定义无符号字符变量,其值的范围是 33 0~255 这里使用晶振12M,精确延时请使用汇编 34 ------------------------------------------------*/ 35 void DelayMs(unsigned char t) 36 { 37 38 while(t--) 39 { 40 //大致延时1mS 41 DelayUs2x(245); 42 DelayUs2x(245); 43 } 44 } 45 46 /*------------------------------------------------ 47 启动总线 48 ------------------------------------------------*/ 49 void Start_I2c() 50 { 51 SDA=1; //发送起始条件的数据信号 52 _Nop(); 53 SCL=1; 54 _Nop(); //起始条件建立时间大于4.7us,延时 55 _Nop(); 56 _Nop(); 57 _Nop(); 58 _Nop(); 59 SDA=0; //发送起始信号 60 _Nop(); //起始条件锁定时间大于4μ 61 _Nop(); 62 _Nop(); 63 _Nop(); 64 _Nop(); 65 SCL=0; //钳住I2C总线,准备发送或接收数据 66 _Nop(); 67 _Nop(); 68 } 69 /*------------------------------------------------ 70 结束总线 71 ------------------------------------------------*/ 72 void Stop_I2c() 73 { 74 SDA=0; //发送结束条件的数据信号 75 _Nop(); //发送结束条件的时钟信号 76 SCL=1; //结束条件建立时间大于4μ 77 _Nop(); 78 _Nop(); 79 _Nop(); 80 _Nop(); 81 _Nop(); 82 SDA=1; //发送I2C总线结束信号 83 _Nop(); 84 _Nop(); 85 _Nop(); 86 _Nop(); 87 } 88 89 90 91 92 /*---------------------------------------------------------------- 93 字节数据传送函数 94 函数原型: void SendByte(unsigned char c); 95 功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 96 此状态位进行操作.(不应答或非应答都使ack=0 假) 97 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 98 ------------------------------------------------------------------*/ 99 void SendByte(unsigned char c) 100 { 101 unsigned char BitCnt; 102 103 for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位 104 { 105 if((c<<BitCnt)&0x80)SDA=1; //判断发送位 106 else SDA=0; 107 _Nop(); 108 SCL=1; //置时钟线为高,通知被控器开始接收数据位 109 _Nop(); 110 _Nop(); //保证时钟高电平周期大于4μ 111 _Nop(); 112 _Nop(); 113 _Nop(); 114 SCL=0; 115 } 116 117 _Nop(); 118 _Nop(); 119 SDA=1; //8位发送完后释放数据线,准备接收应答位 120 _Nop(); 121 _Nop(); 122 SCL=1; 123 _Nop(); 124 _Nop(); 125 _Nop(); 126 if(SDA==1)ack=0; 127 else ack=1; //判断是否接收到应答信号 128 SCL=0; 129 _Nop(); 130 _Nop(); 131 } 132 /*---------------------------------------------------------------- 133 字节数据传送函数 134 函数原型: unsigned char RcvByte(); 135 功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号), 136 发完后请用应答函数。 137 ------------------------------------------------------------------*/ 138 unsigned char RcvByte() 139 { 140 unsigned char retc; 141 unsigned char BitCnt; 142 143 retc=0; 144 SDA=1; //置数据线为输入方式 145 for(BitCnt=0;BitCnt<8;BitCnt++) 146 { 147 _Nop(); 148 SCL=0; //置时钟线为低,准备接收数据位 149 _Nop(); 150 _Nop(); //时钟低电平周期大于4.7us 151 _Nop(); 152 _Nop(); 153 _Nop(); 154 SCL=1; //置时钟线为高使数据线上数据有效 155 _Nop(); 156 _Nop(); 157 retc=retc<<1; 158 if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中 159 _Nop(); 160 _Nop(); 161 } 162 SCL=0; 163 _Nop(); 164 _Nop(); 165 return(retc); 166 } 167 168 169 170 /*---------------------------------------------------------------- 171 应答子函数 172 原型: void Ack_I2c(void); 173 ----------------------------------------------------------------*/ 174 void Ack_I2c(void) 175 { 176 177 SDA=0; 178 _Nop(); 179 _Nop(); 180 _Nop(); 181 SCL=1; 182 _Nop(); 183 _Nop(); //时钟低电平周期大于4μ 184 _Nop(); 185 _Nop(); 186 _Nop(); 187 SCL=0; //清时钟线,钳住I2C总线以便继续接收 188 _Nop(); 189 _Nop(); 190 } 191 /*---------------------------------------------------------------- 192 非应答子函数 193 原型: void NoAck_I2c(void); 194 ----------------------------------------------------------------*/ 195 void NoAck_I2c(void) 196 { 197 198 SDA=1; 199 _Nop(); 200 _Nop(); 201 _Nop(); 202 SCL=1; 203 _Nop(); 204 _Nop(); //时钟低电平周期大于4μ 205 _Nop(); 206 _Nop(); 207 _Nop(); 208 SCL=0; //清时钟线,钳住I2C总线以便继续接收 209 _Nop(); 210 _Nop(); 211 } 212 /*---------------------------------------------------------------- 213 向无子地址器件发送字节数据函数 214 函数原型: bit ISendByte(unsigned char sla,ucahr c); 215 功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla. 216 如果返回1表示操作成功,否则操作有误。 217 注意: 使用前必须已结束总线。 218 ----------------------------------------------------------------*/ 219 /*bit ISendByte(unsigned char sla,unsigned char c) 220 { 221 Start_I2c(); //启动总线 222 SendByte(sla); //发送器件地址 223 if(ack==0)return(0); 224 SendByte(c); //发送数据 225 if(ack==0)return(0); 226 Stop_I2c(); //结束总线 227 return(1); 228 } 229 */ 230 231 /*---------------------------------------------------------------- 232 向有子地址器件发送多字节数据函数 233 函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no); 234 功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件 235 地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。 236 如果返回1表示操作成功,否则操作有误。 237 注意: 使用前必须已结束总线。 238 ----------------------------------------------------------------*/ 239 bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no) 240 { 241 unsigned char i; 242 243 Start_I2c(); //启动总线 244 SendByte(sla); //发送器件地址 245 if(ack==0)return(0); 246 SendByte(suba); //发送器件子地址 247 if(ack==0)return(0); 248 249 for(i=0;i<no;i++) 250 { 251 SendByte(*s); //发送数据 252 if(ack==0)return(0); 253 s++; 254 } 255 Stop_I2c(); //结束总线 256 return(1); 257 } 258 259 /*---------------------------------------------------------------- 260 向无子地址器件读字节数据函数 261 函数原型: bit IRcvByte(unsigned char sla,ucahr *c); 262 功能: 从启动总线到发送地址,读数据,结束总线的全过程,从器件地 263 址sla,返回值在c. 264 如果返回1表示操作成功,否则操作有误。 265 注意: 使用前必须已结束总线。 266 ----------------------------------------------------------------*/ 267 /*bit IRcvByte(unsigned char sla,unsigned char *c) 268 { 269 Start_I2c(); //启动总线 270 SendByte(sla+1); //发送器件地址 271 if(ack==0)return(0); 272 *c=RcvByte(); //读取数据 273 NoAck_I2c(); //发送非就答位 274 Stop_I2c(); //结束总线 275 return(1); 276 } 277 278 */ 279 /*---------------------------------------------------------------- 280 向有子地址器件读取多字节数据函数 281 函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no); 282 功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件 283 地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。 284 如果返回1表示操作成功,否则操作有误。 285 注意: 使用前必须已结束总线。 286 ----------------------------------------------------------------*/ 287 bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no) 288 { 289 unsigned char i; 290 291 Start_I2c(); //启动总线 292 SendByte(sla); //发送器件地址 293 if(ack==0)return(0); 294 SendByte(suba); //发送器件子地址 295 if(ack==0)return(0); 296 297 Start_I2c(); 298 SendByte(sla+1); 299 if(ack==0)return(0); 300 301 for(i=0;i<no-1;i++) 302 { 303 *s=RcvByte(); //发送数据 304 Ack_I2c(); //发送就答位 305 s++; 306 } 307 *s=RcvByte(); 308 NoAck_I2c(); //发送非应位 309 Stop_I2c(); //结束总线 310 return(1); 311 } 312 /*------------------------------------------------ 313 主函数 314 ------------------------------------------------*/ 315 void main() 316 { 317 unsigned char doflye; // 定义临时变量 318 unsigned char i; 319 320 IRcvStr(0xae,4,&doflye,1); //调用存储数据 321 322 while(1) 323 { 324 P1=doflye; //数值用二进制显示,直接用8个LED表示 325 for(i=0;i<5;i++) 326 DelayMs(200); 327 doflye++; //1s钟变量自加1,改变值后存储到24c02 328 //下次开机时将显示当前数值 329 ISendStr(0xae,4,&doflye,1); //写入24c02 330 } 331 }
除了上面的p2.0和p2.1要连外还要把p1的8个脚和灯相连