火柴盒示波器的制作

步骤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好吗?是。如果您的组件抽屉中有各种运算放大器,请尝试使用它们。让我知道哪一个效果最好。

台电新发售的幻影NP900C固态硬盘评测
华为智慧屏摩卡金配色即将上线,搭载4K量子点屏幕
基于符合CI的异频钥匙将两个不同频带的RFID芯片集合一体
思特威推出三款全新SmartGS-2技术的工业应用CMOS图像传感器
2018中国半导体行业发展情况分析,大陆半导体核心产业链逐步规模化
火柴盒示波器的制作
电子元器件收纳也是一门艺术
智能发电系统投入运营
DC-DC开关频率的选择(2)
用于车库机械的稳压汽车电池充电器电路
雷曼超高清大屏保障电网安全稳定运行
光耦初级加三极管有什么作用?
恒频脉宽调制细分电路
5G毫米波有什么优势和劣势?
磷酸铁锂离子电池的均衡保护技术
苹果WWDC21全球开发者大会或采用录播形式
全球汽车芯片短缺,或是汽车厂商引起
同步降压型DC/DC稳压器ADP2384/86的主要特性及应用
特斯拉推电池回收计划,承诺最低2万元更换电池
360正式推出其智能硬件大家族的新成员——360扫地机器人