模拟信号输出是经常会遇到的应用需求,解决的办法应多种,但我们使用最多的还是数模转换。对于不同的数模转换器我们需要为其编写适用的驱动程序,在这一篇中我们就来考虑如何实现dac8552高精度模数转换器的驱动程序。
1、功能概述 该dac8552是一个16位,双通道,电压输出数模转换器(dac)提供低功率操作和灵活的串行主机接口。每个芯片上的精确输出放大器允许轨到轨输出摆动,以实现在2.7v到5.5v的供应范围。该设备支持标准三线串行接口,能够操作与输入数据时钟频率高达30mhz的vdd = 5v。
1.1、功能结构 dac8552这种设备在正常情况下的低功耗使得它非常适合便携式、电池驱动设备和其他低功耗应用。采用soic-8的封装形式,引脚定义如下:
dac8552需要一个外部参考电压来设置每个dac通道的输出范围。dac8552还包括一个电源上电复位电路,以确保dac输出功率能够输出到零,并保持在那里,直到获取一个有效的写入值。dac8552拥有一个spi串行接口,该接口提供了灵活的功能。
从上述结构图可知,dac8552每次仅能操作一路输出,因为全部的操作都是通过同一个移位寄存器来实现的。
1.2、移位寄存器 dac8552有一个24位的输入移位寄存器,前面8位用来作控制位,后面16位用作数据位。具体如下图所示:
在前面的8位控制位中,db23和db22是保留位必须为“0”,db21(ldb)位和db20(lda)用于控制后面的16位数据适用于加载哪一个输出通道还是power_down命令。db19没有定义,dac8552不关心该位的具体数值。db18为缓冲器选择位,用于控制数据的目标通道是dac a还是dac b。后续的db17(pd1)和db16(pd0)用于选择power_down的模式。具体的命令如下表中描述:
至于power_down的模式有几种选择,如下表所示:
2、驱动设计与实现 我们已经了解了dac8552的基本结构及寄存器命令,接下来我们将根据这些认知设计dac8552的驱动程序。
2.1、对象定义 在设计dac8552的驱动程序之前,我们先来考虑一下dac8552的对象定义问题。我们作为一个对象一般会包括属性和操作两个方面的内容。我们先来分析dac8552对象应该包含有哪些属性。属性用于标识对象的某些特性,dac8552通过spi总线下发数据和命令,我们没有发现什么需要特别标记的特性,所以我们不需要为dac8552对象设计属性。
我们再来看一看,dac8552对象需要实现哪些操作。首先dac8552使用spi总线进行通讯,而spi总线采用片选信号来区分不同的节点,所以我们需要操作dac8552的片选信号,而片选型号的操作显然依赖于特定的操作平台,所以我们将控制其片选信号作为dac8552对象的一个操作。另外,dac8552作为模拟量输出对象,我们需要向其发送命令和数据,而向其发送数据和命令也依赖于具体的操作平台,所以应将其作为对象的一个操作来实现。据此我们可以定义dac8552的对象类型如下:
/* 定义dac8552对象类型 */typedef struct dac8552object { void (*writedatatodac)(uint8_t *tdata,uint16_t tsize); //向dac发送数据 void (*chipselcet)(dac8552cstype cs); //片选信号}dac8552xobjecttype; 我们定义了dac8552的对象类型,但当我们使用其声明一个对象时,并不能直接使用,我们需要对对象进行初始化,这就需要我们设计一个对象初始化的函数。对象初始化函数处理对象相关的属性和操作的配置,具体实现如下:
/*初始化dac8552对象*/void dac8552initialization(dac8552xobjecttype *dac, //dac8552对象变量 dac8552writetype write, //写数据函数指针 dac8552chipselecttype cs //片选操作函数指针 ){ if((dac==null)||(write==null)) { return; } if(cs!=null) { dac->chipselcet=cs; } else { dac->chipselcet=defaultchipselect; }}2.2、对象操作 我们已经定义了dac8552的对象类型并为dac8552对象设计了初始化函数,接下来我们看一看dac8552所要实现的操作。对于dac8552对象来说,我们对其操作无非就是写其移位寄存器以实现命令和数据的下发。从其数据表中我们可以看到操作移位寄存器的时序如下所示:
根据我们前面对dac8552相关数据的了解以及上述时序图,我们可以封装对其移位寄存器的操作函数如下:
/*操作dac8552输出通道*/void setdac8552channelvalue(dac8552xobjecttype *dac,dac8552ldtype ld,dac8552bstype bs,dac8552pdtype pd,uint16_t data){ uint32_t inputshiftdata=0; uint8_t sdata[3]; inputshiftdata=data; inputshiftdata=inputshiftdata|(ld<<20); inputshiftdata=inputshiftdata|(bs<<18); inputshiftdata=inputshiftdata|(pd<>16); sdata[1]=(uint8_t)(inputshiftdata>>8); sdata[2]=(uint8_t)inputshiftdata; dac->chipselcet(dac8552cs_enable); dac->writedatatodac(sdata,3); dac->chipselcet(dac8552cs_disable);}3、驱动的使用 我们设计了dac8552的对象驱动,但这个驱动是否正确我们需要验证一下。所以接下来我们设计一个简单的例子来实现对驱动程序的验证。
3.1、声明并初始化对象 我们使用设计的驱动程序操作dac8552时,首先需要使用我们定义的对象类型声明一个dac8552对象。
dac8552xobjecttype dac8552; 声明了这个对象变量之后,我们还需要使用初始化函数对其进行初始化方可使用。这一初始化函数拥有3个参数:
dac8552xobjecttype *dac, //dac8552对象变量dac8552writetype write, //写数据函数指针dac8552chipselecttype cs //片选操作函数指针 第一个参数正是我们要初始化的对象变量;第二个参数为向dac8552写命令和数据的函数指针;第三个参数是片选信号操作函数指针。这两个函数指针需要我们实现。它们的原型如下:
/* 向dac发送数据函数指针类型 */typedef void (*dac8552writetype)(uint8_t *tdata,uint16_t tsize);/* 片选操作函数指针类型 */typedef void (*dac8552chipselecttype)(dac8552cstype cs); 我们根据函数原型定义,在具体的实现平台上实现它们,如我们在stm32平台上实现如下:
/*定义片选信号函数*/void dac8552cs(dac8552cstype en){ if(dac8552cs_enable==en) { hal_gpio_writepin(gpiof, gpio_pin_4, gpio_pin_reset); } else { hal_gpio_writepin(gpiof, gpio_pin_4, gpio_pin_set); }}/*定义发送数据函数*/void dac8552transmitdata(uint8_t *wdata,uint16_t wsize){ hal_spi_transmit (&dac8552hspi, wdata, wsize, 1000);} 我们将对象变量以及上面实现的2个函数的函数指针作为参数传递给dac8552对象初始化函数来实现对象变量的初始化。具体如下:
dac8552initialization(&dac8552, //dac8552对象变量 dac8552transmitdata, //写数据函数指针 dac8552cs //片选操作函数指针 );3.2、基于对象进行操作 初始化对象变量后,我们就可以基于该对象变量实现我们对dac8552的操作了。我们已经封装了对其移位寄存器操作的函数,直接调用该函数来说实现我们的操作。一个简单的实现函数如下:
/* 修改dac8552的通道输出 */void dac8552operation(void){ uint16_t wdata=0; wdata=(uint16_t)(65535*tvaluea/100); setdac8552channelvalue(&dac8552, //所操作的dac对象 dac8552_loada, //加载的通道 dac8552bs_buffera, //选择的缓存 dac8552pd_normal, //power-down设置 wdata //所写的数据 ); wdata=(uint16_t)(65535*tvalueb/100); setdac8552channelvalue(&dac8552, //所操作的dac对象 dac8552_loadb, //加载的通道 dac8552bs_bufferb, //选择的缓存 dac8552pd_normal, //power-down设置 wdata //所写的数据 );} 在这个例子中我们分别通过百分比设定值调整了a、b通道的输出,实现在正常模式下操作a或者b通道,并更新指定的缓存。
4、应用总结 我们设计并实现了dac8552模数转换器的驱动程序,并且设计了一个简单的应用来验证这一驱动程序的正确性。所得到的结果证明驱动的设计是没有问题的,实际上我们已经将其运用到实际的项目中,效果良好。
在使用驱动程序时需要注意,片选信号并非必须实现。因为有些时候我们可能需要在硬件上直接将其选中,此时添加片选操作函数是没有什么意义的,我们可以在初始化时传入null来完成。
什么是云计算,它的特点都有哪些
工业互联网 互联网区别 5g工业互联网是什么
亚太天能科技T56X指纹锁简介
在高速ADC中增加SFDR的主要限制是什么?
5G投资风口 中国竟比美国多出240亿美元
DAC8552高精度模数转换器的驱动设计与实现
自制颜色传感器教程
AXI4-Lite总线信号
单向可控硅最筒单电路图大全(四款模拟电路设计原理图详解)
直流无刷电机通交流电
Spring Boot实现Redis分布式锁
超宽带无线视频监控系统的设计
传统石墨负极电池瓶颈?硅负极新材质面临电池挑战
苹果调整iPhone供应链 部分老供应商惨遭重创
九天睿芯入选“2022全球最值得关注的100家电子和半导体初创公司”榜单
海为PLC/HMI/云/手机APP在现代水产农业养殖上的应用
网线面板接法图解
未来智能交通系统呈现哪些趋势
估算印刷电路板走线或平面直流电阻的方法
无刷直流微电机有哪些特点?