当前位置: 首页 > news >正文

Arduino+AD9833测试!DDS

提示:本文内容仅供学习参考。Author: Jonnie Walker  CGC

 

目录

前言

二、使用步骤

1.硬件

2.软件

1.Demo_1

2.Demo_2

3.测试数据

总结


前言

         你好! 本文我们将使用AD9833指定输出不同波形的测试过程。从目录中你大概已经知道内容在讲什么了!这里我就不废话了!对于小白建议仔细往下看。


一、AD9833是什么?

AD9833是一种低功耗、可编程波形发生器,能产生正弦、三角形和正方形波形输出。输出频率和相位为软件可编程,允许轻松调整。没有外部组件是必需的。频率寄存器是28位宽:时钟频率为25MHz,分辨率可达0.1 Hz实现;时钟频率为1mhz时,AD9833可调至0.004 Hz分辨率。通过3线串行接口写入AD9833。这个系列接口工作在时钟频率高达40MHz,是兼容DSP和微控制器标准。

......。

主要性能参数:

1.工作电压: 2.3V 至 5.5V (兼容 3.3V 和 5V 系统)

2.输出波形: 正弦波、三角波、方波

3.最大输出频率: 理论上为参考时钟频率的一半(奈奎斯特定律),但实际上受限于内部DAC      的性能,纯净的正弦波输出通常推荐在 0 到 12 MHz。

4.频率分辨率: 28位(取决于频率调谐字的位数),在 25 MHz 时钟下,分辨率约为 0.1 Hz

5.功耗: 非常低,在 3V 电压下约 5mW,非常适合电池供电设备。

6.控制接口: SPI 兼容的 3 线串行接口。

7.工作温度:−40℃~ +105℃

8.封装: MSOP-10

 

缺点:

1.输出幅度固定:如果需要调整幅度,需要外接放大器或数字电位器。

2.输出波形纯度:在较高频率时会下降,谐波分量会增加。

3.无法产生任意波形:只能产生内置的三种波形。

 

二、使用步骤

1.硬件

 图1

 

图2

图2为本次测试的实物图,此硬件的带宽5MHz。

硬件通信引脚连接说明:

    ArduinoUNO ------------    AD9833

        SCK --13   ---------------   CLK

        MOSI--11  ---------------     DAT

        PIN4--4    ----------------   FNC

        GND        -----------------   GND

        3.3V-5V   -----------------   VCC

 

图3

图3为实物测试连接图。

2.软件

测试条件:1.示波器  ,2.AD9833模块(图2)3.Arduino UNO开发板(不固定)

编译环境ArduinoIDE。在编译下面例程时需要安装:AD9833-Library-Arduino-master库文件。

要不然编译出错误!!!!

1.Demo_1

   此程序需要结合串口工具,本次使用都是:XCOM V2.0。

 比如:自定义频率需要通过串口工具发送5 指令,然后继续发送你需要设定的频率参数比如:1MHz,2MHz,3MHz。

/*** @file AD9833_test_suite.ino* @author Jonnie Wlaker  CGC* @brief  AD9833_Test2* @version 0.1* @date 2025-10-02* * @copyright Copyright (c) 2025* * ------------------------------------------------/* * 此例程需要结合串口工具,通过串口工具发送简单指令实现不同的功能,具体看一下loop()函数内容。* 在程序中我做了注释说明。* 在编译前先安装AD9833-Library-Arduino-master库。如果运行功能函数不知道起什么功能,可以去这 * 个库文件中查看具体封装函数信息!* * *//*ArduinoUNO     AD9833-----------------SCK --13      CLKMOSI--11      DATPIN4--4       FNCGND           GND3.3V-5V       VCC*/#include <AD9833.h>        #define RUNNING       F("\tRUNNING")
#define NOT_RUNNING   F("")
#define ON            F("ON")
#define OFF           F("OFF")
#define LED_PIN       13      // I'm alive blinker  
#define FNC_PIN       4       // Any digital pin. Used to enable SPI transfers (active LO  // Some macros to 'improve' readability
#define BLINK_LED         digitalWrite(LED_PIN,millis()%1000 > 500);/** We need to manually call serialEventRun since we're not returning through the loop()* function while inside the test functions. If a character is in the receive buffer,* exit the test function. We also blink the I'm Alive LED to give a visual indication* that the program is not hung up.*/
#define YIELD_ON_CHAR     if ( serialEventRun ) serialEventRun(); \if ( Serial.available() ) return; \BLINK_LED#define DELAY_WITH_YIELD  for ( uint8_t i = 0; i < 10; i++ ) { \YIELD_ON_CHAR \delay(100);   \}#define FLUSH_SERIAL_INPUT  if ( serialEventRun ) serialEventRun(); \do { Serial.read(); delay(100); } while ( Serial.available() > 0 );//--------------- Create an AD9833 object ---------------- 
// Note, SCK and MOSI must be connected to CLK and DAT pins on the AD9833 for SPI
// -----      AD9833 ( FNCpin, referenceFrequency = 25000000UL )
AD9833 gen(FNC_PIN);       // Defaults to 25MHz internal reference frequencyvoid setup() { pinMode(LED_PIN,OUTPUT);while (!Serial);          // Delay until terminal opensSerial.begin(9600);// This MUST be the first command after declaring the AD9833 objectgen.Begin();              // The loaded defaults are 1000 Hz SINE_WAVE using REG0// The output is OFF, Sleep mode is disabledgen.EnableOutput(false);  // Turn ON the outputPrintMenu(0,true);        // Display menu for the first time
}void loop() { static bool outputOn = false;BLINK_LEDif ( Serial.available() ) {char ch = Serial.read();FLUSH_SERIAL_INPUTPrintMenu(ch,outputOn);//通过串口工具发送数据,控制一下功能!switch ( ch ) {case '1':IncrementFrequencyTest();  //将选择的频率寄存器增加freqIncHzbreak;case '2':CycleWaveformsTest();  //波形切换实现,循环切换所有波形类型break;  case '3':SwitchFrequencyRegisterTest();break; case '4':PhaseTest();break;case '5':RequestedvsProgrammedValues(); //设置自定义频率break;case '6':outputOn = ! outputOn;   //开启/关闭输出gen.EnableOutput(outputOn);    // Turn off outputbreak;default:Serial.println(F("*** Invalid command ***"));break;                    }      }
}/** Setup a manual ramp from a Start frequency to a Stop frequency in some increment* over a ramp time. */
void IncrementFrequencyTest ( void ) {float startHz = 1000, stopHz = 5000, incHz = 1, sweepTimeSec = 5.0;// Calculate the delay between each increment.uint16_t numMsecPerStep = (sweepTimeSec * 1000.0) / ((uint16_t)((stopHz - startHz) / incHz) + 1);if ( numMsecPerStep == 0 ) numMsecPerStep = 1;// Apply a signal to the output. If phaseReg is not supplied, then// a phase of 0.0 is applied to the same register as freqReggen.ApplySignal(SINE_WAVE,REG1,startHz);while ( true ) {gen.SetFrequency(REG1,startHz-incHz);for ( float i = startHz ; i <= stopHz; i += incHz ) {YIELD_ON_CHARgen.IncrementFrequency(REG1,incHz);delay(numMsecPerStep); }}
}/** Cycle through all of the waveform types. Also cycle the * frequency registers.*/
void CycleWaveformsTest ( void ) {WaveformType waveType = SINE_WAVE;// 设置两个寄存器为相同波形gen.SetFrequency(REG0,10000.0);   // Load valuesgen.SetFrequency(REG1,1000.0);// We don't care about phase for this testwhile ( true ) {gen.SetWaveform(REG1,waveType);   // Next waveform  , 设置波形类型(核心函数)gen.SetWaveform(REG0,waveType);gen.SetOutputSource(REG1);        // Output 1000 Hz waveform// Hack to allow I'm alive lamp a chance to blink and give a better// response to user inputDELAY_WITH_YIELDgen.SetOutputSource(REG0);        // Output 10000 Hz waveformDELAY_WITH_YIELD// 切换波形类型switch ( waveType ) {             // Cycle through all the waveform typescase SINE_WAVE:waveType = TRIANGLE_WAVE;break;case TRIANGLE_WAVE:waveType = SQUARE_WAVE;break;case SQUARE_WAVE:waveType = HALF_SQUARE_WAVE;break;case HALF_SQUARE_WAVE:waveType = SINE_WAVE;break; }}    
}/** Fast switching example.* I use the FFT display capability on my scope*/
void SwitchFrequencyRegisterTest ( void ) {gen.ApplySignal(SINE_WAVE,REG0,500000);gen.ApplySignal(SINE_WAVE,REG1,100000);gen.SetPhase(REG1,180);           // Offset second freq by 180 deggen.Reset();while ( true ) {                  // This takes timeYIELD_ON_CHAR                 // This takes more timegen.SetOutputSource(REG0);    // This takes about 18 usecgen.SetOutputSource(REG1);    // This takes about 18 usec  // What ends up is REG0 frequency is active a shorter amount of time// then REG1 frequency. In the sepctrum, the duty cycle differences will// show up (power is lower by 10log(DC))}  
}/** Phase shift between REG0 and REG1. Use a oscilloscope set to Normal* triggering, AC coupling, 500usec/div, 100 mV/div. This will display* about two cycles for register 0, 4 cycle for register 1, plus dead * time for the Reset.* Use Normal triggering so the display remains even when triggering is * lost. Can use any waveform for this test. Remember that the square * wave is about 5v-pp while sine and triangle are about 600 mv-pp*/
void PhaseTest ( void ) {gen.ApplySignal(TRIANGLE_WAVE,REG0,1000);gen.ApplySignal(SINE_WAVE,REG1,2000);bool reverse = true;while ( true ) {reverse = ! reverse;for ( int16_t i = 0; i <= 360; i += 1 ) {if ( ! reverse )gen.IncrementPhase(REG1,-1);elsegen.IncrementPhase(REG1,1);YIELD_ON_CHAR/** Display ~ 2 cycles using REG0 phase. If no REG is supplied for phase,* defaults to REG specified for frequency. RESET is removed during this* function call.*/gen.SetOutputSource(REG0); /** This is just a wag to try to get exactly 2 cycles of the waveform. * It makes the phase alignments easier to verify.*/delayMicroseconds(1900);YIELD_ON_CHAR/* This also works if you keep using REG1 for frequency* Now display ~ 4 cycles using REG1*/gen.SetOutputSource(REG1);delayMicroseconds(1950);/** Turn off for remaining trace. Reset the registers so triggering occurs * on the start of REG0 signal. Reset() includes 15 msec delay which is good  * to ensure sweep is completed. * I tried using EnableOutput(true) then EnableOutput(false) in this* loop but could not get reliable triggering on the scope.* * The difference between Reset() and EnableOutput(false) is that EnableOutput(false)* keeps the AD9833 in RESET until you specifically remove the RESET using * EnableOutput(true). However, after a call to Reset(), calls to ANY function * EXCEPT Set/Increment Phase will also remove the RESET.* */gen.Reset(); if ( i % 90 == 0  )delay(1000);    // Stop and show phase alignment between REG0 REG1}}
}/** Show the requested versus actual programmed values for frequency and phase* Also show resolution, max frequency (based on refFrequency)*/
void RequestedvsProgrammedValues ( void ) {float requestedFrequency, programmedFrequency;char  buffer[20];   // 14 characters actually needed for display    gen.ApplySignal(SINE_WAVE,REG0,1000.0); //产生正弦波,//产生方波// gen.ApplySignal(SQUARE_WAVE, REG0, 2000.0); // 2kHz方波//产生三角波//gen.SetWaveform(REG1, TRIANGLE_WAVE);     // 设置波形//gen.SetFrequency(REG1, 500.0);            // 500Hz频率//gen.SetOutputSource(REG1);                // 选择寄存器while ( true ) {FLUSH_SERIAL_INPUTSerial.println(F("\nEnter frequency ('Q' to quit) >"));while ( !Serial.available() )   BLINK_LEDif ( toupper(Serial.peek()) == 'Q' ) {// Need an extra <CR> ?FLUSH_SERIAL_INPUT    // why isn't this flushing input?return;}requestedFrequency = Serial.parseFloat();gen.SetFrequency(REG0,requestedFrequency);programmedFrequency = gen.GetActualProgrammedFrequency(REG0);Serial.print(F("Requested :"));dtostrf(requestedFrequency,14,5,buffer); Serial.print(buffer);Serial.print(F("   Actual :"));dtostrf(programmedFrequency,14,5,buffer); Serial.println(buffer);       }
}/* * Display the command menu*/
void PrintMenu ( char ch, bool outputOn ) {Serial.println(); Serial.println();Serial.println(F("****** AD9833 Test Menu ******\n"));Serial.print(F("'1' IncrementFrequencyTest"));Serial.println(ch == '1' ? RUNNING : NOT_RUNNING);Serial.print(F("'2' CycleWaveformsTest\t"));Serial.println(ch == '2' ? RUNNING : NOT_RUNNING);Serial.print(F("'3' SwitchFrequencyRegisterTest"));Serial.println(ch == '3' ? RUNNING : NOT_RUNNING);Serial.print(F("'4' PhaseTest\t\t"));Serial.println(ch == '4' ? RUNNING : NOT_RUNNING);Serial.print(F("'5' RequestedvsProgrammedValues"));Serial.println(ch == '5' ? RUNNING : NOT_RUNNING);Serial.print(F("'6' Output "));  if ( ch == '6' ) {  if ( outputOn ) Serial.println(OFF);else            Serial.println(ON);}else {if ( outputOn ) Serial.println(ON);else            Serial.println(OFF);      }Serial.println(F("Enter a number 1 to 6 >"));
}

 

2.Demo_2

/*** @file ApplySignal-3T.ino* @author Jonnie Wlaker  CGC* @brief  AD9833_Test1* @version 0.1* @date 2025-10-02* * @copyright Copyright (c) 2025* * -----------------------------------------------------------/* * 此程序测试硬件Arduino UNO。如果你使用的其他硬件请你修改SPI通信引脚,在这个程序中没有看到引 * 脚定义是因为默认硬件为UNO开发板引脚定义被封装,* 所以你需要去查看SPI通信封装内容或调用SPI的API函数重新定义引脚。* * 在编译前先安装AD9833-Library-Arduino-master库。如果运行功能函数不知道起什么功能,可以去这 * 个库文件中查看具体封装函数信息!* * */
/*ArduinoUNO     AD9833----------------------SCK --13      CLKMOSI--11      DATPIN4--4       FNCGND           GND3.3V-5V       VCC*/#include <AD9833.h>     // Include the library#define FNC_PIN 4       // Can be any digital IO pin//--------------- Create an AD9833 object ---------------- 
// Note, SCK and MOSI must be connected to CLK and DAT pins on the AD9833 for SPI
AD9833 gen(FNC_PIN);       // Defaults to 25MHz internal reference frequencyvoid setup() {// This MUST be the first command after declaring the AD9833 objectgen.Begin();              //产生正弦波gen.ApplySignal(SINE_WAVE,REG0,1000); // 1kHz正弦波//产生三角波//gen.SetWaveform(REG1, TRIANGLE_WAVE);     // 设置波形//gen.SetFrequency(REG1, 500.0);            // 500Hz频率//gen.SetOutputSource(REG1);                // 选择寄存器//产生方波// gen.ApplySignal(SQUARE_WAVE, REG0, 2000.0); // 2kHz方波gen.EnableOutput(true);   // Turn ON the output - it defaults to OFF// There should be a 1000 Hz sine wave on the output of the AD9833
}void loop() {// To change the signal, you can just call ApplySignal again with a new frequency and/or signal// type.
}

 在Demo_2程序中分别有3处地方需要你自己去修改:

 1.产生正弦波  

 2.产生三角波

 3.产生方波

通过添加或取消注释符分别开启相应的功能,程序中已经有说明了!

3.测试数据

图4

图4中测试频率:1KHz ,输出正弦波 。

图5

图5中测试频率:500Hz ,输出三角波 。

图6

图6中测试率:2KHz ,输出方波 。

图7

图7中波形是本次测试硬件最大频率稳定波形图,带宽频率:4.59MHz.,输出正弦波。

下面是超出硬件带宽5MHz,测试数据图形:

图8

图9

图10

从图8,图9,图10波形图中可以看出测试的波形已经突变了!


总结

        AD9833 是一款将数字世界的精确性与模拟世界连接起来的桥梁芯片。 它让用户能够以极低的成本和简单的操作,生成一个在传统模拟电路中需要复杂、昂贵且不稳定的元器件才能产生的精密波形。对于任何需要可编程信号源的项目来说,它都是一个非常出色的选择。

      所以本文通过结合硬件和软件简单测试 ,展示AD9833基本功能使用步骤。 

      感谢你能看到这里!CGC

 

http://www.dtcms.com/a/447009.html

相关文章:

  • 海宁高端高端网站设计优质服务的小企业网站建设
  • 中国建设银行网站会员注册dw网站开发教程
  • 巢湖路桥建设集团网站福永响应式网站多少钱
  • CDN加速原理:从快递分仓看内容分发
  • 从 0 到 1 精通延迟消息队列实战实战实战:秒杀订单自动取消、定时支付超时处理全实战
  • 手机网站微信咨询网站建设公司销售提成
  • 第四十天:成绩排序
  • 怎么建设自己的卡盟网站创可贴网站怎么做图片大全
  • 响应式商城网站手机网页游戏排行榜前十
  • 长沙网站建设kaodezhu上海制作网站多少钱
  • 做网站要找什么软件佛山营销网站建设
  • 点估计与置信区间及假设检验详解
  • 苏州好的做网站的公司主题猫-wordpress
  • 网站空间流量轻定制网站建设
  • List\Tuple\Set 这些数据类型大写和不大写
  • 做一个免费网站的流程郑州网站建
  • 李宏毅机器学习笔记16
  • 建网站的几个公司iis 设置此网站的访问权限
  • 网站需要域名吗为何网站打不开
  • 企业品牌网站营销网站改版后百度不收录
  • 2025年实用大模型工具清单
  • 网站定制开发上海建设网站费用
  • 黔东南州住房和城乡建设局网站石家庄商城网站建设
  • 【循环神经网络6】LSTM实战——基于LSTM的IMDb电影评论情感分析
  • 数据库原理及应用_第3篇数据库设计_第9章关系模型规范化设计理论_关系模式规范化
  • wordpress网站 添加微信支付专注郑州网站建设
  • 自己做网站平台淘宝客网站如何做推广
  • fastboot getvar all 输出完整解析
  • 动易cms网站后台很慢是什么原因asp网站首页
  • 上高做网站公司公司简介ppt内容