对于DAC8571的I2C通信问题始终无法解决(写入时序是这样的,开始、写入0x98、写入0x10、写入数据高位、写入数据低位、停止),就是说我发完DA芯片地址指令(1001 1000,即0x98)之后,接着应该在第九位将SDA拉高,等着DA芯片的应答,但是问题出现了,发现SDA无法拉高,后来经检查发现是由于DA芯片在第八个脉冲下降沿一到就立即就将SDA拉低了,导致单片机无法在第八个脉冲结束时将SDA拉起,当过了第九个脉冲之后,单片机就可以将SDA拉高了,这是什么原因呢?即使如此,如果我忽略这些,过了第九位之后,我接着发DA的控制指令(0x10),数据的高八位,低八位,转出的电压值也是不正确的,数字信号如图,
MichaelSheep:
你好,
手册的13 14页开始,对这个每隔8个bit就会出现的ACK信号做了较为详细的描述。第一个ACK就是你说的强制拉低的信号,可以作为单片机判断是否与芯片联系上的信号。如果不想用这个功能,我个人认为直接忽略它即可,但要注意这个需要占用一个bit的时钟。
bo zhang9:
回复 MichaelSheep:
我确实也这么试过了,忽略ACK,把第九个脉冲放过去,也就是说在第九个脉冲上DA芯片不接收单片机给它的数据,等第九个脉冲结束之后,再接着发送下一个字节,但是即使如此,转换出来的电压值还是不对
Carter Liu:
回复 bo zhang9:
你是用的是I/O口模拟的I2C吗?把程序上传看一下
bo zhang9:
回复 Carter Liu:
void init_DAC(void) { SDA =1; _nop_(); SCL =1; //I2C bus is idle delay1circle(15); //起始条件建立时间大于4.7us,延时 SDA =0; //发送起始信号 delay1circle(15); //起始条件建立时间大于4us,延时 SCL =0; //serial data transfer has started _nop_(); _nop_();}//========终止DAC8571===================void DAC_Stop(){ SDA = 0; //发送结束条件的数据信号 _nop_(); SCL = 1; //发送结束条件的时钟信号 delay1circle(15); //结束条件建立时间大于4us,延时 SDA = 1; //发送I2C 总线结束信号 delay1circle(15);}
//========写DAC8571指令=================void WriteToDAC(unchar add) { // init_DAC(); //初始化DAC8571 unchar BitCnt; for (BitCnt=0; BitCnt<8; BitCnt++) //要传送的数据长度为8 位 { if((add<<BitCnt)&0x80) //判断发送位(从高位起发送) { SDA = 1; } else { SDA = 0; }
delay1circle(8); //等SDA稳定后再拉高SCL SCL = 1; //置时钟线为高通知被控器开始接收数据位 delay1circle(15); //保证时钟高电平周期大于4us SCL = 0; } SDA = 1; delay1circle(8); while(SDA) {} SDA = 0; SCL = 1; delay1circle(15); SCL = 0; delay1circle(8); _nop_(); _nop_();}//========启动DAC8571指令===============void DA_convertor_start(void){
WriteToDAC(0x98); //10011000 WriteToDAC(0x10); //00010000}//========DAC8571转换====================void DA_convertor(unint angle){ unchar data angle_H,angle_L; angle_H=(angle)&0xFF; angle<<=8; angle_L=(angle)&0xFF; init_DAC(); DA_convertor_start(); WriteToDAC(angle_H); WriteToDAC(angle_L);
delay1circle(60); //等待DAC8571进行转换 2013.11.1 DAC_Stop();}
main(){ while(1) { DA_convertor(0xFFFE); //单片机的其他设置,定义及其他无关功能函数在此省略,按这个情况,DAC应该输出5V左右电 } //压,但效果并不是如此,只是0.140V左右的样子 }
MichaelSheep:
回复 bo zhang9:
你好, 很多句没看懂。
while(SDA){}这句是表达什么意思?
另外你能把整个I2C波形截图给我们看么? 因为手册上说不仅第九位,而且有18,27,36位都需要忽略,手册上并没有说那些位是拉低的。
Carter Liu:
回复 MichaelSheep:
等待总线释放SDA
bo zhang9:
回复 Carter Liu:
对,是等待释放SDA,我现在的程序是每发完一个字节后用单片机将SDA拉高,其实是拉不高的,因为DA芯片已经强制将SDA拉低了,所以程序可以直接跳出while(SDA){},之后单片机也对SDA写0,这些过程都是发生在第八个脉冲之后第九个脉冲之前,接着是第九个脉冲,第九个脉冲的高电平对应的SDA的低电平,不过这个应该无所谓,因为第九个脉冲DA芯片应该是不接收SDA上的信号的吧。等第九个脉冲完了之后接着发送下一字节。
Carter Liu:
回复 bo zhang9:
你的 init_DAC(void) 中起始条件将SDA和SCL均拉低,这个好像不太对,当总线稳定后主机将SDA拉低但同时保持SCL仍然是高电平表明发送数据开始
bo zhang9:
回复 Carter Liu:
但是我看网上单片机模拟I2C通信的起始条件都这么写的啊,把SCL拉低是为了钳住I2C 总线准备发送或接收数据,如果不拉低的话发送数据第一个字节的第一位数据的时候,第一个脉冲的高电平(时长)在哪里体现?从起始条件到开始发送第一个字节的第一位数据SCL始终是高电平。例程见附件,
Carter Liu:
回复 bo zhang9:
你好,芯片手册第16页是这么写的:
I2C protocol starts when the bus is idle, that is, when SDA and SCL lines are stable high. The master then pullsthe SDA line low while SCL is still high indicating that serial data transfer has started. This is called a startcondition, and can only be asserted by the master.
然后在初始化子函数里延迟一段时间后再将SCL拉低备用。