以前在大学时候研究过iic,参照的是郭天祥的视频教程,把at24c02里面的数据读写完成之后就没深入研究了,而是作为一个子程序封装来用了。
最近研究rda5802时候参考挪用了一个论坛一坛友的代码,后来据说是伟纳的工程师放出来的代码,呵呵偏题了。
我发现用如下的代码读at24c02时候总是出错,比如我的某个但愿存的是bcd码01,但是读出来就是03,我参考at24c02的官方pdf,然后参考如下代码段,就产生疑问了,望坛友们不吝赐教,谢谢
代码
#include <intrins.h>
#define I2C_ACK 1
#define I2C_NACK 0
#define uchar unsigned char
#define uint unsigned int
//#define AT24c02
extern unsigned char RDA_reg_data[8];
sbit SDA = P3^6;
sbit SCL = P3^7;
void I2C_start()
{
SDA = 1;
SCL = 1;
_nop_();_nop_();_nop_();
SDA = 0;
_nop_();_nop_();_nop_();
SCL = 0;
}
void I2C_stop()
{
SDA = 0;
SCL = 1;
_nop_();_nop_();_nop_();
SDA = 1;
_nop_();_nop_();_nop_();
}
// 发送一个字节子程序
unsigned char I2C_write_byte(unsigned char indata)
{
unsigned char i, ack;
// I2C 发送8 位数据
for (i=0; i<8; i++)
{
// 高在前低在后
if (indata & 0x80)
SDA = 1;
else
SDA = 0;
// 发送左移一位
indata <<= 1;
_nop_();_nop_();_nop_();
SCL = 1;
_nop_();_nop_();_nop_();
SCL = 0;
}
// 设置SDA为输入
SDA =1;
_nop_();_nop_();_nop_();
// 读取从机应答状态
SCL = 1;
_nop_();_nop_();_nop_();
if(SDA) //为什么?一个是uchar一个是bit,返回一个ack值有什么意义呢??? ack = I2C_NACK; else ack = I2C_ACK; SCL = 0;
return ack;
}
// 读一个字节子程序
unsigned char I2C_read_byte(unsigned char ack)
{
unsigned char i, out_data = 0;
SDA = 1; // SDA 设置输入方向
// I2C 接收8位数据
for(i = 8; i > 0; i--)
{
out_data <<= 1;
SCL = 1;
_nop_();_nop_();_nop_();
// 高在前低在后
if (SDA)
out_data++;
SCL = 0;
_nop_();_nop_();_nop_();
}
// 主机发送应答状态
if(ack == I2C_ACK) //pdf所示的时序中没有对sda进行操作啊,为什么这儿进行了,并且时序还不一致 SDA = 0; else SDA = 1; _nop_();_nop_();_nop_();
SCL = 1;
_nop_();_nop_();_nop_();
SCL = 0;
return out_data;
}
问题结症是我在读多字节读操作中读完最后一个字节后主机没有向从机发送无应答信号NACK,导致错误。发送应答信号后一切正常。但是此处还有个小疑问:最后一个自己结束后我就发了stop()信号,按道理我已经读到正确值了,上述问题到底怎么得来的。void IIC_ser_read(uchar chip_add,uchar firstadd ,uchar length ,uchar getadd,uchar *aim){ I2C_start(); //启动总线 I2C_write_byte(chip_add & 0xfe); //发送器件地址 I2C_write_byte(firstadd); //发送器件子地址 I2C_start(); //启动总线 I2C_write_byte(chip_add | 0x01); //发送器件读地址
length -= 1; while(length) { aim[getadd] = I2C_read_byte(I2C_ACK); getadd += 1; length -= 1; } aim[getadd] = I2C_read_byte(I2C_NACK);//原来就是这个非应答信号没有,所以失败 I2C_stop();} [ 此帖被younges在2011-10-30 14:05重新编辑 ]