跪求DAC8571数模转换的方式
对于DAC8571的I2C通信问题始终无法解决(写入时序是这样的,开始、写入0x98、写入0x10、写入数据高位、写入数据低位、停止),就是说我发完DA芯片地址指令(1001 1000,即0x98)之后,接着应该在第九位将SDA拉高,等着DA芯片的应答,但是问题出现了,发现SDA无法拉高,后来经检查发现是由于DA芯片在第八个脉冲下降沿一到就立即就将SDA拉低了,导致单片机无法在第八个脉冲结束时将SDA拉起,当过了第九个脉冲之后,单片机就可以将SDA拉高了,这是什么原因呢?即使如此,如果我忽略这些,过了第九位之后,我接着发DA的控制指令(0x10),数据的高八位,低八位,转出的电压值也是不正确的,数字信号如图,
你好,
手册的13 14页开始,对这个每隔8个bit就会出现的ACK信号做了较为详细的描述。第一个ACK就是你说的强制拉低的信号,可以作为单片机判断是否与芯片联系上的信号。如果不想用这个功能,我个人认为直接忽略它即可,但要注意这个需要占用一个bit的时钟。
我确实也这么试过了,忽略ACK,把第九个脉冲放过去,也就是说在第九个脉冲上DA芯片不接收单片机给它的数据,等第九个脉冲结束之后,再接着发送下一个字节,但是即使如此,转换出来的电压值还是不对
你是用的是I/O口模拟的I2C吗?把程序上传看一下
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左右的样子
}
你好, 很多句没看懂。
while(SDA)
{}
这句是表达什么意思?
另外你能把整个I2C波形截图给我们看么? 因为手册上说不仅第九位,而且有18,27,36位都需要忽略,手册上并没有说那些位是拉低的。
等待总线释放SDA
对,是等待释放SDA,我现在的程序是每发完一个字节后用单片机将SDA拉高,其实是拉不高的,因为DA芯片已经强制将SDA拉低了,所以程序可以直接跳出while(SDA){},之后单片机也对SDA写0,这些过程都是发生在第八个脉冲之后第九个脉冲之前,接着是第九个脉冲,第九个脉冲的高电平对应的SDA的低电平,不过这个应该无所谓,因为第九个脉冲DA芯片应该是不接收SDA上的信号的吧。等第九个脉冲完了之后接着发送下一字节。
你的 init_DAC(void) 中起始条件将SDA和SCL均拉低,这个好像不太对,当总线稳定后主机将SDA拉低但同时保持SCL仍然是高电平表明发送数据开始
但是我看网上单片机模拟I2C通信的起始条件都这么写的啊,把SCL拉低是为了钳住I2C 总线准备发送或接收数据,如果不拉低的话发送数据第一个字节的第一位数据的时候,第一个脉冲的高电平(时长)在哪里体现?从起始条件到开始发送第一个字节的第一位数据SCL始终是高电平。例程见附件,
你好,芯片手册第16页是这么写的:
I2C protocol starts when the bus is idle, that is, when SDA and SCL lines are stable high. The master then pulls
the SDA line low while SCL is still high indicating that serial data transfer has started. This is called a start
condition, and can only be asserted by the master.
然后在初始化子函数里延迟一段时间后再将SCL拉低备用。
对啊,我就是在起始函数里这么做的啊,延迟了5个微秒之后再将SCL拉低备用(delay1circle(15); )
不好意思呵,只看了程序的上半截,下半截没注意到...对的你的程序时序看起来没问题,有一点你可以试一下呵,你在主程序中不停地对其进行初始化和写入,可能会导致其输出为0和你的配置的输出值来回切换,用万用表测试则其值很小你用示波器看一下
恩好的,我用示波器看一下,还有一个问题,如果我想连续转换一个变化的数字量呢?也就是说我可以将 init_DAC()和DA_convertor_start()放到主函数里,但只在进入主函数开头时调用一下这两个函数,并不放在while(1)主循环里面,while(1)主循环里面只用 WriteToDAC(unchar add) 函数往DA里写数据从而使DA芯片进行连续转换。这样可以吧?
这样是可以的,一次转换完成后若不进行下次转化且不复位则其输出会保持原来的转换值
刚才拿示波器看了一下,电压输出一直是0V左右。如下是整个周期的SDA和SCL的波形,三张图片依次排开看,发送时序为:开始,0x98,0x10,0xAA(数据的高8位),0xAA(数据低8位),停止。
暂时我也看不错哪里有问题,顶上去等牛人回复吧。不过你的示波器的信号为什么幅度那么小?才500mV?你是用10倍衰减的探头和5V的电源供电吗? MCU也是这个供电吗?
嗯对,经过10倍衰减了,其实每个脉冲的幅值是5V,我是把单片机引脚(SDA,SCL)输出方式设为漏极开路,然后接上拉电阻,上拉电压为5V.
我这里有一个用的是标准IIC控制DAC8571,你可以参考一下。我看你的程序是没有什么问题的,不知道为什么输出不正常。你可以写入后再读一下寄存器,看看是否正常写入了。
6443.21238846DAC8571.zip
嗯非常感谢,不过您给我的这个工程得用什么编译环境打开啊?您跟我说一下,我好安装一下。我这儿装的是Keil
你好这个是用IAR编译的,你使用记事本打开相应.c及.h文件即可。
你好 不知道关于DAC8571的问题你解决了吗,我现在也在做,电压输出也一直是0V,用的是模拟I2C
求代码
解决了吗
void DAC_config(void)
{
IIC_Send_Byte(0x98); // 1001 1000 д
while(IIC_Wait_Ack());
IIC_Send_Byte(0x00); // Store full scale data in temporary register
while(IIC_Wait_Ack());
}
void DAC_config1(void)
{
IIC_Send_Byte(0x98); // 1001 1000 д
while(IIC_Wait_Ack());
IIC_Send_Byte(0x20); // Update DAC8571 with the data previously stored in the temporary register
while(IIC_Wait_Ack());
}
void DAC_start(uint16_t data)
{
IIC_Start();
DAC_config();
IIC_Send_Byte((uint8_t) (data >> 8));
while(IIC_Wait_Ack());
IIC_Send_Byte((uint8_t)(data&0x00FF));
while(IIC_Wait_Ack());
delay_us(100);
IIC_Stop();
IIC_Start();
DAC_config1();
IIC_Send_Byte((uint8_t) (data >> 8));
while(IIC_Wait_Ack());
IIC_Send_Byte((uint8_t)(data&0x00FF));
while(IIC_Wait_Ack());
delay_us(100);
IIC_Stop();
}