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; x<8; 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(d&0x80) 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.5&id=15769166730。
欢迎加入单片机技术讨论QQ群:231033072,互相帮助、共同提高。
(待续)
(本文最初发表于ENDCHINA,转载请注明出处,谢谢!)
用户1508872 2014-3-7 23:19
用户913991 2012-6-25 14:37
用户403664 2012-6-25 08:51