#申请原创#
之前曾经在帖子中提过驱动DS1307日历模块时读出的数据不正确,当时以为是模拟I2C的时序问题,花费了3~4天时间反复调试都没有结果,只好先测试长短按键及滚轮编码器。今天再继续测试驱动DS1307日历模块,仔细分析代码及逻辑分析仪抓取的时序图,发现初始化DS1307设置日期时间的时候数据就不正确,从时序图上可以看出写入的并不是正确的数据,如下图所示:
读出的数据时序图与写入的基本一致(见下图),说明读数据基本正确,是写数据有问题:
于是进一步分析模拟I2C的写入函数,代码如下:
- /******************************************************************************************************************************************
- * 函数名称: I2C_Send()
- * 功能说明: 向IIC总线发送一个字节的数据
- * 输 入: byte dat 要发送的数据
- * 输 出: 无
- ******************************************************************************************************************************************/
- void SI2C_Send(uint8_t dat)
- {
- uint8_t i;
- SDA_OUT();
- SCL_0(); //拉低时钟开始数据传输
- for(i=0;i<8;i++)
- {
- if(((dat&0x80)>>7) == 1)
- SDA_1(); //准备好SDA数据
- else
- SDA_0();
- dat<<=1;
- <blockquote> DELAY_microseconds(2);
上述代码若有问题,则可能是这行if(((dat&0x80)>>7) == 1),
经过反复测试,发现这行代码并无问题,能正确判断,但优化成下面这样也行:
- if(dat&0x80)
- SDA_1(); //准备好SDA数据
- else
- SDA_0();
- dat<<=1;
代码优化后依旧写数据不正确,于是便想起之前测试LCD显示时遇到的数组指针传递不过去的问题,我原来是通过数组指针将要写入的日期时间数据存入在数组中,通过指针传递到模拟I2C的写函数中,代码如下:
SI2C_8bitBuffWrite(DS1307_ADDR,0,8,DS_Buff);
模拟I2C写入函数接收相关的参数:
uint8_t SI2C_8bitBuffWrite(uint8_t I2Caddr,uint8_t addr,uint8_t size,uint8_t *buff)
分析问题应该是出在此处,于是便修改为通过全局变量数组来传递,测试果然不出所料,能够正确地写入和读出数据了。下面是模拟I2C写入的代码:
- /**********************************************************************************************
- * 函数名称: SI2C_8bitBuffWrite()
- * 功能说明: 向I2C器件的地址addr开始写入size个字节的数据,将要写入的数据存储在全局变量数组I2C_Buff中
- * 输 入: uint8_t addr 数据被写入从addr开始的地址处
- * uint8_t size 要设置的数据个数(1~8)
- * 输 出: uint8_t 0= 成功 1=出现错误
- **********************************************************************************************/
- uint8_t SI2C_8bitBuffWrite(uint8_t I2Caddr,uint8_t addr,uint8_t size,uint8_t *buff)
- {
- uint8_t i = 0;
-
- SI2C_Start(); //产生起始信号
- SI2C_Send(I2Caddr|0); //发送从设备芯片地址及读写位,0表示写
- if(SI2CIsAck()) //检测从设备是否有响应
- {
- SI2C_Stop(); //产生停止信号
- return 1;
- }
- SI2C_Send(addr); //发送数据要写入的地址
- if(SI2CIsAck()) //检测从设备是否有响应
- {
- SI2C_Stop(); //产生停止信号
- return 2;
- }
- for(i=0;i<size;i++)
- {
- // SI2C_Send(buff[i]);
- SI2C_Send(DS_Buff[i]);
- if(SI2CIsAck()) //检测从设备是否有响应
- {
- SI2C_Stop(); //产生停止信号
- return 3;
- }
- }
- SI2C_Stop(); //产生停止信号
- return 0;
- }
这是测试过程的照片,用逻辑分析仪来抓取I2C的时序:
调试过程:
这是视频动画:
|