天南地北客
发表于: 2018-1-29 11:01:14 | 显示全部楼层

本文主要介绍如何使用ATmega328p控制器、DDS函数发生器IC、运算放大器、几个无源器件以及一些艰苦的工作来制作属于自己的任意波形发生器。


如果家里能拥有属于自己的电子实验室,那会是非常棒的 - 唯一的缺点就是即使是基础设备也可能会是非常昂贵的。自己制作设备不仅可以省钱,还是提高知识的一个很好的方式。因此,在本文中,我将介绍如何制作属于您自己的函数生成器。

thumbnail_signalGenerator.jpg


什么是函数发生器?

首先,函数发生器(也称为乐音发生器)是能够以设定频率输出特定波形的电子设备。例如,可以产生60Hz的正弦信号。您可以使用它来测试音频放大器的内部工作情况,找出运算放大器和二极管的特性,制造噪音 - 以及一些其他的应用。


DDS函数发生器是一个数字任意波形发生器,这意味着它使用数模转换器(DAC)来产生一个信号。它还具有只读存储器(ROM),根据采样频率(Fs),以不同时间间隔存储特定波形的幅度值。


假设我们有一个8位DAC的DDS信号发生器,它以100Hz的采样频率输出800Hz的正弦信号。因为Fs是正弦波频率的8倍,所以工程师或更可能的是计算机需要从实际的正弦波中提取8个幅度值,从t = 0到t =2π。这个幅度间隔是[0,255](二进制中的1111 1111 = 255),其对应于具有实际正弦波的区间[-1,1]。由于图片胜过千言万语,下面是真实正弦波与我们的虚拟(和低性能)DDS函数发生器输出的图片之间的比较。

TrueVSDAC.png


自制设备

本文的目标是建立一个可靠的函数发生器,频率可高达1MHz,幅度高达9V,并允许您选择正弦波、三角波和时钟(即具有50%占空比的矩形)信号。为了帮助您理解为什么选择使用的组件,它们如何协同工作以及如何编写固件,我将把本文分成两大块,即硬件和软件。


硬件

这个设备的硬件方面有两个主要部分:电源和包含函数发生器IC和微控制器的主板PCB。


电源

主PCB需要两个电压:+ 12V和-12V。信号的最终放大需要对称的电源。通过调节+ 12V一个直接在主PCB上创建一条较小的+ 5V电源轨;需要给单片机、AD9833、函数发生器IC、最后是24MHz的晶体振荡器供电。以下您可以找到电源板的原理图:

PowerSupplySchematic.png


为了获得这些电压,将使用一个变压器,从230V或110V(取决于你所在的地区)到两个12V的交流线路(在变压器上通常会写12V-0V-12V的线路)。 200mA的输出电流已经足够了。


请记住,变压器的输出是交流电,我们需要直流电。为此,我们将使用一个简单的整流桥。这将改变正弦信号。这些通常作为独立元件来使用,但也可以使用四个通用二极管,如1N4001。


我们不会在标准配置中使用它,因为我们需要一个对称的输出,所以我们将按照上面的原理图连接它们:变压器的两端连接到整流器,中心抽头连接到地。为了平滑输出,我们将首先使用两个大电容,每个1000μF额定电压为35V。以下您可以在各个阶段找到电源轨的输出波形:

PowerSupplyWaveforms2.png


此外,为了消除纹波,使用两个电压调节器,典型的LM7812及其兄弟LM7912,它用于负电压。最后,我们在每个稳压器IC输出端加一个100μF电容器和一个100nF电容器,两者的额定电压都是25V。我们希望此电源尽可能平滑,因为我们将使用它们来抵消我们的最终输出电压,并且任何AC分量都将传播到输出。


AD9833电路板

让我们来看一看主板PCB。 LM1117-5V线性稳压器用于从+ 12V电源产生+ 5V电源。为了使得输出平滑,我们在电压输入线(+ 12V和-12V)和稳压器的输出端加上电容。

SignalGenMainSchematic.png

在原理图的左侧,您会看到一个ATMega328p-AU微控制器,与Arduino Uno中使用的相同,但采用SMD封装。为了对MCU进行编程,在它旁边放置一个称为AVR-ISP的6针连接器。它有两个电源引脚(+ 5V和GND)和另外四个通信引脚:MISO、MOSI、CLK和RESET。


我们只使用一个用户输入组件:一个带集成开关的旋转编码器。这将是我们的控制元素来设置频率、信号类型和其他设置。来自旋转编码器的信号被连接到微控制器PD2和PD3(Uno上的D2和D3)上的两个中断引脚,并且开关转到可用作输入的可用引脚;我选择了PD1(Uno上的D1)。我们不会添加任何上拉电阻,因为我们将使用集成在微控制器中的那些电阻。由于机械触点并不完美,所以当我们旋转编码器而不是一个理想的脉冲时,会出现一个抖动信号,但是这个可以通过软件或硬件使用一个电容来很容易的修复。对于集成开关,我们将使用软件方法,对于旋转触点,将使用两个100nF电容器。


普通的绿色LED连接到引脚PD7(Uno上的D7),用于调试目的或显示状态。使用的显示器是一个带有HD44780控制器的简单LCD,它具有16行和2列的背光。为了减少连接线的数量,使用了一个适配器板,以便控制LCD的唯一引脚为2,用于I2C上的数据,另外2个用于电源(+ 5V和GND)。微控制器上的I2C线路用于SDA引脚PC4和SCL引脚PC5。在Arduino Uno上,分别命名为A4和A5。


最后,在微控制器与AD9833集成电路之间建立最后一个连接。它使用单向SPI总线,这意味着数据只能从MCU向IC流动。信号是MOSI(主出从入),CLK(时钟)和CS(片选),在AD9833上称为FSYNC。为了总结微控制器部分,我应该提到,每个电源引脚都需要100nF的去耦电容。

SignalGenMainSchematic-part1.png


在继续原理图的最后一部分之前,先介绍带有函数发生器IC的部分,让我指出AD9833的几个关键特性。虽然我会听起来像一个销售人员,让我们开始吧。这是一个DDS型可编程波形发生器,所以它需要一个最高频率为25MHz(对于这个特定的IC)的时钟信号,然后根据微控制器(最大228)通过SPI总线传递的值进行分频,使用10位DAC输出由微控制器选择的波形。输出的峰峰值为0.65V-0.038V(VOUT最大值 - VOUT最小值),偏移量为(0.65V-0.038V)/ 2。这意味着VOUT最小值非常接近0V。一个重要的注意事项是时钟输出(矩形信号)的幅度为2.5V,这是设备内部稳压器产生的电压。


现在我们已经弄清楚了,让我们看看原理图的最后一部分。晶振用于向AD9833的主时钟输入提供24MHz的时钟信号。 FSYNC,SCLK和SDATA连接到微控制器的SPI总线。在VDD引脚附近使用两个去耦电容,一个值为0.1μF,另一个值为10μF。 2.5V内部电压调节器需要另一个去耦电容;这在引脚CAP附近并且具有0.1μF的值。 COMP和VDD引脚之间需要另外一个电容来解耦DAC偏置电压;它的值为10nF,如数据表所示。

SignalGenMainSchematic-part2.png


当我谈到微控制器连接时,我还写了Arduino Uno引脚等价物。我这样做是因为上一段中描述的AD9833电路可以在中国的各个制造商处作为可以连接到Arduino Uno的分线板使用。请记住,输出是直接从IC,没有额外的电路,我会继续在下面解释。


IC的输出通过1.3kΩ电阻馈入运算放大器的同相输入端。其侧引脚连接到-12V和+ 12V的微调器POT1(可变电阻器)具有连接到开关输入端的扫频器以提供偏移电压。 SPDT开关的另一个输入端直接接地,输出端通过另一个1.3kΩ电阻连接到运算放大器的同相输入端。这个配置与一个50kΩ电位器相结合,可以使我们获得1到20之间的可变增益。这是使用Millman定理和运算放大器将输入V +和V-保持在相同电压的事实计算得到的:

Millman’s theorem.jpg


请记住,增益也适用于偏移电压。我这样做有三种配置:

1.    使用微调器POT1将失调电压设定为-350mV。当开关处于位置3(R4接地)时,输出电压是IC的输出,一个幅度为350mV,偏移量为350mV的信号乘以电位器POT2设置的增益。当开关处于位置1(R4连接到由调整器POT1获得的偏移电压)时,输出正如之前减去偏移电压,本质上是具有350mV振幅且没有偏移的信号乘以增益。

采用这种配置,输出电压可以从-7V到+ 7V或从0V摆动到运算放大器的能力(接近+ 12V)。

2.    偏移电压设置为AD9833的VOUT最小值。然后乘以1到20之间的增益。

3.    您可以使用电位计代替微调电位器POT1,并将其安装在前面板上,这样就可以获得一个可变偏移。只要记住偏移量也受增益影响,所以首先设置增益,选择所需的峰峰值电压是明智的,然后使用偏移电位器调整信号的垂直位置。我不推荐这个设置;如果你需要可变偏移,我建议你增加一个单独的运算放大器作为一个固定增益为2的求和放大器,如下图所示

summing amplifier.jpg

SchematicAD9833-3_1.png


为了将电路的放大部分封装起来,我不得不提到,正负电源需要100nF去耦电容,而且您需要选择一个能够承受电源电压的运算放大器( + 12V和-12V),并具有非常好的压摆率,以便能够跟上高放大信号。


理想情况下,该电路应该建立在专门为此应用而设计的PCB上,而不是在原型电路板上。我将通过下面的文件为您提供KiCad中已经设计的PCB。但是,如果你想自己做,请记住这些事情:

●    将所有集成电路的去耦电容尽可能靠近电源引脚。

●    尝试使用地平面(如果只使用两层,使底层主要由地面组成)。

●    将电路的模拟部分(AD9833的输出端、放大电路和输出BNC连接器)与数字部分(AD9833的单片机和通信端)分开。您可以将接地层分割到AD9833的正下方。由于IC具有两个独立的模拟和数字接地引脚,因此可以轻松完成。

●    正如AD9833的数据表所示,避免在AD9833下运行数字走线。

SignalGeneratorPCB.jpg


现在我们已经完成了构建电路的工作,接下来开始进行编程。

跳转到指定楼层
天南地北客
发表于: 2018-1-29 11:57:33 | 显示全部楼层

软件

我们将使用Arduino IDE编写代码,然后下载到微控制器的内存中。在接下来的几段中,我将介绍如何为AD9833编写一个库,然后介绍主要的软件代码,使我们能够将微控制器连接AD9833、LCD和旋转编码器。 AD9833具有这些所谓的寄存器,这些寄存器基本上是存储器的位置,我们可以将数据放入其中,并且集成电路基于这些值,改变其操作模式;它选择输出什么波形、相位和分频系数。我们将使用五个寄存器:控制寄存器、两个相位寄存器(PHASE0和PHASE1)和两个频率寄存器(FREQ0和FREQ1)。


AD9833软件库

我们将创建两个文件,AD9833.cpp,包含源代码的文件以及AD9833.h头文件。


在头文件中,我们指定了类(AD9833)的名称,就像一个俄罗斯套娃一样,并且在该文件中,我们将调用变量和函数来与波形发生器IC进行通信,并更改其参数,例如频率和波形的类型。变量和函数可以定义成两种类型中的一种:公共的,我们可以从类的外部调用方法(函数),也可以是私有的,只有当我们在类的方法中时才可以调用。我已经添加了注释,以便您了解每个函数和变量的含义。例如:

  1. //Initialise the AD9833
  2. //_FYNC is the pin on the uC where FYNC is connected
  3. //_mclk is the frequency of the crystal generator
  4. AD9833(int _FSYNC, unsigned long _mclk);
复制代码

接下来介绍源文件,当我们初始化一个新的AD9833类型的对象时,需要做一些事情;这些是在函数“AD9833 :: AD9833(int _FSYNC,unsigned long _mclk)”中实现。首先,我们需要注意FSYNC引脚,将其作为形参进行传递,并将其设置为输出引脚。当向AD9833写入时,该引脚变为低电平。在这个方法里面,我们还设置了一些寄存器的默认值,这样我们就可以用FREQ0寄存器输出一个1kHz的正弦信号。最后一行将SPI设置为mode2,这是单片机和AD9833用于通信的设置。


现在剩下的就是仔细阅读数据表,看看我们需要在AD9833的寄存器中设置什么值来操纵输出波形及其操作。因此,我们将为以下操作编写函数:写入数据、设置频率、设置相位、睡眠、复位、模式以及选择频率/相位寄存器。


我们将直接进行位级操作。有时我们可能想改变整个寄存器的值,例如频率寄存器,但有时我们只想改变整个字的几个位。要实现这一点,我们将使用以下操作:


“&=”将一些位设置为0,而其余的则不受干扰。 (0 =设置为0,1 =保持原样)。例:

  1. controlRegister &= 0xF3FF; // Set D11 and D10 in control register to 0
复制代码

“| =”将一些位设置为1,而其余的则不受干扰。 (1 =设置为1,0 =保持原样)。 例:

  1. controlRegister |= 0x0C00; // Set D11 and D10 in control register to 1
复制代码

在下面的表中,我已经从数据手册中提取了需要设置哪些位来执行操作。

操作
寄存器
设置频率 FREQ0 FREEQ0: D15 = 1, D14 = 0
设置频率 FREQ1 FREEQ1: D15 = 0, D14 = 1
设置相位 PHASE0 PHASE0:D15 = 1, D14 = 1, D13 = 0
设置相位 PHASE1 PHASE0:D15 = 1, D14 = 1, D13 = 1
设置模式 - 正弦波 CNTRL D5 = 0, D1 = 0
设置模式 - 三角波 CNTRL D5 = 0, D1 = 1
设置模式 - 时钟 CNTRL D5 = 1, D1 = 0
设置频率寄存器 CNTRL D11 = 0 (选择 FREQ0);D11 = 1 (选择 FREQ1)
复位 CNTRL D8 = 0 或 1
睡眠模式 - DAC电源工作 CNTRL D7 = 0, D6 = 0
睡眠模式 - DAC电源断电 CNTRL D7 = 0, D6 = 1
睡眠模式 - 内部时钟禁止 CNTRL D7 = 1, D6 = 0
睡眠模式 - DAC电源断电并且内部时钟禁止 CNTRL D7 = 1, D6 = 1

寄存器的大小不同。控制寄存器长16位,相位寄存器长12位,频率寄存器有28位。要通过SPI输出数据,我们一次发送一个字节,如“writeData”函数中所示,从低字节开始(数据整数​​的前8位),然后是高字节。


设置频率有点棘手,因为我们不直接发送我们想要的频率。根据数据手册,模拟输出为fMCLK / 228×FREQREG。因此,频率寄存器必须设置为:

FREQREG.jpg


由于得到的值的长度可以达到28位,所以我们把它分成两个字,每个长16位,然后我们发送数据从低位开始。


如果你按照上面的表格和注释的指导。其余的方法应该很容易实现,


主要的例程代码

对于将我们的AD9833、LCD、旋转编码器和微控制器连接在一起的主要代码,我们将偷一点懒,为使用I2C总线的LCD旋转编码器使用一些已经写好的库。


我们的任意波形发生器不能很好地使用相位功能,我决定暂时不用这个功能,但是可以通过取消注释“//#define usePhase”指令来使用它。但是,这样做会禁止在FREQ0和FREQ1寄存器之间进行选择。


我试图尽可能地使得软件界面友好。从一开始,在液晶显示器上你可以看到左上角的频率,并逐个数字地改变它,右上角是模拟输出的电源状态,可以是开或关,这意味着你可以转动关闭输出而不关闭设备。在左下角,可以选择用于存储频率的寄存器,FREQ0或FREQ1。如果您想在两个不同频率之间轻松切换,这非常有用。最后,右下角是要输出的波形类型,可以是正弦波、三角波或矩形波。请记住,时钟输出将始终具有更高的幅度,因为AD9833以2.5V输出,而正弦和三角信号则为0.65V。

SignalGeneratorScreen.jpg


以下是如何进行更改:按下编码器,使光标处于激活状态,然后旋转编码器在四种设置(频率、ON / OFF、FREQ0 / 1和波形类型)之间“滚动”。选择要更改的设置后,按下编码器将改变设置(如果选择了ON / OFF或FREQ0 / 1),或者可以通过旋转编码器来改变设置值(旋转递增/递减当前数字或改变波形类型,取决于所选的设置)。再按下一次,将会应用设置(对于波形类型)或转到下一个数字(对于频率)。


我尽量使代码尽可能简洁,希望注释可以帮助你理解我的思维过程。如果您有任何问题,请不要犹豫,留下评论或与我联系。


我真诚地希望一切顺利,您将能够享受您自己的任意波形发生器。


以下是您可以欣赏的一些输出波形:

SineWithOffset.png

正弦波,1V峰 - 峰值,1kHz,无偏移

Triangular.png

三角波,1V峰 - 峰值,1kHz,无偏移

SQuareNoOffset.png

时钟信号,11V峰峰值,500Hz,带偏移


本文翻译自:https://www.allaboutcircuits.com/projects/how-to-DIY-waveform-generator-analog-devices-ad9833-ATmega328p/。如有错漏,敬请指正。

回复

使用道具 举报

lihao
发表于: 2019-3-27 14:12:08 | 显示全部楼层

看着很不错,最大速度不知道能够到多少
回复

使用道具 举报

gdgzwqz
发表于: 2020-9-20 13:26:00 | 显示全部楼层

高度赞扬,准备用Nano制作一个!!!
回复

使用道具 举报

gdgzwqz
发表于: 2020-9-26 21:57:12 | 显示全部楼层

好介绍,准备制作一个试试!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 8 | 回复: 19



手机版|

GMT+8, 2024-3-29 16:11 , Processed in 0.117162 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表