【Follow me第二期】基础任务 - DAC+OPAMP+ADC以及上位机波形显示
[复制链接]
前阵子因为事务繁忙,没来得及更新Follow me的相关测评任务。趁着国庆假期有一些闲暇,把相关任务再完成完成。
本次活动的基础任务主要涉及Arduino内置的DAC,ADC还有运算放大器OPAMP的使用。这些组件对于电子项目的开发至关重要,它们能够处理模拟信号,为数字世界提供精确的数据。
1. 本地IDE的安装
由于本次测评需要直观地展示波形,而我们目前缺乏便携式示波器,因此我们将采用Arduino IDE内置的串口绘图工具(Serial Plotter)作为替代方案。这一工具能够将串口传输的数据实时转化为波形图,为缺乏专业设备的用户提供了极大的便利。
为了使用串口绘图工具,我们首先需要安装Arduino IDE。用户可以从Arduino官方网站的【Software | Arduino】页面下载安装包。安装完成后,您可以在IDE的右上角轻松找到串口绘图工具的入口。
在基础任务中,我们将通过串口发送采集到的数据至IDE,并利用串口绘图工具将这些数据绘制成波形图,以此模拟示波器的功能。
2. 基础任务(必做):用DAC生成正弦波
为了更好地理解和运用DAC模块,我们将参考官方文档【Arduino UNO R4 WiFi Digital-to-Analog Converter (DAC) | Arduino Documentation】,了解如何利用Arduino的内部DAC模块生成特定形状的波形。我们将使用analogWave库,并通过配置使其通过DAC输出波形。
我们计划将输出波形的频率设定为100Hz,并将输出幅度设置为量程的0.5倍(即1.65V)。尽管Arduino理论上能够输出这样的正弦波,但受限于没有示波器,我们无法直观地观察输出波形。
#include "analogWave.h"
analogWave wave(DAC);
int freq = 100;
void setup() {
// put your setup code here, to run once:
wave.sine(freq);
wave.amplitude(0.5);
}
为解决这一问题,我们将调用ADC模块,将DAC输出的模拟信号再转回数字信号,并通过串口发送。通过配置串口的传输波特率并开启串口,发送的数据将基于ADC采集得到。我们通过Serial来配置串口的传输波特率并打开串口,其发送的数据将由ADC采样得到。
Arduino的DAC默认输出口设为A0,我们将使用analogRead绑定A0来读取DAC输出的电平。ADC发送的数字信号为二进制数据,Arduino支持的数字信号最高14位精度,我们可以使用analogReadResolution函数进行调整。
相比于使用示波器,使用ADC采样并通过串口发送数据绘制波形时,可能面临波特率与采样频率不匹配的问题。例如,初始设置的串口波特率为2000000,采样位数为14位,代码示例如下:
#include "analogWave.h"
analogWave wave(DAC);
int freq = 100;
void setup() {
// put your setup code here, to run once:
Serial.begin(2000000);
analogReadResolution(14);
wave.sine(freq);
wave.amplitude(0.5);
}
void loop() {
// put your main code here, to run repeatedly:
int value = analogRead(A0);
Serial.println(value);
}
观察到波形中出现了许多台阶,这可能是由于串口发送速率过快,导致相同数据的重复发送。串口的print和println函数在绘制波形时,默认以数据采集的个数为分度,因此重复数据形成了台阶。
由于ADC采样频率有上限,我们尝试降低串口波特率以获得更直观的波形展示。将ADC采样精度降低至8位以便换算,最终选定波特率为250000,绘制结果如下:
尽管波形上的台阶仍然存在,但长度已显著缩短,验证了之前的假设。此时,波形曲线大约每隔二至三个点就会更新一次数据,表明需要更精细地调整波特率。由于可用的波特率并不是连续可调的,如果使用115200波特率,波形将仅在几个点上出现台阶,如下图所示,图形非常不美观;而使用更低的波特率必将导致某些采样点缺失。
为避免数据重复发送,我们最终选择在循环中加入了1ms的延时。当然,我们也可以通过计算波特率和采样频率来准确计算数据发送的间隔,并使用delayMicroseconds函数实现微秒级精确延时。最终的完整代码如下:
#include "analogWave.h"
analogWave wave(DAC);
int freq = 100;
void setup() {
// put your setup code here, to run once:
Serial.begin(250000);
analogReadResolution(8);
wave.sine(freq);
wave.amplitude(0.5);
}
void loop() {
// put your main code here, to run repeatedly:
int value = analogRead(A0);
Serial.println(value);
delay(1);
}
在IDE的串口绘制工具中,我们得到了相对完整的波形,虽然它不是完美的正弦波,但幅度与设置的一致(使用8位精度,最大值为255,0.5倍量程,最大幅值应在128左右,最高点可能未被采集或发送):
动态图像可以在后面的结果视频中查看。在后续的模块绘制任务中,我们将按照这个波特率和采样精度对串口和ADC进行配置。
3. 基础任务(必做):用OPAMP放大DAC信号
在进行OPAMP模块的任务之前,我们首先参考了官方文档【Arduino UNO R4 WiFi OPAMP | Arduino Documentation】,,以了解Arduino内置运算放大器的管脚配置。里面介绍了Arduino运放的管脚配置如下:
文档中是以一个电压跟随器为例的,其中输入信号连接至A1(运放的正输入端),A2作为负输入端,A3则作为输出端。为了实现电压跟随效果,我们将A2和A3直接连接,这样A3的输出电压将恒等于A1的输入电压。
若要实现电压放大功能,我们可以通过在A2和A3之间分配不同比例的电阻来实现预定比例的电压放大。常用的同相放大电路图如下:
根据理想运放的“虚短”和“虚断”特性,很容易推导得到如下表达式,即放大的倍数为(1+R2/R1)。以一个两倍的电压放大电路为例,我们只需要取R1与R2相等,就能够实现一个两倍的放大。
我们选择R1和R2均为10kΩ的电阻。电路连接方式如下:A0作为DAC的输出,与A1相连,作为运放的同相输入端;A2作为运放的反相输入端,通过R1和R2电阻分别连接至GND和A3。
在代码中,我们需要配置好OPAMP模块,调用OPAMP.h头文件,并设置运放的工作模式为高速模式。由于ADC读取的数值来源于运放的输出端口,我们将analogRead端口绑定为A3。完整的代码如下:
#include "analogWave.h"
#include <OPAMP.h>
analogWave wave(DAC);
int freq = 100;
void setup() {
// put your setup code here, to run once:
Serial.begin(250000);
analogReadResolution(8);
wave.sine(freq);
wave.amplitude(0.5);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
void loop() {
// put your main code here, to run repeatedly:
int value = analogRead(A3);
Serial.println(value);
delay(1);
}
最终的结果如图所示:
由于我们设计的是一个二倍放大器,所以从ADC采样到的电压从原来的半量程(8位,约128)增加到了满量程(255左右),成功实现了输出电压的翻倍。动态的图像可以在后面的结果视频中查看。
4. 基础任务(必做):用ADC采集并上传到上位机显示
在本任务中,我们将通过ADC模块采集信号,并利用上位机进行显示,以直观地呈现信号的变化。这一过程在前两个任务中已有展示,本次任务将对之前的DAC输出信号和经OPAMP放大后的信号进行汇总显示,从而直观地展示放大器的效果。
由于DAC输出和OPAMP输出位于不同的管脚,我们需要分别对这两个信号进行ADC模拟读取。值得注意的是,当通过串口交替传输这两个信号时,不能连续使用println函数,因为这会导致串口绘图工具将它们视为同一个变量进行绘制,如下:
为了避免这一问题,我们需要在数据之间手动插入换行或空格来进行区分。最终的代码示例如下:
#include "analogWave.h"
#include <OPAMP.h>
analogWave wave(DAC);
int freq = 100;
void setup() {
// put your setup code here, to run once:
Serial.begin(250000);
analogReadResolution(8);
wave.sine(freq);
wave.amplitude(0.5);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
void loop() {
// put your main code here, to run repeatedly:
int dacvalue = analogRead(A0);
int opampvalue = analogRead(A3);
Serial.print(dacvalue);
Serial.print(" ");
Serial.println(opampvalue);
delay(1);
}
最终结果如下:
在图中,蓝线代表DAC的输出信号,而红线代表经OPAMP放大后的信号,直观地展示了二倍电压放大的效果。动态的图像可以在后面的结果视频中查看。
有一个疑问就是,DAC的输出是否一定绑定在A0这个端口,是否可以通过配置信息来进行修改?之前因为疏忽忘记把A0和A1这条给连在一起了,导致输出的不正常,所以想到除了我们这样在外电路飞线连接的方式,是否有在Arduino内部直接进行配置连接的方式呢?
DAC+OPAMP+ADC
|