当前位置:首页 > 工业控制 > 电路设计项目集锦
[导读]位数取决于有多少个2R分支。本项目中,我们将使用8位R-2R和6位R-2R来驱动Arduino Uno或Nano。如果你使用的是其他已知支持至少8位完整端口操作的微控制器,例如STM32的“蓝色芯片”和“黑色芯片”,那么你就可以直接使用两个8位DAC。

通过设计一个R-2R梯形DAC,即可实现数字到模拟转换最简单的方案之一。这种DAC仅需电阻即可工作,因此非常适合初学者使用。

这种DAC的基本原理是:只需设定两个电阻值——R和2R。然后按照下图所示进行电路连接。

R的数值可以任意选择,但电路中每个R的值必须相同。

例如,如果选择R = 1k,则2R就是其两倍,即2R = 2k。因此你可以使用1k和2k的电阻。

若选择R = 3.3k,则2R = 6.6k,依此类推。如果你希望所有元件都使用相同的阻值,那么要得到2R,只需将两个电阻串联即可,这样会增加元件数量。

位数取决于有多少个2R分支。本项目中,我们将使用8位R-2R和6位R-2R来驱动Arduino Uno或Nano。如果你使用的是其他已知支持至少8位完整端口操作的微控制器,例如STM32的“蓝色芯片”和“黑色芯片”,那么你就可以直接使用两个8位DAC。

关于DAC集成电路的补充说明:

本项目主要使用R-2R DAC,但你也可以自由选择使用DAC集成电路来实现类似功能。如果打算使用DAC集成电路,我建议选用支持高速通信协议(如SPI)的型号,因为I2C传输速度太慢,无法绘制出详细的图像。本文不会详细介绍如何使用DAC集成电路,但可能会在后续的文章中提及。不过,我认为R-2R仍然是更优的选择,因为它能输出更精细的图像。

端口操作

我们将采用微控制器的并行端口操作方式。这样做可以提高输出速度,同时保持代码简洁。你可以通过此链接了解Arduino端口寄存器的更多详细信息。

Arduino Uno和Nano使用的微控制器是ATmega328p,其引脚映射与Atmega168相同:

端口引脚和位数用符号PXN表示,其中X代表端口号,N代表位编号。

示例:PB1表示PORT B的第1位。同样地,PC5 用于 PORT C 的第 5 位。

如果我们查看引脚,会发现微控制器具有 B、C 和 D 三个端口。通过查阅 Arduino 参考资料,我们可以知道哪些端口可以进行读写操作,或两者都支持。在我们的应用中,我们只关心写入操作。

文档说明 PORTD 支持读写,并映射到数字引脚 0 到 7,这意味着我们可以对整个 8 位端口进行写入操作。

接下来是 PORTB,如前所述,它映射到数字引脚 8 到 13。此外还特别指出,其中的第 6 和第 7 引脚(即完整的 8 位)不可访问,因此该端口只能用于写入 6 位数据。

PORTC 的情况也是如此:它映射到模拟引脚 0 到 5,但同时保留了两个引脚,因此可写入的数据仅剩 6 位。

由于这些限制,我们将不得不使用一个 8 位 DAC 用于 PORTD,以及一个 6 位 DAC 用于 PORTC 或 PORTB。

我们将使用PORTD和PORTB,现在可以开始将DAC连接到引脚上。

如果你需要一些组装的视觉参考,这是我在面包板上组装两个R-2R电阻器的方法。请注意,我使用了两个R-2R电阻器,因为我是在STM32“黑盒子”上进行测试。我留出了两根跳线,以便连接示波器探针,同时还加了一根接地线。我使用了全部10k电阻,因此对于我的两个R-2R电路,我将两个10k电阻串联起来。

这里是一个更整洁的面包板设置,使用Tinkercad完成。我用X和Y标记了输出端口,因为这些是示波器探针需要连接的位置。如果你需要更多关于设置的指导,我会提供包含所有相同电阻值的R-2R梯形电路图,以及另一个包含两种不同电阻值的电路图。

请务必检查你的地线!每次组装这个电路时,我都会容易忘记这一点。同时,请仔细检查是否遗漏了任何连接点之间的空隙。

Arduino代码

现在是时候编写Arduino程序了。

首先,我们需要将端口设置为输出模式。根据Arduino参考文档中关于端口操作的内容,我们可以看到如何设置端口:

基本上,位值为1时将其设为输出,值为0时设为输入。对于PORTD,我们可以直接写入,因为所有位都可以访问。而对于PORTB,需要注意的是,第6位和第7位不可用,因为它们映射到晶振上。建议使用位运算或OR操作符,并将值设为0,以避免修改那些不会被设置的位。

在我们的设置循环中,代码如下:

代码会附带下载链接,因此不必手动输入。

配置下方的for循环只是对6位端口进行重新映射。这些值来自一个包含8位范围数值的列表。为了重新映射为6位,最大值为2^6-1,即63。我们是从0到2^8-1(即255)的范围内进行映射。在Arduino代码中进行重映射的原因是,我们的手绘工具会以8位表示x和y坐标。虽然可以在任一代码中更改此设置,但最好在使用的微控制器上进行修改。

基本上,我们需要根据示波器的情况设置一些延迟。我发现我的设备上1毫秒的延迟就足够了。实际上,完全省略延迟也是可以接受的。关于点数,将由我们的手绘工具自动生成,因此你只需复制粘贴数字即可。但基本上这是需要绘制的点数,迭代变量可以依次遍历这些点。无论如何,以下是完整的代码:

x_points 和 y_points 数组每次绘制时都会不同,并由我们的工具自动生成。

关于快速PWM的补充说明:

如果你是微控制器的高级用户,可能会发现,如果关注速度,或许可以通过使用快速PWM并修改时钟寄存器来实现相同效果。然后将PWM输出信号输入低通滤波器,以获得模拟电压,从而减少引脚数量。我尝试过这两种方法,结果仍然能更好地支持具有更多细节的图像,至少在Arduino Uno上是如此。

绘图工具

我用Python 3和tkinter开发了这个工具。如果你没有安装tkinter,请使用pip进行安装。

代码会附上,其基本功能是记录光标点击时在窗口上的坐标位置。请不要尝试调整窗口大小,否则会影响分辨率。如果你想更精确,可以使用 Windows 中的放大镜工具。窗口大小基于 255x255,因为这将是我们的位范围的最大值。当然,如果你使用的是 Arduino UNO,其中一个维度会被映射为 6 位。

要调用该工具,只需使用以下格式即可

这将生成一个名为 arduino_list.txt 的 .txt 文件,其中包含为你生成的 x_points、y_points 和 NUM_POINTS 的 Arduino 列表,可以直接复制粘贴到你的代码中。

例如,当你打开该 .txt 文件时,它会显示如下内容。你只需将代码中的这些行替换即可。

打开后它的样子如下所示。从这里开始,你可以绘制任何图形。

我画了下面这张图来测试一下。当窗口关闭时,代码就会自动生成。

上传代码到 Arduino 后,在 X-Y 模式下显示的效果如下。

重要提示:

如果你遇到关于内存的编译错误,这通常是由于Arduino UNO可用内存不足所致。这意味着你应该绘制一个细节较少的图像。我认为最大点数大约为400,但可能更高。如果你使用的是STM32“蓝片”或“黑片”,这个数值可能会超过4000。

示波器X-Y模式

必须将示波器设置为X-Y模式。8位R-2R DAC输出(PORTD)连接到通道1,6位R-2R DAC(PORTB)连接到通道2。然后通过旋钮进行调整,直到看到图像为止。

就这样!如果你有任何问题,欢迎随时提问。此外,如果你想用蓝色药片或黑色药片来试一试,这里是我 GitHub 页面的链接,里面有一些示例代码。

现在是几张我绘制的图像。

编辑:

内存管理的重要细节

正如Tim在评论中提到的:

在你的Arduino代码中,遍历点的迭代器t是“byte”类型,因此最多只能支持255个点。为什么不将其改为“int”呢?

你的绘图代码为x_points和y_points使用了“const unsigned long”,这会导致问题,因为之后你可能会修改y-point的值。此外,为什么不直接用“byte”来节省内存呢?

请留意你所使用的硬件限制。对于Arduino Uno,使用byte类型更好;但如果你使用的是STM32甚至ESP32,则可支持更多的点进行绘图。感谢大家的反馈。

Timster:

我找到了一种方法,可以大幅增加UNO支持的点数——将它们存储到程序存储空间中。你可以使用 PROGMEM修饰符实现这一点。这样大约可以存储15,000个点!

所以,数组的声明方式如下:

不要在setup函数中修改y_points(即去掉其中的for循环)。相反,在loop函数中进行位移操作即可。

此外,还需要一个特殊的指令来从程序存储读取数据(pgm_read_byte_near)。因此,void loop()中的for循环应如下所示:

然后就可以存储一张高分辨率图像或多张较小的图像,并在它们之间循环切换。

本文编译自hackster.io

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭