一个项目需要用到四路DAC,STM32内置2路DAC,当然,也可以使用PWMDAC的方法得到。考虑使用环境比较恶劣,尽量都使用的集成芯片,以及快速开发。这里我选用了ADI的AD5304,因为对精度要求不高,所以八位DAC也足够使用要求。如果需要更高精度的,它和AD5314(十位)以及AD5324(十二位)可以Pin To Pin替换。
接下来就是苦逼的煎熬模式了,其他的功能都还算顺利的调试完成。只有AD5304有问题,数据一直出不来。有时出来了却不是我设置的值。我反复对照Datasheet中的时序图,就是下面这货。
很明显,每次传输的数据是16Byte,在发送数据之前,CS(SYNC)先要给个下降沿信号(先拉高再拉低),注意,是保持拉低状态,然后DIN数据在每个SCLK的时钟信号的下降沿时将数据发送给AD5304,在16位数据发送结束后,将片选CS(SYNC)置高(置低亦可).到这里都很正常,毕竟ADI是个大公司,而且这样符合SPI的时序。很简单嘛,感觉分分钟就可以写好。
OK,具体每个位的数据是什么意思呢?这个在Datasheet中也有介绍。如下:
可以看到,AD53X4系列的控制方式也很类似,只是有效的数据位不同。这个图可以看的很明白,最高位(bit15)是要设置的通道的高位,bit14是通道的地位,接下来是两个位的说明是这样的。。。
PD是是否使能的管脚,LDAC是只让所设置的通道置数还是要四个通道同时置数。剩下的就是设置的数据位。也很简单明了,还是感觉可以分分钟解决掉。
接下来就是配置STM32的对应管脚,由于STM32自带的两个SPI有别的器件的操作,所以我使用的是模拟SPI,而且也挺简单,完全可以很快实现功能。
下面, 好戏开始了。
驱动程序写好了,烧进去,量输出电压(我设置的是最大值,也没用2.5V的基准.直接就是3.3V的电压简单处理下,毕竟精度要求并不高),值不对!!!什么鬼,写错了?
我反复看了几遍,又对着资料看了很多遍,就是不对,哪的问题??不晓得嘛。怎么办~~~~~~~
就这样,弄了两个晚上。找不到原因,难道是因为我没钱贪便宜买的拆机货的缘故?真的是便宜没好货吗?
各种测试,各种猜测实验。
完全感觉要绝望鸟。
到这时候我都没怀疑过回事资料不对,毕竟 ADI啊,这么大一公司,而且是老外搞的,我觉得肯定都是一丝不苟的工作,肯定不会忽悠人,乱标参数。我也从网上那乱七八糟的各种卖芯片的链接中找到一个官方的使用的一个配置,虽然用的单片机不一样,但是驱动看了是类似的,没写错。
在我深深怀疑是芯片问题的时候,偶然的,死马当活马医,我试着改了下PD和LDAC的值。奇迹出现了,输出数据对了!!
我改的是让PD=1,LDAC=0,这样输出的每个通道都正常。这里,有人也许要问,那LDAC=1时肯定也有输出,只是输出四个通道都应该是一样的吧,事实是并没有,输出的数据都是错误的,具体什么问题我也就不管了,目的是尽快将项目结掉,人家做的片子可以用就可以了。不求甚解嘛。。。
废话辣么多,下面贴代码,有需要的可以看看,别在吭哧吭哧的像我似的瞎搞。附件是同样的文件。
#define AD5304_SCLK PBout(6)
#define AD5304_CS PBout(7)
#define AD5304_MOSI PBout(5)
void AD5304_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);//根据设定参数初始化GPIOB.5
// AD5304_SCLK = 1;
// AD5304_CS = 1;
DAC_OutOff();
}
void AD5304_ValueSet(u8 adc_address, u8 _dac_data)
{
u8 i;
u16 dacdata_now = 0;
u16 addess_now = 0;
dacdata_now = ((u16)_dac_data)<<4;//A1 A0 /PD /LDAC D7 D6 D5 D4 D3 D2 D1 D0 0 0 X X
addess_now = ((((u16)adc_address)<<2) | 0x0002) << 12;
dacdata_now = addess_now | dacdata_now; //要发送的数据
AD5304_SCLK = 0; //SPI_CLK=0;
delay_us(10);
AD5304_CS = 1; //CS=1
delay_us(10);
AD5304_CS = 0; //CS=0,此处下降沿将激活CLK和DI
delay_us(10);
for(i=0;i<16;i++)
{
if((dacdata_now << i) & 0x8000)
{
AD5304_MOSI = 1;//SPI_DI=1;
}
else
{
AD5304_MOSI = 0;//SPI_DI=0;
}
AD5304_SCLK = 1;//SPI_CLK=1;
delay_us(10);
AD5304_SCLK = 0;//SPI_CLK=0;
delay_us(10);
}
AD5304_CS = 1; //CS=1
delay_us(100);
}
void DAC_OutOff(void) //输出DAC为0,即关闭
{
AD5304_ValueSet(0x00, 0x00);
AD5304_ValueSet(0x01, 0x00);
AD5304_ValueSet(0x02, 0x00);
AD5304_ValueSet(0x03, 0x00);
}
void DAC_ValueSet(u8 *pbuff) //设置DAC的输出值
{
AD5304_ValueSet(0x00, pbuff[6]);
AD5304_ValueSet(0x01, pbuff[7]);
AD5304_ValueSet(0x02, pbuff[8]);
AD5304_ValueSet(0x03, pbuff[9]);
}