本帖最后由 洋葱圈 于 2013-11-4 20:44 编辑
上节讲了ADC模拟转数字模块,这节趁热打铁,说说DAC数字转模拟模块。ADC和DAC就像一对欢喜冤家,大家可以把这两个模块理解为互逆过程,就像录音机与播音机两个东西,前者负责把模拟量采集进来,后者负责把模拟量输出出去。其实当你会用了这两个模块之后,完全可以自己做一个简单的录音和播音机了。
与ADC的复杂程度不同,DAC模块可以说是非常简单了,不但它本身的寄存器很少,而且你在直接使用固件库编程的时候就更简单了。因此我们就先讲一下的工作模式,了解了工作模式之后再使用固件库编程便是极好的了。
DAC转换原理K60中的DAC是12位精度的,这个概念与ADC的精度概念一样,就是把参考电压分成2的12次方份,每一份的电压就是它的最小输出精度,因此DAC的输出电压精度就是3.3V/4096=0.00081V。至于内部的转换原理如何,我们可以从官方技术文档中的模块框图看出:
上图是截取的模块框图的上半部分,其中红框内就是实现电压转换的部分,大家可以理解为K60内部通过4096个等值的电阻将参考电压分成了4096分,而MUX则根据蓝框中的值来判断到底选择哪个分压值进行输出。这个蓝框中的值就是大家在编程中设置的输出值,它其实是一个缓冲区,可以配置为不同的模式来输出缓冲区中的值。绿框中的部分是一个缓冲放大器,途中的DACEN是一个寄存器控制位,用来使能DAC工作,DACRFS用来选择参考电压,LPEN用来使能低功耗模式。
至于本框图的下半部分,则是DAC的比较重要也是难点所在,本文中没有示出,大家可以自己到技术文档中感受下,这部分用于控制DAC的硬件触发、缓冲区工作模式选择、中断等等。
DAC工作模式
非缓冲区工作模式
这个“非缓冲区工作模式”一看就是和“缓冲区工作模式”相对应的,如果大家在用固件库初始化DAC时不做任何配置,默认就是非缓冲区工作模式。该模式是DAC最简单的工作模式,因为几乎不用做任何配置,使能DAC后,只要向DAC数据寄存器(DAC[x]_DAT)的第一个缓冲区(DAC[0]_DAT)写入0~4095之间的数值,就可以在DAC输出引脚输出电压。 缓冲区工作模式既然该模式叫做“缓冲区工作模式”,那么它必然会用到了DAC数据寄存器(DAC[x]_DAT)的所有缓冲区,而不仅仅是第一个缓冲区。那么DAC是如何选择缓冲区中的数据进行输出的呢,原来在缓冲区工作模式下,DAC还分为了3个不同的工作模式。
在学习3中工作模式前,你要了解什么是DAC数据寄存器的缓冲区。DAC输出的模拟电压值是由DAC数据寄存器(DAC[x]_DAT)决定的,它不是一个寄存器,而是一系列缓冲区,x为0~15,即长度为16。DAC可根据触发模式(硬件触发或软件触发)的不同,依次将缓冲区中的值输出出去。至于按照什么顺序输出,就是要看你设置的工作模式了。
在固件库的使用中,如果你要使用缓冲区工作模式,需要配置初始化结构体的变量DAC_BufferEnable为TRUE。
普通模式
在该模式下,DAC的读指针会从最底部的缓冲区依次读出数据并输出,每触发一次,地址+1,到达最高上限后(比如设置缓冲区最高为4),那么读指针会在下一次触发时会到底部缓冲区(DAC[0]_DAT)。
如果使用普通模式,需要配置DAC_BufferWorkMode为BUFFER_MODE_NORMAL。
摆动模式
顾名思义,在该模式下,读指针像单摆一向,不会在到达顶端后立即返回底部,而是会在下次触发后由地址+1改为地址-1,也就是说读指针会一直在缓冲区底部和最高上限之间游走。
如果使用普通模式,需要配置DAC_BufferWorkMode为BUFFER_MODE_SWING。
单次扫描模式
在该模式下,读指针从底部逐渐增加到最高上限后,就会停止在那里不动,只有在再次复位指针后,它才会再一次开始增加。
如果使用普通模式,需要配置DAC_BufferWorkMode为BUFFER_MODE_ONETIMESCAN。
以上所说的缓冲区最高上限是由DAC_BufferUpperLimit配置的,取值为1~16。
关于DAC的触发如果你使用“非缓冲区工作模式”,那么不必理会这节,因为只有只用“缓冲区工作模式”时才需要配置DAC的触发模式。每触发一下DAC,它的数据读指针就会改变一次地址,从而改变数据的输出。最简单的方式是配置DAC为软件触发(.DAC_SoftTrgEnable=TRUE),你就可以使用库函数LPLD_DAC_SoftwareTrigger()触发指针变更。当然DAC也可配置为硬件触发,也需要用到PDB模块来配合使用。
关于DAC的中断同样,如果你使用DAC的缓冲区工作模式,那么也可以配置是否触发不同的中断。
当使能读指针底部中断后(.DAC_ReadPointerBottomIntEnable=TRUE),DAC会在读指针到达缓冲区最高上限后产生中断请求。
当使能读指针顶部中断后(.DAC_ReadPointerTopIntEnable=TRUE),DAC会在读指针等于0后产生中断请求。
当使能缓冲区水印中断后(.DAC_BufferWatermarkIntEnable=TRUE),DAC会在读指针到达水印位置后产生中断请求,这个水印位置由DAC_BufferWatermarkSel结构体变量决定。
当然,在初始化参数中使能相关中断后还不够,还要配置相关中断的回调函数才可以,最终还要调用使能DACx中断函数来使能中断控制器。
DAC例程讲解打开例程“08-(DAC)LPLD_AnalogSignalOutput”(请使用该例程的0.2版本,0.1版本存在BUG),编译下载后运行,用示波器观察DAC0_OUT引脚的波形,会看到三角波的产生,如下图所示:
这是一个极其简单的例程,我们只需要几行的程序就可以实现三角波的生成,首先看初始化代码:
1 | dac_init_struct.DAC_Dacx = DAC0; | 2 | LPLD_DAC_Init(dac_init_struct); |
Line 1:使用DAC0模块。
Line 2:调用初始化函数初始化DAC0。没错,只需要这简单的2行就完成了DAC的最简单功能的初始化任务! 接下来看while循环内的代码:
1 | if(i==0) | 2 | delta = DELTA; | 3 | else if(i==4095) | 4 | delta = -DELTA; | 5 |
| 6 | i += delta; | 7 |
| 8 | LPLD_DAC_SetBufferDataN(DAC0, i, 1); | 9 | delay(DELAY); |
Line 1~4:这几行决定每次循环的输出值是增还是减,因为我们要输出三角波,因此不管波形的增加还是减小,它都是线性变化的,当到达底部后,让每次变化为递增DELTA,当达到顶部后 ,让每次变化为递减DELTA,这个DELTA值默认设置为1。
Line 6:将递增或递减的值累加到输出值i中。
Line 8:调用设置输出缓冲区数据函数,配置输出数据的第1个缓冲区为输出值i。因为我们没有使能“缓冲区工作模式”,因此只要调用了此函数后,DAC就会立即输出数值i。
Line 9:延时一小会以保持波形,如果你想更改波形的频率,更改这里的延时值就可以了。当然,如果想精确的设置输出间隔时间,最好还是使用“缓冲区工作模式”并配合“硬件触发”为好!
DAC能干什么开篇我们说了,ADC和DAC是就像一对欢喜冤家,互相是对着干的。那么DAC到底都能实际干些什么呢?最常用的就是我们说的输出音频数据,当然它本质还是输出模拟波形,只不过这个波形的频率范围是我们可以用耳朵识别出来的。
DAC也可以做为波形发生器,就像本例程中生成的三角波一样,你可以利用不同的算法,加上点有计划的输出间隔、触发配置,就可以做得更像样一点。
如果你想做一个可编程电流源,同样可以例程DAC来控制,这里我们就抛砖引玉了,大家可以慢慢挖掘!
本片仅仅是针对OSKinetis固件库来阐述DAC到底怎么用,更详细的原理、使用方法,大家可以百度、谷歌、看技术文档等等。
|