热度 26
2012-9-6 00:43
4451 次阅读|
1 个评论
I2C、24C02的读写,这是个老掉牙了的问题,还有必要浪费时间来讨论吗?事情是这样,笔者在移植一个已经过验证、正确的24C32程序到《HDQ-51E》单片机学习板上、读写板上的24C02时,发现读写的过程总是很不稳定,一时无法判断是程序代码问题,还是电路故障问题,还是24C02芯片问题。经过了2天时间,最终确定是24C02芯片质量问题。更换了进口的ATMEL 24C02后,读写正常了。在此过程中,笔者编写了一些测试24C02的程序,发现这些代码也许适合单片机初学者用来学习I2C总线原理,并用来读写24C02存储器,因为这些代码更简单易用。 大家已经见过了很多有关I2C、24C02的单片机程序,为了实现对24C02的读写,一般都需要7、8个函数,甚至更多。其实,只需要4个函数(加上一个延时函数),就能很容易地实现I2C读写,见下: sbit SDA = P2^6; //管脚定义 sbit SCL = P2^7; //SCL时钟的频率对于正确操作E2很重要;一般地,频率要求100KHz。 void i2c_dly(void) { DelayNms(1); //ok } //IIC最基本的操作可以归结为下面4个函数:启始、停止、写、读 //IIC start void i2c_start(void) { SDA = 1; // i2c start bit sequence i2c_dly(); SCL = 1; i2c_dly(); SDA = 0; i2c_dly(); SCL = 0; i2c_dly(); } //IIC stop void i2c_stop(void) { SDA = 0; // i2c stop bit sequence i2c_dly(); SCL = 1; i2c_dly(); SDA = 1; i2c_dly(); } //IIC read //ack: 主机发送ACK位 unsigned char i2c_rx(char ack) { char x, d=0; SDA = 1; for(x=0; x8; x++) //读8个bit,高bit在前 { d = 1; //存储中间结果 do { SCL = 1; } while(SCL==0); //如果SCL被IIC设备拉低,则等待 i2c_dly(); if(SDA) d |= 1; //读取数据线 SCL = 0; } //发送ACK/NACK if(ack) SDA = 1; else SDA = 0; SCL = 1; i2c_dly(); // send (N)ACK bit SCL = 0; SDA = 1; return d; } //IIC write //d: 待发送字节,高位先发送 //返回:0 -- ACK, 1 -- NACK bit i2c_tx(unsigned char d) { char x; static bit b; for(x=8; x; x--) //发送8个bit { if(d0x80) SDA = 1; else SDA = 0; i2c_dly(); SCL = 1; i2c_dly(); d = 1; SCL = 0; i2c_dly(); } SDA = 1; SCL = 1; i2c_dly(); b = SDA; //读取ACK bit SCL = 0; i2c_dly(); return b; } 这4个函数完成最基本的I2C时序:起始、停止、写8bit、读8bit。通过对这4个函数合理组合,即可实现24C02的单字节读写,见附件例程。这是一个测试24C02是否有正确的ACK响应的程序,例子中的24C02设备地址为A0。 24C02读写时序图: 《HDQ-51E》51学习板: http://item.taobao.com/item.htm?spm=a1z10.1.11.5id=15769166730 。 欢迎加入单片机技术讨论QQ群:231033072,互相帮助、共同提高。 (待续) (本文最初发表于ENDCHINA,转载请注明出处,谢谢!)