Y_G_G 发表于 2019-8-3 16:22 感谢你的耐心回复喔!不准备纠结这个问题了,感觉还是我买的芯片有问题,后面有机会再换换芯片试试 |
cjm82 发表于 2019-8-4 02:32 好的,thank you!! |
Y_G_G 发表于 2019-8-3 16:22 我在面包板上接了两个AT24C02也试了下的,两片AT24C02芯片的硬件地址A0A1A2设置为不同,我在程序上分别向两块芯片发送数据,也是上面那种现象,A0A1A2随意改变,都能向芯片正确写入数据,并且正确读出。 同时我又发现一个诡异的现象,就是向第一块芯片的一个固定地址(程序里我选的储存地址是0x01,比如写个数据为0x27)写入数据,但是我没有向第二块芯片的储存地址0x01写入数据,接下来我直接读第二块芯片储存地址0x01里的数据,读出来的数据居然和我刚刚向第一块芯片储存地址0x01写入的数据相同(为了避免巧合我多次改变向第一块芯片写入的数据,发现实验现象和上面相同),也就是在向一块芯片写入数据时,两块芯片的相同储存地址里的内容都被写入数据了(A0A1A2随意改变也是这样)。 |
张松松 发表于 2019-7-30 14:05 #define SCK_High GPIO_SetBits(GPIOA,GPIO_Pin_1) #define SCK_Low GPIO_ResetBits(GPIOA,GPIO_Pin_1) #define SDA_High GPIO_SetBits(GPIOA,GPIO_Pin_3) #define SDA_Low GPIO_ResetBits(GPIOA,GPIO_Pin_3) #define SCK_read GPIOA->IDR & GPIO_Pin_1 #define SDA_read GPIOA->IDR & GPIO_Pin_3 typedef enum { FALSE = 0, TRUE = !FALSE } bool; void I2C_delay() { u8 i=100; while(i) { i--; } } bool I2C_Start() { SDA_High; SCK_High; I2C_delay(); if(!SDA_read) { return FALSE; //SDA线为低电平则总线忙,退出 } SDA_Low; I2C_delay(); if(SDA_read) { return FALSE; //SDA线为高电平则总线出错,退出 } SDA_Low; I2C_delay(); return TRUE; } void I2C_Stop() { SCK_Low; I2C_delay(); SDA_Low; I2C_delay(); SCK_High; I2C_delay(); SDA_High; I2C_delay(); } void I2C_Ack() { SCK_Low; I2C_delay(); SDA_Low; I2C_delay(); SCK_High; I2C_delay(); SCK_Low; I2C_delay(); } void I2C_NoAck() { SCK_Low; I2C_delay(); SDA_High; I2C_delay(); SCK_High; I2C_delay(); SCK_Low; I2C_delay(); } bool I2C_WaitAck() //返回TRUE有ACK,FALSE无ACK { SCK_Low; I2C_delay(); SDA_High; I2C_delay(); SCK_High; I2C_delay(); if(SDA_read) { SCK_Low; return FALSE; } SCK_Low; return TRUE; } void I2C_SendByte(u8 SendByte) //数据从高位到低位// { u8 i=8; while(i--) { SCK_Low; I2C_delay(); if(SendByte&0x80) { SDA_High; } else { SDA_Low; } SendByte<<=1; I2C_delay(); SCK_High; I2C_delay(); } SCK_Low; } u8 I2C_ReadByte(void) //数据从高位到低位// { u8 i=8; u8 data=0; SDA_High; while(i--) { data<<=1; SCK_Low; I2C_delay(); SCK_High; I2C_delay(); if(SDA_read) { data|=0x01; } } SCK_Low; return data; } //===================24C02 读写程序=========================== bool AT24C02_WriteByte(u8 SendByte, u8 Address) { if(!I2C_Start()) { return FALSE; } I2C_SendByte(0xa0); if(!I2C_WaitAck()) { I2C_Stop(); return FALSE; } I2C_SendByte(Address); I2C_WaitAck(); I2C_SendByte(SendByte); I2C_WaitAck(); I2C_Stop(); Delay(15); //加个延时等待写完 return TRUE; } bool AT24C02_ReadByte(u8* data,u8 Adress) { if(!I2C_Start()) //如果总线忙,则返回失败. return FALSE; I2C_SendByte(0xa0); if(!I2C_WaitAck()) //如果没有得到应答,则返回失败. { I2C_Stop(); return FALSE; } I2C_SendByte(Adress); I2C_WaitAck(); I2C_Start(); I2C_SendByte(0xa1); I2C_WaitAck(); *data = I2C_ReadByte(); I2C_Stop(); return TRUE; } 这个是我以前学I2C时的程序,和24C02的程序,不过是32的,你稍微改下,用在51也很简单,24C02的两个函数也就学习的时候用过下,后面基本没碰过.但前面的I2C程序我用过好几次,没发现问题.你可以参考下. |
硬件电路上传看一下了 |
张松松 发表于 2019-8-3 10:09 你能写入和读取,就说明读写的函数是正确的了 A0 A1 A2 这几个位在多个24C02并联使用时才会用到的,在24C02中,你只能改动R/W位,其它位是不能动的,1010是固定不变的,A0 A1 A2 这个是和24C02三个引脚的逻辑对应的,你接地了,就是000了,不能改,改了就找不到地址了 如果你是A0接了高电平,那么这三个应该就是:100 |
Y_G_G 发表于 2019-7-31 08:41 对了,我用的芯片型号是,ATMEL 711 24C02 PU27 D |
Y_G_G 发表于 2019-7-31 08:41 你好,我用程序验证时,在I2C总线上只用一个AT24C02芯片,用的模拟I2C通讯;先写入一个数据到一个固定的地址,然后读取并显示在数码管上,下载运行时发现读取的结果正常,断电再上电,结果依然正常,然后去掉写入数据程序部分,只留下读取数据程序部分,再下载到开发板,发现读取的数据还是和之前写入的一样,断电再上电,读取结果依然正常,<<同时我又尝试将发送的器件地址改变,仅改变A0/A1/A2三位的数值,使它和硬件上连接的地址不相同,我开发板上的AT24C02芯片的A0A1A2都接地了的,重复上面的验证过程,发现结果还是一样,写入的数据和读取的数据相同, 但是 “将器件地址的高四位,也就是AT24C02固定的那四位1010, 1010 A0 A1 A2 R/W 也改变的话,就会读取和写入失败。” >> |
芯片有问题的情况并不多 你得写一个验证的程序,两个按键:写入并显示,读取并显示,地址可以是固定的某个地址 先向一个地址写入一个数据并显示 然后,断电,开机,不要写入,直接读取,数据是对的话,你的IIC代码就是对的 验证好程序之后,其它的再说 |
yzwzfyz 发表于 2019-7-26 09:18 不能确定是不是目标设备发出的0/1, 我总线上就用了一个AT24C02芯片,这样是不是可以怀疑是芯片有问题 |
cjm82 发表于 2019-7-25 21:58 /** * @brief 主机检测从机应答 * @param none * @retval return(1)应答,return(0)非应答 */ bit Test_ACK() { SCL=1; //拉高SCL线 Delay_5us(); if(SDA==1) //如果为1,则非应答 { SCL=0; //拉低SCL线,使SDA线可以发送停止信号 _nop_(); I2C_Stop(); //发送停止信号 return (0); //非应答 } else { SCL=0; //拉低SCL线 _nop_(); return (1); //应答 } } 应答程序部分就是这样写的,随便发个设备地址(A0A1A2三个引脚都接地了的),发现SDA都会被拉低。 |
当你序读取每一位的时候,总会认定的一个值,非0即1! 只不过读到的0/1是不是“目标设备”发出来的,就不好说了。 |
看看你程序里应答部分是怎么写的 |