火柴盒示波器的制作

电子说

1.2w人已加入

描述

步骤1:以每秒1M个样本进行采样

示波器

我们称这个示波器为“ArdOsc”(因为这是INO文件的名称)。

六年前,Cristiano Lino Fontana为他的Girino设计发布了一个Instructable。

它有点工作但有问题。特别是,它的最大可靠采样率约为37ksps(75ksps偶尔会冻结)并且触发器似乎无法正常工作。它也没有显示。

Girino很慢,因为它使用中断。由于保存和恢复寄存器所需的代码,中断很慢。中断是危险的,因为它们可能导致软件出现错误,而且很少发生错误。我已经编写了40年的嵌入式代码,我尽可能避免中断。轮询好,中断不好。注意我的话。

因此,ArdOsc禁用所有中断,进入紧密循环并在需要时从ADC中获取数据。如果ADC没有完成:太糟糕了 - 只要给我你所拥有的。它抓取1000个样本(每个一个字节),然后重新启用中断并通过串行端口以115200波特率将字节发送到PC - 或者它抓取128个样本并将其显示在屏幕上。

Girino Instructable详细描述了Arduino ADC。如果您有兴趣,请阅读并阅读Atmega328p数据表。我只想告诉你大纲。

Arduino ADC使用“逐次逼近”。它测量最重要的位 - 是0还是1?得到它之后,它将其“到目前为止的答案”与输入电压进行比较并测量下一个最重要的位。接下来。等等10位。这些位存储在ADCH寄存器(前8位)和ADCL(后两位。我只想要8位,所以我忽略了ADCL。

ADC测量全部10位时设置一个标志。但我只想要8位,所以我忽略了标志并读取ADCH是否ADC完成。我原本以为这意味着我会得到“答案到目前为止”但我没有。到目前为止的“答案”存储在其他地方,我们得到的是上传到ADCH的最后一个答案。这意味着在1Msps模式下,每个连续的4个样本集都是相同的。 Arduino草图使它们平滑,因此它们看起来很好但不会被愚弄:你看到250ksps。 (感谢AndrewJ177指出这一点 - 请参阅下面的讨论。)

测量每个位需要时间。该定时脉冲来自于将Atmega的时钟(16MHz)除以“预分频器”值:2,4,8,16,32,64或128.如果将预分频器设置为2,则为0.125uS,这对于ADC正确地进行比较 - 质量很差。预分频器= 4,表示0.25uS哪种工作 - 结果有噪声。预分频器= 8,表示0.5uS,对于8位非常合理。一般来说,每位给ADC的时间越长,工作效果就越好。

但如果你允许ADC,比如每位1uS那么它每个字节需要8uS,即125ksps - 相当慢。如果将预分频器设置得太低,则只能正确转换前几位,并且得到的图形具有大的锯齿状步长。如果将预分频器设置得过高,则需要等待很长时间才能进行转换。

因此,这是每比特时间和每秒采样之间的权衡。

我们还必须考虑输入信号需要多长时间才能改变ADC采样保持电容的电压。我们不会在每次转换之前更改通道,因此充电时间不必与Atmel文档建议的时间一样长,但仍有效果。示波器可以达到20kHz,但响应会下降。您可以看到一个50kHz的正弦波,但它的大小应该是它的四分之一。

ArdOsc代码只有一个完全正确的长度,以1Msps的速度采样 - 即它需要16个时钟周期环。另一个更复杂的循环会占用更长的采样时间。

第2步:最简单的示波器

示波器

示波器

示波器

示波器

最简单的ArdOsc由Arduino Nano(328p 16MHz)4个电阻和3个电容组成。

示波器由USB连接供电并传输帧通过USB将数据传送到PC。

输入信号被送入ADC A0引脚。在极端电压情况下,10k电阻可为Atmega提供一些保护。 Atmega引脚具有二极管,可防止其输入超过Vcc(5V)或低于0V。二极管可以传导高达1mA的电流,因此示波器的输入信号可以安全地在-10V和+ 15V之间变化。 ADC引脚的输入阻抗约为100M和14pF,因此额外的10k对ADC的精度影响不大。

ADC使用Vcc作为参考电压读取A0引脚电压 - 因此测量范围为0V至5V。 (实际上它是0到Vcc * 254/255。)不幸的是,Vcc很少是5V,所以程序读取Vcc的实际值并适当地绘制“示波器显示”的格线。

输入是也通过一个100nF电容馈入ADC A1引脚。 A1通过1M电阻连接到0.55V。因此,A1引脚看到输入信号的交流分量以0.55V为中心。

ADC使用内部1.1V参考电压读取A1引脚电压 - 因此测量值为-0.55V至+ 0.55V。

0.55V是由Nano的3V3引脚的分压器产生的。 3V3引脚电压比USB连接的“5V”稳定得多。 3V3引脚的输出不完全是3.3V,因此您必须修整分压器以提供0.55V的电压。将示波器输入连接到地,然后查看AC范围显示的“电压”。调整R1直到线位于屏幕中心 - 我需要R1 = 33k。

我已经展示了电路的条形板布局。条形板与Arduino Nano的尺寸相同,形成三明治。 Nano的底面位于条形板的铜侧(因此在图中,Nano从下方显示)。将一些引脚焊接到条板上,然后将Nano安装在引脚上并将它们焊接到Nano上。在我的图表中,条形板的铜以青色显示。红线是条形板上的导线或柔性导线从电路板上传出信号和电源。

步骤3:放大信号

示波器

示波器

示波器

“最简单”示波器有两个输入范围:

0V至5V

-0.55 V至+ 0.55V

但我们感兴趣的许多信号都小于此值。因此我们可以添加两个放大级。

LM358双运算放大器放大A1的AC信号。运算放大器采用交流耦合,两个输入均以0.55V为中心。两个运算放大器级的增益都不到5倍。它们的输出转到A2和A3,因此Atmega可以选择要采样的信号。

示波器现在有四个输入范围:

0V到5V

-0.55V至+ 0.55V

-117mV至+ 117mV

-25mV至+ 25mV

它使用相同的INO文件并且作为“最简单”的执行。

将交流信号对中在0.55V附近的优点是运算放大器信号保持低电平。 LM258输出不能在Vcc的1.5V范围内;所以它的范围是0V到3.5V - 可怕。

我已经展示了电路的条形板布局。有两个条板 - 一个用于Nano,另一个用于LM358。他们应该形成三明治。电路板从元件侧显示。精细的柔性电线连接两块板。将电路板与粘垫,焊接支架或其他任何东西连在一起。在我的图表中,条形板的铜以青色显示。红线是条形板上的线链或将板连接在一起的柔性线。我没有显示“测试引线”。

再一次,你可能需要修整分压器给0.55V。将示波器输入连接到地并调整R9直到线位于屏幕中央 - 我需要R9 = 33k。

LM358可能存在问题。如果信号大于LM358可以处理LM358的输出失真。您应该使用较高增益设置来查看小信号。如果你在大信号上使用它们,它们就会变形。你可以尝试更好的芯片 - 如果你有一个 - LM358是一个相当差的芯片。

第4步:逻辑显示

示波器

通常你在处理逻辑电平 - 示波器是否可以显示几个“逻辑”通道。是的 - 这比搞乱ADC更容易。

值得吗?可能不是,但很容易这样做为什么不呢?

示波器现在有五个输入范围:

0V到5V

-0.55V到+ 0.55V

-117mV至+ 117mV

-25mV至+ 25mV

逻辑

在“逻辑”中“模式,四个逻辑通道可以连接到Arduino引脚D8,D9,D10和D11。它们在显示屏上显示为四行。

D8至D11对应于Atmega328p芯片的端口B引脚0至3.芯片将整个端口B读入其采样缓冲器而不是ADC输出在ADCH寄存器中。

在1Msps模式下,你能看到的理论最大频率是500kHz - 但你得到的只是一个“状态变化”的实心条。实际上,250kHz信号更容易看到。

如果您不想要“逻辑”输入,则不要将连接器包括在D8到D11中。在INO文件中,将bool常量bHasLogic设置为false。 (我尝试重新编写代码以使用#define而不是bool const但是它很乱。)

步骤5:触发器

示波器

假设您正在查看重复波形,例如正弦波。如果示波器在每次扫描时在屏幕上的相同位置显示它,那就太好了。因此,示波器扫描应该被启动,就像波从负变为正。

首先我尝试使用比较器来触发扫描(即开始收集数据)吉里诺做到了。它似乎很理想,但结果却有缺点。我决定使用0.55V的固定触发电压 - 交流信号的中间位置。 Atmel允许您将比较器连接到当前ADC通道。听起来不错。但您必须关闭ADC,并在触发发生时再次将其重新打开。 ADC需要一段时间才能启动。不太好。

所以我采取简单的方法 - 运行ADC并观察它产生的值。当它们从中途下降到中途时,开始扫描。

在“逻辑”模式下,D8用作触发器。

如果没有信号则示波器应该是自由运行的。在等待一段时间后开始扫描。我选择了最长等待250毫秒。程序初始化Timer1(一个16位定时器),然后等待,直到它计算了足够数量的滴答。我只是看着Timer1的计数器 - 应该有一个更好的方法来使用标志,但它非常复杂,我无法让它100%可靠地工作。

步骤6:测试信号输出

示波器

您偶尔需要一个信号来测试您正在构建的任何电路。很多人已经有了信号发生器。

ArdOsc电路可以提供以下频率的方波:

31250/1 = 31250Hz

31250/8 = 3906Hz

31250/32 = 977Hz

31250/64 = 488Hz

31250/128 = 244Hz

31250/256 = 122Hz

31250/1024 = 31Hz

测试信号在引脚D3上生成。

如果您不想要“测试信号”输出,则不要包含连接器D3。在INO文件中,将bool常量bHasTestSignal设置为false。

步骤7:串行协议

示波器

示波器通过USB电缆将数据帧传输到PC,就好像它是115200波特,8位,无奇偶校验的串行数据流一样。

PC可以将两种命令发送到示波器。小写命令是单个字节:

‘a’将x轴设置为“1mS”= 1Msps

‘b’将x轴设置为“2mS”

‘c’将x轴设置为“5mS”

‘d’将x轴设置为“10mS”

‘e’将x轴设置为“ 20mS“

‘f’将x轴设置为”50mS“

‘g’将x轴设置为”100mS“

‘j’set y -axis to 5V

‘k’设置y轴为0.5V

‘l’设置y轴为0.1V‘m’设置y轴为200mV

‘n’将模式设置为“逻辑”

‘p’将触发设置为下降

‘q’将触发设置为上升

‘r ’设置测试信号关闭

‘s’设置测试信号31250Hz

‘t’设置测试信号3906Hz

‘u’设置测试信号976Hz

‘v’设置测试信号488Hz

‘w’设置测试信号244Hz

‘x’设置测试信号122Hz

‘y’设置测试信号30Hz

‘z’扫描并发送数据

扫描数据发送如下:

0xAA

0xBB

0xCC

1000字节数据

程序通过发送响应每个命令一个Ack字节 - “@”。

Arduino串行库使用中断来读取串行输入。扫描期间输入关闭,因此输入字节保留在Atmega的串行输入寄存器中。扫描结束时,串行库收集字节,程序可以读取它。但是如果在扫描期间到达第二个字节,它将被丢弃。

大写命令可以包含几个字节,因此如果在扫描期间发送,则会损坏。在发送大写命令之前,停止发送‘z’并等待结果。大写命令仅用于调试和测试。有几个可以包含整数十进制值‘n’:

‘A’n将ADC通道设置为n

‘B’报告“电池”电压= Vcc

‘D’报告状态

‘F’n设置频率pwm

‘R’n设置Vref为ADC

‘T’n触发上升或下降

‘U’n设置预分频器并发送扫描数据

‘V’n设置ADC的采样周期

步骤8:添加显示

示波器

示波器

示波器

示波器

示波器

示波器

示波器可以有自己的内置显示器--1.3“OLED。虽然1.3”听起来很小,但这些显示器非常清晰。

显示器有1.3“OLE运行在3.3V时,由SH1106芯片通过I2C总线控制。(SPI版本可用,但我使用Arduino SPI引脚作为“逻辑”。)

我需要一个非常快速的Arduino库和它最好是小的.U8glib库很慢而且很大,所以我自己编写。它只有很少的命令所以它叫做“SimpleSH1106”。

SH1106有一个内置缓冲区,每像素一位。它被安排为128列7个条带(其他尺寸可用)。每个样本高8像素,顶部有lsb。在SH1106文档中,swathes称为“pages”,但“swathe”是计算机图形学中的标准术语。您可以写入的最小单位是一个字节 - 从8像素边界开始的8像素列。

我的库在Arduino上没有屏幕缓冲区所以所有命令都基于将整个字节写入页面。它不太方便,但你获得1k的RAM。

Atmel328p内置I2C驱动程序连接到A4(SDA)和A5(SCL)引脚。 SDA和SCL需要上拉电阻;内置的I2C驱动程序使用Atmel328p弱上拉电阻约50kohm。 50k上拉电阻在低速下工作,但上升沿的速度不够快,因此我在Nano的3V3引脚上增加了1k的上拉电阻。

Arduino IDE有一个名为Wire.h的I2C驱动程序库。这是一个不错的小型快速库,但正如您对Arduino所期望的那样,文档记录很少。该库初始化I2C硬件以100kHz运行,但我想要更快。因此在调用Wire.begin()之后,我将Atmel328p TWBR寄存器设置为较小的值。

生成的库很快 - 示波器的扫描显示在40mS内绘制。可以使用以下命令:

void clearSH1106()用0字节(黑色)填充屏幕。

void DrawByteSH1106 绘制一个字节(一个8像素的列)。

int DrawImageSH1106 绘制图像。

int DrawCharSH1106 绘制一个角色。

int DrawStringSH1106 绘制一个字符串。

int DrawIntSH1106 绘制一个整数。

图像在程序存储器(PROGMEM)中声明。提供了一个Windows程序,用于将BMP文件转换为SimpleSH1106的游程编码图像。

库中给出了完整的描述。

我展示了一个条形板电路布局。有三个条形板 - 一个用于Nano,一个用于显示器,一个用于LM358。他们应该形成三明治。电路板从元件侧显示。精细的柔性电线连接两块板。将电路板与焊接的支架连接在一起。在我的图表中,条形板的铜以青色显示。红线是条形板上的线链或将板连接在一起的柔性线。我没有展示“测试线索”。

有些显示器的引脚似乎有不同的顺序。检查它们。

我购买的0.9“显示器的像素的x坐标从x = 0到127运行。使用1.3”显示器它们是从x = 2到129.该库包含一个常量“colOffset”,允许您调整显示器的偏移量。

我已经为SM PCB附加了Gerber文件和EasyPC源文件。这些尚未经过测试,因此使用它们需要您自担风险。

步骤9:不同的屏幕

示波器

示波器

模拟显示屏显示带有刻度的波形。横轴表示时间im mS。纵轴表示伏特,虚线为4V,0.5V,0.1V和20mV;在DC模式下,0V位于底部;在AC模式下,0V在中间显示为虚线。

逻辑显示屏显示四个通道位。 D8是顶部通道,D11是底部通道。横轴表示以mS为单位的时间。

有两个按钮:一个用于调整时基轴的“水平”按钮和一个用于调整增益轴的“垂直”按钮。如果您按住任一按钮1秒钟,则会出现一个菜单屏幕。

当菜单显示时,“垂直”按钮会滚动浏览不同的设置,“水平”按钮会设置每个设置的值。 。如果您没有按任何一个按钮2秒钟,程序将返回显示波形。

步骤10:频率计数器

示波器

示波器

通过使用Timer1和Timer2,ArdOsc也可以充当频率计数器。频率计有两种工作方式:在一秒钟内计算上升沿的数量,或者测量从一个上升沿到下一个上升沿的时间。

再一次,值得吗?也许。我不记得我需要一个频率计数器的时间。为什么不这样做很容易?

为了计算D8“逻辑”信号的边沿,程序选择D5作为Timer1的时钟输入(16位计数器/定时器)。 D5外部连接到D8 - “逻辑”输入之一。 Timer0(一个8位定时器)设置为每毫秒溢出一次。每次Timer0溢出时,都会产生中断。 1000次中断后,Timer1中的计数显示为“频率”。如果Timer1计数超过65536,则会产生中断并记录此类中断的数量。

要测量从一个边沿到下一个AC信号的时间,定时器1被设置为空闲 - 运行16MHz计时器。 ICR1寄存器设置为在比较器变为高电平时捕获Timer1中的当前值。比较器的负输入连接到A3,正输入连接到D6。每次比较器变为高电平时,都会产生中断。一个中断和下一个中断之间的时间是周期(1/频率)。程序显示一秒钟内测量的平均频率。比较器意味着在上升沿触发,但没有杂音,因此如果有噪声,下降沿将被视为上升沿。这在低频时尤其重要,因此,例如,10Hz信号将被报告为20Hz。

同时,Timer2可能产生“测试信号”。因此没有定时器可用,我们不能使用正常的Arduino函数delay(),millis()等。

频率计数器的代码基于Nick Gammon的优秀网页。

如果您不想输入“频率计数器”,则不需要从D5到D8的连接。在INO文件中,将bool常量bHasFreq设置为false。

步骤11:电压表

示波器

示波器

示波器还可以作为电压表,可以测量大约-20V和+ 20V之间的电压。它使用Atmega328p的内置带隙电压参考,因此相当准确。

值得吗?功能的数量越来越荒谬。好的,为什么不呢?

在A6测量电压,ADC使用Vcc(即大约5V)作为参考。因为“5V”是近似值,我们还通过将其与1.1V带隙进行比较来测量Vcc的实际值。根据数据表,带隙仅为10%准确,但我尝试的几个接近1.1V。

要测量的输入电压通过电阻网络。我选择了上面显示的值

Ra = 120k

Rb = 150k

Rc = 470k

你会在MeasureVoltage()函数的开头附近找到这些常数。

Rc告诉你电压表的输入阻抗。与便宜的数字万用表相比,470k是低的,但是足够高,可以使用。

电压表可以测量的最低电压是

-5 * Rc/Ra = -19.6V

它可以测量的最高值是

5 * Rc/Rb + 5 = 20.7V

如果需要,可以选择不同的电阻。

如果超过这些电压怎么办?没事的。如果Arduino输入引脚上的电压高于Vcc或低于0V,保护二极管可以承受1mA电流。使用470k意味着理论上可以测试470V的电压。但是我不相信在470V的条形板绝缘,你不应该玩这样的电压和这种原油电路。

如果想要精确的测量,你需要校准电压表。将电压表输入“探头”连接到0V,看看电压表报告的内容。调整calibrateZero常数,直到电压表读数为“0.00V”。现在将电压表输入连接到已知电压源 - 如果你有一个不错的万用表,那么测量一个9V电池的电压。调整calibrateVolts常数直到电压表给出正确的答案。

如果您不想要“电压表”输入,那么您不需要连接到D6的电阻。在INO文件中,将bool常量bHasVoltmeter设置为false。

步骤12:测试引线

示波器

示波器通常具有花哨的测试引线。我通常使用无焊接面包板,所以我只是附加了一种用于面包板的插入式电线。由于示波器由5V供电,我将其连接到我在面包板上使用的任何5V和0V电源以及更多的插入式电线。

步骤13:添加信号发生器

示波器

示波器

示波器

示波器

示波器

信号发生器是一个非常有用的部分测试装备这个使用AD9833模块。我在这里描述了一个独立的版本;此步骤描述如何将一个添加到ArdOsc。 (此步骤是对此原始Instructable的编辑。)

AD9833可以生成0.1 MHz至12.5 MHz的正弦波,三角波和方波 - 本项目中的软件限制为1Hz至100kHz。它可以用作扫描发生器。扫频发生器有助于测试滤波器,放大器等的频率响应。

我选择的AD9833模块与此类似。我不是说这是最好或最便宜的供应商,但你应该买一张看起来像那张照片。

模块之间的连接是:

地面连接在一起

5V = AD9833的Vcc

D2 = FSync

D13 = Clk

D12 =数据

上面的示意图是步骤8中的原理图的补充。您可以使用另一块stripboard将另一层添加到步骤8中描述的三明治中。

我已在步骤中更新了INO文件8包括控制AD9833的代码。如果添加AD9833,则应将bHasSigGen变量设置为true(我将其保留为false,因为大多数人没有AD9833)。

新菜单控制AD9833。它允许您选择频率和波形以及是否扫描频率。

扫描发生器在1,5或20秒内反复输出逐渐增加的频率。它以“min”频率开始,1,5或20秒后处于“最大”频率。频率变化是对数的,并且每毫秒改变一次。在扫描频率时,示波器无法显示频率。

在不同模式下,扫描发生器输出频率,显示示波器输入,更改频率,显示示波器输入等。频率从“min”变为“max”超过这些步骤的20,100或500(或称为“帧”)。频率变化比“扫描”模式更加粗糙,但您可以观察正在发生的事情。

步骤14:未来发展

可能是电池供电?是的,只需添加连接到Nano的RAW引脚的9V PP3。它通常使用25mA。

它可以由单个锂电池供电吗?这不是那么简单,因为3.7V可能还不够。在DC模式下显示电压的代码已经读取Vcc电压,因此它将调整刻度位置。 Nano可以在3.7V(进入“5V”引脚)上运行。但是,3V3输出可能不会达到3.3V;监管机构的辍学率太大了。你可以直接从锂电池的3.7V开始运行显示器,但是你从哪里获得0.55V的参考电压?它需要稳定。也许您可以使用LM317(如果将其Adjust引脚连接到0V,则可提供稳定的1.25V电压 - 该电流下降应该足够低)。或者您可以使用LED作为齐纳。或者,只要您汲取微小电流,就可以使用Vref引脚上的电压 - 将其连接到发射极跟随器。您可能需要将LM358替换为工作电压较低的运算放大器。

触发器可以更好吗?数字示波器在触发之前将数据收集到循环缓冲区中。触发水平可以变化吗?你能一次扫一扫吗?是的,你可以做所有这些,但你可能更好只需购买“适当的”示波器。

你能使用Pro Mini吗?是的,但这不值得。您需要为显示器和0.55V参考电压制作自己的3V3信号。如果您要将数据发送到PC,那么您将需要一个串口转USB。只需使用Nano。

它可以是无线的吗?是。添加自己的蓝牙与HC-05(Instructables可用)并连接到PC或Android手机。 ESP 8266对于这个项目来说会更麻烦。

你能用更大的显示器吗?是的,但为什么这么麻烦,质量不是那么好。只需买一台示波器。

你能做得比LM358好吗?是。如果您的组件抽屉中有各种运算放大器,请尝试使用它们。让我知道哪一个效果最好。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分