如何使用Arduino和AD9833构建信号发生器

如果您是像我这样想要调整不同电子电路的电子爱好者,那么拥有一个像样的函数发生器有时是必不可少的。但是拥有一个是个问题,因为这样的基本设备可能要花一大笔钱。构建自己的测试设备不仅更便宜,而且是提高知识的好方法。
因此,在本文中,我们将使用 arduino 和 ad9833 dds 函数发生器模块构建一个简单的信号发生器,它可以在输出端产生最大频率为 12 mhz 的正弦波、方波和三角波。最后,我们将在示波器的帮助下测试输出频率。
什么是 dds 函数发生器?
顾名思义,函数发生器是一种可以通过设置输出特定频率的特定波形的设备。例如,假设您有一个 想要测试输出频率响应的lc 滤波器,您可以在函数发生器的帮助下轻松做到这一点。您需要做的就是设置所需的输出频率和波形,然后您可以调低或调高它以测试响应。这只是一个例子,随着列表的继续,你可以用它做更多的事情。
dds 代表直接数字合成。它是一种波形发生器,使用数模转换器(dac) 从头构建信号。此方法专门用于生成正弦波。但是我们使用的ic可以产生方波或三角波信号。dds 芯片内部发生的操作是数字的,因此它可以非常快速地切换频率,也可以非常快速地从一个信号切换到另一个信号。该设备具有良好的频率分辨率和宽频谱。
了解 ad9833 函数发生器 ic 的工作原理
我们项目的核心是由模拟设备设计和开发的ad9833可编程波形发生器 ic。它是一种低功耗、可编程波形发生器,能够产生最大频率为 12 mhz 的正弦波、三角波和方波。这是一款非常独特的 ic,只需一个软件程序即可改变输出频率和相位。它有一个 3 线 spi 接口,这就是为什么与这个 ic 通信变得非常简单和容易的原因。该ic的功能框图如下所示。
该ic的工作非常简单。如果我们看一下上面的功能框图,我们会发现我们有一个相位累加器,它的工作是存储从 0 到 2π 的所有可能的正弦波数字值。接下来,我们有 sin rom,其工作是将相位信息转换为以后可以直接映射到幅度的信息。sin rom 使用数字相位信息作为查找表的地址,并将相位信息转换为幅度。最后,我们有一个 10 位数模转换器,它的工作是从 sin rom 接收数字数据并将其转换为相应的模拟电压,这就是我们从输出中得到的电压。在输出端,我们还有一个开关,只需一点软件代码就可以打开或关闭它。我们将在本文后面讨论。ad9833 数据表,您也可以查看它以获取更多信息。
构建基于 ad9833 的函数发生器所需的组件
下面列出了构建基于 ad9833 的函数发生器所需的组件,我们使用非常通用的组件设计了这个电路,这使得复制过程非常容易。
arduino 纳米 - 1
ad9833 dds 函数发生器 - 1
128 x 64 oled 显示屏 - 1
通用旋转编码器 - 1
dc 桶形千斤顶 - 1
lm7809 稳压器 - 1
470uf 电容 - 1
220uf 电容 - 1
104pf 电容 - 1
10k 电阻 - 6
轻触开关 - 4
螺丝端子 5.04mm - 1
女头 - 1
12v 电源 - 1
基于 ad9833 的函数发生器 - 原理图
ad9833 和基于 arduino 的函数发生器的完整电路图如下所示。
我们将使用带有 arduino 的 ad9833来生成我们想要的频率。在本节中,我们将借助原理图解释所有细节;让我简要概述一下电路发生的情况。让我们从ad9833 模块开始。 ad9833模块为函数发生器模块,按照原理图与arduino连接。为了给电路供电,我们使用了 lm7809 稳压器 ic,它带有一个不错的去耦电容,这是必要的,因为电源噪声会干扰输出信号,从而导致不需要的输出。与往常一样,arduino 是这个项目的大脑。为了显示设定频率和其他有价值的信息,我们连接了一个 128 x 64 oled 显示模块。为了改变频率范围,我们使用了三个开关。第一个将频率设置为 hz,第二个将输出频率设置为 khz,第三个将频率设置为 mhz,我们还有另一个按钮可用于启用或禁用输出。最后,我们有旋转编码器,我们必须连接一些上拉电阻,否则这些开关将不起作用,因为我们正在检查池方法上的按钮按下事件。旋转编码器用于改变频率,旋转编码器内部的轻触开关用于选择设定的波形。
基于 ad9833 的函数发生器 - arduino 代码
此项目中使用的完整代码可在此页面底部找到。添加所需的头文件和源文件后,应该可以直接编译arduino文件了。您可以从下面给出的链接下载ad9833 arduino 库和其他库,或者您可以使用板管理器方法安装库。
ino中的代码说明。文件如下。首先,我们首先包含所有必需的库。ad9833 dds 模块库首先是 oled 库,我们的一些计算需要数学库。
 ino中的代码说明。文件如下。首先,我们首先包含所有必需的库。ad9833 dds 模块库首先是 oled 库,我们的一些计算需要数学库。
#include // ad9833 模块库#include // oled 线库#include // oled 支持库#include // oled 库#include // 数学库  
接下来,我们为按钮、开关、旋转编码器和 oled 定义所有必要的输入和输出引脚。
#define screen_widata_pinh 128 // oled 显示宽度(以像素为单位)#define screen_height 64 // oled 显示高度,以像素为单位#define set_frequency_hz a2 // 以hz为单位设置频率的按钮#define set_frequency_khz a3 // 以 khz 为单位设置频率的按钮#define set_frequency_mhz a6 // 以 mhz 为单位设置频率的按钮#define enable_disable_output_pin a7 // 启用/禁用输出的按钮#define fnc_pin 4 // ad9833 模块需要的 fsync#define clk_pin 8 // 编码器的时钟引脚#define data_pin 7 // 编码器的数据引脚#define btn_pin 9 // 编码器上的内部按钮  
此后,我们定义了此代码中所需的所有必要变量。首先,我们定义一个整数变量计数器来存储旋转编码器的值。接下来的两个变量clockpin和clockpinstate存储理解编码器方向所需的引脚状态。我们有一个时间变量来保存当前的定时器计数器值,这个变量用于按钮去抖动。接下来,我们有一个无符号长变量modulefrequency,它保存了计算的频率,它将被应用。接下来,我们有debounce delay。可以根据需要调整此延迟。接下来,我们有三个布尔变量set_frequency_hz,set_frequency_khz和 set_frequency_mhz 这三个变量用于确定模块的当前设置。我们将在本文后面更详细地讨论它。接下来,我们有存储输出波形状态的变量,默认输出波形是正弦波。最后,我们有encoder_btn_count变量,它保存用于设置输出波形的编码器按钮计数。
整数计数器 = 1;// 如果旋转编码器转动,此计数器值将增加或减少整数时钟引脚;// 旋转编码器使用的引脚状态占位符整数时钟引脚状态;// 旋转编码器使用的引脚状态占位符无符号长时间 = 0; // 用于去抖动无符号长模块频率;//用于设置输出频率长时间去抖 = 220; // 去抖动延迟布尔 btn_state; // 用于启用 ad98333 模块的禁用输出布尔 set_frequency_hz = 1; // ad9833模块的默认频率bool set_frequency_khz;bool set_frequency_mhz;字符串 waveselect = sin; // 模块的启动波形int 编码器_btn_count = 0; // 用于检查编码器按钮是否按下接下来,我们有两个对象,一个用于 oled 显示器,另一个用于 ad9833 模块。adafruit_ssd1306 显示(screen_widata_pinh,screen_height,&wire,-1);ad9833 gen(fnc_pin);  
接下来,我们有我们的setup()函数,在该 setup 函数中,我们首先启用 serial 进行调试。我们借助begin()方法初始化 ad9833 模块。接下来,我们将所有分配的旋转编码器引脚设置为输入。而我们将时钟引脚的值存储在clockpinstate变量中,这是旋转编码器的必要步骤。
接下来,我们将所有按钮引脚设置为输入,并在display.begin()方法的帮助下启用 oled 显示,我们还使用if 语句检查是否有任何错误。完成后,我们清除显示并打印启动启动画面,我们添加 2 秒的延迟,这也是启动画面的延迟,最后,我们调用update_display()函数清除屏幕并更新再次显示。update_display()方法的细节将在本文后面讨论。
无效设置(){ 序列号.开始(9600);// 启用串行@9600 波特 gen.begin(); // 这必须是声明 ad9833 对象后的第一个命令 pinmode(clk_pin,输入);// 将引脚设置为输入 pinmode(data_pin,输入); pinmode(btn_pin,input_pullup); clockpinstate = digitalread(clk_pin); pinmode(set_frequency_hz, input);// 将引脚设置为输入 pinmode(set_frequency_khz,输入); pinmode(set_frequency_mhz,输入); pinmode(enable_disable_output_pin,输入); if (!display.begin(ssd1306_switchcapvcc, 0x3c)) { // 地址 0x3d 为 128x64 serial.println(f(ssd1306 分配失败)); 为了 (;;); } display.cleardisplay(); //清屏 display.settextsize(2); // 设置文本大小 display.settextcolor(白色);//设置液晶颜色 display.setcursor(30, 0); // 设置光标位置 display.println(ad9833); // 打印这个文本 display.setcursor(17, 20); // 设置光标位置 display.println(函数); // 打印这个文本 display.setcursor(13, 40); // 设置光标位置 display.println(生成器); // 打印这个文本 显示.显示();// 更新显示 延迟(2000);// 延迟 2 秒 更新显示();// 调用 update_display 函数}  
接下来,我们有我们的loop()函数,所有主要功能都写在循环部分。
首先,我们读取旋转编码器的时钟引脚并将其存储在我们之前声明的 clockpin 变量中。接下来,在if语句中,我们检查 pin 的先前值和 pin 的当前值是否相似,我们还检查 pin 的当前值。如果全部为真,我们检查数据引脚,如果为真,则表示编码器逆时针旋转,我们在counter--命令的帮助下减少计数器值。否则,我们使用counter ++命令增加计数器值。最后,我们用另一个if语句将最小值设置为 1。接下来,我们用当前的clockpin更新clockpinstate未来使用的价值。
无效循环(){ clockpin = digitalread(clk_pin); if (clockpin != clockpinstate && clockpin == 1) { if (digitalread(data_pin) != clockpin) { 柜台 - ; } 别的 { counter ++;// 编码器顺时针旋转,因此递增 } 如果 (计数器 denounce), 在此语句中,我们首先检查按钮是否引脚是否为低电平,如果它为低电平,则它被按下。然后我们再次检查带有去抖动延迟的计时器值,如果两个语句都为真,那么我们声明它是一个成功的按钮按下动作,如果这样我们增加encoder_btn_count值。接下来,我们声明另一个 if 语句将最大计数器值 设置为 2,我们需要它,因为我们正在使用它来设置输出波形。连续三个 if 语句就是这样做的,如果值为 0,则选择正弦波,如果为 1,则为方波,如果值为 2,则为三角波。在所有这三个 if 语句中,我们使用 update_display() 函数更新显示。 最后,我们用当前的计时器计数器值更新时间变量。
//如果我们检测到一个low信号,按钮被按下 if ( digitalread(btn_pin) == low && millis() - time > debounce) { 编码器_btn_count++;// 增加值 if (encoder_btn_count > 2) // 如果值大于 2 将其重置为 0 { 编码器_btn_count = 0; } if (encoder_btn_count == 0) { // 如果值为 0 则选择正弦波 波选择=“罪”;// 用 sin 值更新字符串变量 更新显示();// 更新显示 } if (encoder_btn_count == 1) { // 如果值为 1 则选择方波 波选择 = sqr; // 用 sqr 值更新字符串变量 更新显示();// 更新显示 } if (encoder_btn_count == 2) { // 如果值为 1 则选择三角波 波选择=“三”;// 用 tri 值更新字符串变量 update_display();// 更新显示 } 时间=毫秒();// 更新时间变量 }  
接下来,我们定义所有必要的代码,这些代码需要设置所有具有去抖动延迟的按钮。由于按钮连接到 arduino 的模拟引脚,我们使用模拟读取命令来识别按钮按下,如果模拟读取值低于 30,则我们检测其成功按下按钮,我们等待 200 毫秒检查它是实际的按钮按下还是仅是噪音。 如果此陈述为真,我们为布尔变量分配用于设置函数发生器的 hz、khz 和 mhz 值的值。接下来,我们更新显示并更新时间变量。我们为与 arduino 连接的所有四个按钮执行此操作。
if (analogread(set_frequency_hz) debounce) { set_frequency_hz = 1; //更新布尔值 设置频率khz = 0; set_frequency_mhz = 0; update_display();// 更新显示 time = millis();// 更新时间变量 } if (analogread(set_frequency_khz) debounce){ set_frequency_hz = 0; //更新布尔值 set_frequency_khz = 1; set_frequency_mhz = 0; 模块频率 = 计数器 * 1000; update_display();// 更新显示 time = millis();// 更新时间变量 } if (analogread(set_frequency_mhz) debounce ) { // 使用去抖延迟检查模拟引脚 set_frequency_hz = 0; //更新布尔值 设置频率khz = 0; set_frequency_mhz = 1; 模块频率 = 计数器 * 1000000; update_display();// 更新显示 time = millis();// 更新时间变量 } if (analogread(enable_disable_output_pin) debounce ) {// 使用去抖延迟检查模拟引脚 btn_state = ! btn_state; // 反转按钮状态 gen.enableoutput(btn_state); // 根据按钮状态启用/禁用函数发生器的输出 update_display();// 更新显示 time = millis();// 更新时间变量 }}  
最后,我们有了update_display()函数。在此功能中,我们所做的不仅仅是更新此显示器,因为显示器的某些部分无法在 oled 中更新。要更新它,您必须使用新值重新绘制它。这使得编码过程变得更加困难。
在这个函数中,我们从清除显示开始。接下来,我们设置所需的文本大小。此后,我们设置光标并使用display.println(function function); 打印函数生成器;命令。在display.setcursor(0, 20) 函数  的帮助下, 我们再次将文本大小设置为 2,将光标设置为 (0,20 ) 。
这是我们打印波浪信息的地方。
display.cleardisplay(); // 首先清除显示 display.settextsize(1); //设置文字大小 display.setcursor(10, 0); // 设置光标位置 display.println(函数生成器); //打印文本 display.settextsize(2);//设置文字大小 display.setcursor(0, 20);//设置光标位置  
接下来,我们检查布尔变量以获取频率详细信息并更新modulefrequency变量中的值。我们对 hz、khz 和 mhz 值执行此操作。接下来,我们检查waveselect变量并确定选择了哪个波。现在,我们有了设置波形类型和频率的值。
if (set_frequency_hz == 1 && set_frequency_khz == 0 && set_frequency_mhz == 0 ) { // 检查设置频率的按钮是否被按下 模块频率 = 计数器;//用当前计数器值更新modulefrequency变量 } if (set_frequency_hz == 0 && set_frequency_khz == 1 && set_frequency_mhz == 0 ) { // 检查是否按下了设置 khz 频率的按钮 modulefrequency = counter * 1000;//用当前计数器值更新 modulefrequency 变量,但我们乘以 1000 将其设置为 khz } if (set_frequency_hz == 0 && set_frequency_khz == 0 && set_frequency_mhz == 1) { // 检查是否按下了以mhz为单位的频率设置按钮 模块频率 = 计数器 * 1000000; 如果(模块频率> 12000000) { 模块频率 = 12000000;// 不要让频率超过 12mhz 计数器 = 12; } } if (waveselect == sin) { // 正弦波被选中 display.println(sin); gen.applysignal(sine_wave, reg0, modulefrequency); serial.println(modulefrequency); } if (waveselect == sqr) {// sqr 波被选中 display.println(sqr); gen.applysignal(square_wave, reg0, modulefrequency); serial.println(modulefrequency); } if (waveselect == tri) {// 三波被选中 display.println(tri); gen.applysignal(triangle_wave, reg0, modulefrequency); // 更新 ad9833 模块。 serial.println(modulefrequency); }  
我们再次设置光标并更新计数器值。我们再次检查布尔值以更新显示器上的频率范围,我们必须这样做,因为 oled 的工作原理非常奇怪。
display.setcursor(45, 20); display.println(计数器); // 在显示器上打印计数器信息。 如果(set_frequency_hz == 1 && set_frequency_khz == 0 && set_frequency_mhz == 0){ display.setcursor(90, 20); display.println(hz); // 在显示器上打印 hz 显示.显示();// 当所有设置更新显示 } 如果(set_frequency_hz == 0 && set_frequency_khz == 1 && set_frequency_mhz == 0){ display.setcursor(90, 20); display.println(khz); 显示.显示();// 当所有设置更新显示 } if (set_frequency_hz == 0 && set_frequency_khz == 0 && set_frequency_mhz == 1) { display.setcursor(90, 20); display.println(mhz); 显示.显示();// 当所有设置更新显示 }  
接下来,我们检查按钮按下变量以将输出打开/输出关闭到 oled。由于 oled 模块,这再次需要完成。
如果(btn_state){ display.settextsize(1); display.setcursor(65, 45); display.print(输出开启); // 打印输出到显示器 显示.显示(); display.settextsize(2); } 别的 { display.settextsize(1); display.setcursor(65, 45); display.print(输出关闭); // 打印输出到显示器 显示.显示(); display.settextsize(2); }  
这标志着我们编码过程的结束。如果此时有疑惑,可以查看代码中的注释进一步理解。
测试基于 ad9833 的函数发生器
为了测试电路,使用上述设置。如您所见,我们已将 12v 直流电源适配器连接到 dc 筒形插孔,并将 hantek 示波器连接到电路的输出端。我们还将示波器连接到笔记本电脑,以可视化和测量输出频率。
完成后,我们在旋转编码器的帮助下将输出频率设置为 5khz,并测试输出正弦波,果然,输出端是 5khz 正弦波。
接下来,我们将输出波形改为三角波,但频率保持不变,输出波形如下图所示。
然后我们把输出改成方波,观察输出,是一个完美的方波。
我们还改变了频率范围并测试了输出,它运行良好。
进一步增强
该电路只是概念验证,需要进一步增强。首先,我们需要一块优质的 pcb 和一些优质的 bnc 连接器用于输出,否则我们无法获得更高的频率。模块的幅度非常低,因此为了增强它,我们需要一些运算放大器电路来放大输出电压。可以连接电位计以改变输出幅度。可以连接一个用于抵消信号的开关;这也是必备功能。此外,代码需要大量改进,因为它有点错误。最后,oled 显示器需要更换,否则无法编写易于理解的代码。
#include // ad9833 模块
库 #include // oled 线库
#include // oled 支持库
#include // oled 库
#include // 数学库
#define screen_widata_pinh 128 // oled 显示屏宽度,以像素为单位
#define screen_height 64 // oled 显示屏高度,以像素为单位
#define set_frequency_hz a2 // 设置频率的按钮,以 hz 为单位
#define set_frequency_khz a3 // 以 khz 为单位设置频率
的按钮 #define set_frequency_mhz a6 // 以 mhz 为单位设置频率的按钮
#define enable_disable_output_pin a7 // 启用/禁用输出的按钮
#define fnc_pin 4 // ad9833 模块所需的 fsync
#define clk_pin 8 // 编码器时钟引脚
#define data_pin 7 // 编码器数据引脚
#define btn_pin 9 // 编码器内部按钮
int counter = 1; // 如果旋转编码器转动
int clockpin; // 这个 counter 值会增加或减少 // 旋转编码器使用的占位符 por 引脚状态
int clockpinstate; // 旋转编码器使用的占位符 por 引脚状态
unsigned long time = 0; // 用于去抖动
unsigned long modulefrequency; // 用于设置输出频率

long debounce = 220; // 去抖动延迟
bool btn_state; // 用于启用 ad98333 模块的禁用输出
bool set_frequency_hz = 1; // ad9833模块的默认频率
bool set_frequency_khz; 
bool set_frequency_mhz; 
字符串 waveselect = sin; // 模块启动波形
int encoder_btn_count = 0; // 用于检查编码器按钮按下
adafruit_ssd1306 display(screen_widata_pinh, screen_height, &wire, -1); 
ad9833 gen(fnc_pin); 
无效设置(){
  序列.开始(9600);
  gen.begin(); // 这必须是声明 ad9833 对象
  pinmode(clk_pin, input) 后的第一个命令;
  pinmode(data_pin,输入);
  pinmode(btn_pin,input_pullup);
  clockpinstate = digitalread(clk_pin); 
  pinmode(set_frequency_hz,输入);
  pinmode(set_frequency_khz,输入);
  pinmode(set_frequency_mhz,输入);
  pinmode(enable_disable_output_pin,输入);
  if (!display.begin(ssd1306_switchcapvcc, 0x3c)) { // 地址 0x3d for 128x64 
    serial.println(f(ssd1306 allocation failed)); 
    为了 (;;); 
  } 
  display.cleardisplay(); // 清屏
  display.settextsize(2); // 设置文本大小
  display.settextcolor(white); // 设置 lcd 颜色
  display.setcursor(30, 0); // 设置光标位置
  display.println(ad9833); // 打印这个文本
  display.setcursor(17, 20); // 设置光标位置
  display.println(function); // 打印这个文本
  display.setcursor(13, 40); // 设置光标位置
  display.println(generator); // 打印这个文本
  显示.显示();// 更新显示
  延迟(2000);// 延迟 2 秒
  update_display(); // 调用 update_display 函数

void loop() 

  clockpin = digitalread(clk_pin); 
  if (clockpin != clockpinstate && clockpin == 1) { 
    if (digitalread(data_pin) != clockpin) {
      计数器 --; 
    } 
    else { 
      counter ++;// 编码器顺时针旋转,所以递增
    } 
    if (counter debounce) { 
    encoder_btn_count++; // 增加值
    if (encoder_btn_count > 2) // 如果值大于 2 将其重置为 0 
    { 
      encoder_btn_count = 0; 
    } 
    if (encoder_btn_count == 0) { // 如果值为 0 则选择正弦波
      waveselect = sin; // 用 sin 值更新字符串变量
      update_display(); // 更新显示
    } 
    if (encoder_btn_count == 1) { // 如果值为 1 则选择方波
      waveselect = sqr; // 使用 sqr 值更新字符串变量
      update_display(); // 更新显示
    }
    if (encoder_btn_count == 2) { // 如果值为 1 则选择三角波
      waveselect = tri; // 用 tri 值更新字符串变量
      update_display();// 更新显示
    } 
    time = millis(); // 更新时间变量
  } 
  // 使用analogread方法检查按钮按下动作
  // 稍微延迟以帮助消除读数
  if (analogread(set_frequency_hz) debounce) { // 检查analogpin有去抖延迟
    //更新布尔值
    set_frequency_hz = 1; 
    设置频率khz = 0;
    set_frequency_mhz = 0; 
    update_display();// 更新显示
    time = millis();// 更新时间变量
  } 
  if (analogread(set_frequency_khz) debounce) { // 使用 debounce delay 检查analogpin 
    //更新布尔值
    set_frequency_hz = 0; 
    set_frequency_khz = 1; 
    set_frequency_mhz = 0; 
    模块频率 = 计数器 * 1000;
    update_display();// 更新显示
    时间 = millis();// 更新时间变量
  } 
  if (analogread(set_frequency_mhz) debounce ) { // 使用 debounce delay 检查analogpin 
    //update布尔值
    set_frequency_hz = 0; 
    设置频率khz = 0;
    set_frequency_mhz = 1;
    模块频率 = 计数器 * 1000000;
    update_display();// 更新显示
    时间 = millis();// 更新时间变量
  } 
  if (analogread(enable_disable_output_pin) debounce ) {// 使用 debounce delay 检查analogpin 
    btn_state = ! btn_state; // 反转按钮状态
    gen.enableoutput(btn_state); // 根据按钮状态启用/禁用函数发生器的输出
    update_display();// 更新显示
    time = millis();// 更新时间变量
  } 

void update_display() 

  display.cleardisplay(); // 首先清除显示
  display.settextsize(1); //设置文本大小
  display.setcursor(10, 0); // 设置光标位置
  display.println(function generator); //打印文本
  display.settextsize(2);//设置文本大小
  display.setcursor(0, 20);//设置光标位置
  if (set_frequency_hz == 1 && set_frequency_khz == 0 && set_frequency_mhz == 0 ) { / / 检查是否按下了以hz为单位设置频率的按钮
    modulefrequency = counter; //更新模块频率变量与当前计数器值
  }
  if (set_frequency_hz == 0 && set_frequency_khz == 1 && set_frequency_mhz == 0 ) { // 检查是否按下了设置 khz 频率的按钮
    modulefrequency = counter * 1000;//更新模块频率变量与当前计数器值但我们相乘1000 to set it on khz 
  } 
  if (set_frequency_hz == 0 && set_frequency_khz == 0 && set_frequency_mhz == 1) { // 检查设置频率的按钮是否被按下
    modulefrequency = counter * 1000000; 
    if (modulefrequency > 12000000) 
    { 
      modulefrequency = 12000000; // 不要让频率大于 12mhz
      计数器 = 12; 
    } 
  } 
  if (waveselect == sin
    display.println(sin); 
    gen.applysignal(sine_wave, reg0, modulefrequency); 
    serial.println(modulefrequency); 
  } 
  if (waveselect == sqr) {// 选择 sqr 波
    display.println(sqr); 
    gen.applysignal(square_wave, reg0, modulefrequency); 
    serial.println(modulefrequency); 
  } 
  if (waveselect == tri) {// 选择三波
    display.println(tri); 
    gen.applysignal(triangle_wave, reg0, modulefrequency); // 更新 ad9833 模块。
    serial.println(modulefrequency); 
  } 
  display.setcursor(45, 20); 
  display.println(计数器); // 在显示屏上打印计数器信息。
  if (set_frequency_hz == 1 && set_frequency_khz == 0 && set_frequency_mhz == 0 ) { 
    display.setcursor(90, 20); 
    display.println(hz); // 在显示器上打印 hz 
    display.display(); // 当所有设置更新显示
  } 
  if (set_frequency_hz == 0 && set_frequency_khz == 1 && set_frequency_mhz == 0 ) { 
    display.setcursor(90, 20); 
    display.println(khz); 
    显示.显示();// 当所有设置更新显示
  } 
  if (set_frequency_hz == 0 && set_frequency_khz == 0 && set_frequency_mhz == 1) { 
    display.setcursor(90, 20); 
    display.println(mhz); 
    显示.显示();
  if (btn_state) {  
    display.settextsize(1); 
    display.setcursor(65, 45); 
    display.print(输出开启); // 将输出打印到显示器
    display.display(); 
    display.settextsize(2); 
  }
  其他 { 
    display.settextsize(1); 
    display.setcursor(65, 45); 
    display.print(输出关闭); // 打印输出到显示器
    display.display(); 
    display.settextsize(2); 
  } 
}

OLED产线陆续量产,材料“卡喉”如何补救?
安富利向行易道科技颁赠2021财年最佳战略合作伙伴奖杯
军品任务回暖业绩拐点显现 军用市场向产业链纵深发展
completion是什么?怎么使用?
浙江省物联网产业协会举行第四期“协企沙龙
如何使用Arduino和AD9833构建信号发生器
digilentSinoV-TE110P数字卡介绍
大电流电感定制电感的案例
d触发器芯片的工作原理
dcdc模块可以反向吗 dcdc模块可以并联吗 dcdc模块可以抗干扰吗
安波福荣膺中国汽车新供应链百强
光纤色散是什么?如何进行色散补偿?光纤色散对光信号的影响
康佳便携式榨汁机,让生活变得更简单
全球任何地方均可控制超低功耗CC2650无线微控制器
Ethisphere宣布安森美半导体连续第六次入选 2021年世界最道德企业之一
简化HEV 48-V系统的隔离CAN、电源接口
VR企业活下去就有机会成为巨头?
智能NFC芯片已成标配 手机没电是否还能继续使用
人工智能下的车型识别是如何实现的
采样示波器和实时示波器的区别