将 Arduino 连接到面包板以通过 Tinkercad 点亮 LED





5.00/5 (6投票s)
本文将引导您完成使用 Tinkercad 创建连接到面包板的模拟 Arduino 项目。
刚开始接触 Arduino,想尝试一个简单的项目吗?这个项目大约需要 45 分钟,非常有趣,甚至还有闪烁的灯光!
本文有两个版本
- 本文使用基于浏览器的 Arduino 模拟器
- 另一篇是关于如何连接真实的 Arduino 到面包板,然后控制 LED 的(https://codeproject.org.cn/Articles/1247040/Connecting-an-Arduino-to-a-Breadboard-to-light-u)
如果你有时间,做这两个项目其实都很有意思,它们使用了相同的应用,一个是在现实世界中,另一个是在虚拟环境中。
让我们开始吧。
引言
本文将带你上手一个涉及 Arduino 模拟器、面包板和一些 LED 的简单项目。
该项目将引导你完成制作一个 8 位二进制计数器所需的步骤。一旦它正常工作,你就可以轻松地尝试其他序列和效果。这是 Arduino 的一个很棒的入门项目,或者如果你很久没用 Arduino 了,这是一个重拾兴趣的好方法。
入门
要开始使用模拟器,请访问 https://www.tinkercad.com 并创建一个免费帐户。完成后,你将进入 Tinkercad 的仪表板。在屏幕左侧的菜单中,点击“电路”。然后,在屏幕右侧,点击“创建新电路”按钮开始。当电路设计屏幕加载后,点击“组件”下拉框,然后选择“全部”。现在你就可以搭建一个二进制计数器了!只需按照下面的步骤开始。
- 在屏幕右侧的零件列表中,向下滚动直到看到“面包板和微控制器”。将 Arduino 和一个小面包板拖到工作区。将面包板放在 Arduino 的上方。
- 将鼠标光标悬停在 Arduino 顶部的 GND 引脚上。当 GND 引脚高亮显示为红色时,单击鼠标开始连接电线。
- 将鼠标移动到面包板第 1 行的底部孔,当该孔高亮显示为红色时,单击以连接电线。在模拟面包板上,请注意有 30 行引脚。每行有 10 个引脚,标有从 a 到 j。你刚刚连接了电线到引脚 1a。
- 有时,在连接电线之前弯折电线会很有帮助。这可以防止视觉混乱,并有助于使电路更易于理解。现在让我们练习一下。单击刚添加的电线以选择它。
- 按 Delete 键删除电线。
- 如同步骤 2,将鼠标移动到 Arduino 顶部的 GND 引脚。单击,将鼠标移动到 Arduino 和面包板之间的中间点,然后再次单击。在绘制电线时,在非连接点单击鼠标会使电线弯折。
- 将鼠标向左移动,直到它位于面包板第 1 行正下方,然后再次单击。现在,将鼠标移动到第 1 行的 a 引脚。当看到该引脚高亮显示为红色时,再次单击。这将连接电线。
- 由于这根电线连接到地 (-) 线,请单击下拉框将其颜色更改为黑色。虽然电线的颜色不会影响电路,但黑色电线通常用于连接负极 (-),红色电线用于连接正极 (+)。遵循这些约定可以使我们在查看电路时更容易理解。
- 在零件列表中,找到电阻器。将一个电阻器拖到面包板上,使其连接到引脚 1d 和 1f。
- 在右上角的框中,将电阻器的电阻值更改为 220Ω。确保单击下拉菜单将单位从 kΩ 更改为 Ω。
- 添加一根黑色电线,将引脚 1j 连接到面包板顶部的负电源轨。
- 在零件列表中找到 LED,然后将其拖到面包板上,使其连接到引脚 12b 和 13b。
- 在第一个 LED 的右侧添加 7 个 LED。确保它们都在 b 列,并且它们之间没有间隙。
- 从顶部电源轨连接黑色电线到引脚 12e、14e、16e、18e、20e、22e、24e 和 26e。这会将电路的负极连接到每个 LED 的阴极。在模拟器中,每个 LED 的阴极引脚是直的,阳极引脚是弯曲的。这一点很重要,因为二极管(包括 LED)只允许电流单向流动。
- 现在,是时候将 Arduino 的输出引脚连接到面包板上 LED 的阳极了。从 Arduino 的引脚 5 添加一根电线到面包板的引脚 27a,该引脚连接到最右侧 LED 的阳极。接下来,将 Arduino 的引脚 6 连接到面包板的引脚 25a。继续以这种模式进行,直到最后将 Arduino 的引脚 12 连接到面包板的引脚 13a。
- 从 Arduino 的模拟引脚 0 连接一根电线到一个未使用的面包板行。在下面的示例中,我们已将电线连接到面包板端口 30a。
你的二进制计数器电路现在准备就绪!你就可以开始编写 Arduino 代码来让计数器工作了。
好了!我们可以开始编写代码来让计数器工作了。
添加代码
请注意,这部分与配套文章“使用 Arduino 连接到面包板点亮 LED”中的内容完全相同。
现在是时候编写代码来让我们的二进制计数器工作了。在 Arduino 的世界里,编写并上传到 Arduino 设备上的程序被称为“草图”(sketch)。一个草图可以包含多个文件,只要它们都保存在同一个目录中。由于这是一个非常简单的项目,我们将把所有代码放在一个文件中。
在使用 Tinkercad 时,可以通过点击屏幕顶部的“代码”按钮来输入代码。一开始,你可能看不到输入代码的地方。在代码窗口中,你会看到一个下拉框,允许你在“块”、“块 + 文本”和“文本”之间选择。选择“文本”,你将看到一个编辑器窗口,你可以在其中编写代码。你的代码在你输入时会自动保存。在 Tinkercad 中输入代码后,它就可以在模拟的 Arduino 上立即运行。不需要上传步骤。当你准备运行代码时,点击“开始模拟”按钮,你的代码将立即开始运行。
Arduino 草图是用 C++ 编写的。Arduino IDE 支持 C++11,所以如果你愿意,可以使用它的所有新特性。我们将坚持使用 C++98,因为这是 Tinkercad Arduino 支持的版本。这样,无论你将来在哪里运行它,代码都能正常工作。请注意,Arduino 环境不包含 C++ 标准库。所以你无法使用 vector 或 C++ 字符串等。有一个 C++ 标准库的实现 可在 GitHub 上找到,但本项目不需要它。
首先,我们将介绍几个我们需要使用的函数,以便 Arduino 点亮我们的 LED。这些函数都是全局可用的。你不需要导入任何东西即可使用它们。
我们要使用的第一个函数是 pinMode。此函数用于告诉 Arduino 一个引脚将用作输入还是输出。它的用法如下:
pinMode(10, OUTPUT);
这将按预期将引脚 10 设置为输出模式。第二个参数可以设置为 INPUT 或 OUTPUT。这些都是在任何 Arduino 草图中全局可用的常量。
接下来是 digitalWrite。此函数允许我们打开或关闭特定的输出引脚。要关闭或打开引脚,我们可以使用另外两个全局常量: LOW 和 HIGH。这些常量没什么特别之处。如果你在 Arduino 源代码中查找它们,你会发现 LOW 是 0, HIGH 是 1。因此,例如,关闭引脚 10 可以写成以下任一方式:
digitalWrite(10, LOW);
digitalWrite(10, 0)
而要打开引脚 10,你可以使用以下任一方式:
digitalWrite(10, HIGH);
digitalWrite(10, 1)
接下来是 analogRead。顾名思义, analogRead 用于读取 Arduino 模拟引脚的模拟值。
我们需要使用的最后一个函数是 delay。此函数与其名称的含义完全一致。它会导致 Arduino 暂停,然后再执行后续代码。它接受一个参数:要暂停的毫秒数。因此,要暂停执行 1 秒钟,你可以写:
delay(1000);
delay 函数对我们的二进制计数器很重要,因为我们希望在每次计数器递增后暂停片刻。虽然 Arduino 体积小、功能不强大,但它仍然可以非常快速地从 0 数到 255,以至于我们甚至看不到计数器 LED 的变化。
要输入代码,你需要 下载 Arduino IDE (如果你使用的是物理 Arduino 硬件),或者如果你使用的是 Tinkercad,则打开代码视图。为此,请点击“代码”按钮,然后在下拉菜单中选择“文本” - 默认设置为“块”。
现在我们已经了解了所需的 Arduino 函数,让我们深入研究一下让我们的二进制计数器工作的代码。为了保持一切整洁有序,我们将把我们的计数器包装在一个类中:
class BinaryCounter {
};
接下来,让我们用类所需的变量和方法来填充它:
class BinaryCounter {
private:
static const uint8_t digitCount = 8;
const uint8_t pins[digitCount] = {12, 11, 10, 9, 8, 7, 6, 5};
uint8_t count = 0;
static const uint8_t showSingleValuePin = 0;
uint8_t valuetoShow = 255;
public:
BinaryCounter();
void increment();
uint8_t* getBinaryDigits(uint8_t num);
void clearLights();
};
让我们快速看一下刚添加的变量。首先,我们有一个变量来计数我们的二进制计数器将包含的位数。如果愿意,我们可以直接硬编码数字 8,但将其存储在一个地方,如果我们要更改二进制计数器包含的位数,则非常容易更新我们的代码。
接下来,我们有一个数组,其中包含每个 LED 连接的引脚编号。我们按从左到右的顺序排列它们。这样,当我们想要从左到右迭代引脚以打开或关闭 LED 时,会变得非常容易。
接下来,我们有一个变量将存储计数器的当前值。
你可能会问,为什么是 uint8_t 而不是 int?在 Arduino 上, int 占用 16 位内存。顾名思义, uint8_t
只占用 8 位。而且由于我们使用的是 8 个 LED,我们只需要 8 位就可以表示我们能够显示的任何数字。虽然在这个小程序中没有区别,但养成只使用你需要的习惯是很好的。Arduino 只有 2KB 的 RAM,所以很容易很快用完。
现在是时候进入我们代码的核心部分了。我们将从为 BinaryCounter 类编写一个构造函数开始。
BinaryCounter::BinaryCounter() {
//set all counter pins to output mode
for(int i = 0; i < digitCount; i++) {
pinMode(pins[i], OUTPUT);
}
构造函数只做一件事:它遍历我们将使用的引脚,并将它们设置为输出模式。
接下来,我们需要一个方法,该方法接受一个 uint8_t
并返回一个 uint8_t 数组。只有一个问题:C 和 C++ 不允许你返回整个数组。但我们可以很容易地在堆上创建一个数组并返回指向其第一个元素的指针,所以我们将这样做。我们只需要记住完成后删除它。
uint8_t* BinaryCounter::getBinaryDigits(uint8_t num) {
// Make a byte array to hold all of the binary digits.
uint8_t *digits = new uint8_t[digitCount];
memset(digits, 0, digitCount * sizeof(uint8_t));
uint8_t remaining = num;
uint8_t currentPosition = digitCount-1;
while(remaining > 0) {
digits[currentPosition] = remaining % 2;
remaining /= 2;
currentPosition--;
}
return digits;
}
第一行代码创建了一个足够大的 uint8_t
数组来保存所有数字,第二行代码将数组的所有元素设置为 0。
接下来,我们进行将整数转换为二进制数字的过程。
整数到二进制转换背后的数学相对简单。我们只需取我们的数字,然后连续除以 2,直到剩下 0。在每一步,如果剩余的当前数字可以被 2 整除,那么该步的二进制数字将是 0。如果当前数字 不能 被 2 整除,则该步的二进制数字是 1。有关更深入的解释,请参阅 这篇博文。理解整数到二进制转换的最佳方法是手动进行几次转换。完成此操作后,你会发现整个过程更容易理解。
请注意,我们正在向后遍历数字数组以设置值。我们用于将整数转换为二进制的方法以从右到左的顺序给出数字。通过向后遍历数组,我们确保为每个引脚设置正确的值。
完成后,我们返回指向数字数组开头的指针。
接下来,我们将添加代码来递增计数器并打开表示当前二进制计数的 LED。
void BinaryCounter::increment() {
uint8_t* binaryDigits;
if(analogRead(showSingleValuePin) > 500) {
binaryDigits = getBinaryDigits(valuetoShow);
}
else {
binaryDigits = getBinaryDigits(count);
if(count == 255) {
count = 0;
} else {
count++;
}
}
for(int i = 0; i < digitCount; i++) {
digitalWrite(pins[i], binaryDigits[i]);
}
delete binaryDigits;
delay(500);
}
我们首先检查模拟引脚 0(在 showSingleValuePin
中设置)是否连接了电线。如果是,我们将从 valuetoShow
中的值生成一个 8 位代码。如果没有连接电线,那么我们就运行递增计数器的代码。
如果我们在运行计数器,我们首先调用 getBinaryDigits
将当前计数转换为二进制数字数组。
由于我们从 getBinaryDigits
返回的数组按从左到右的顺序包含数字,而我们的引脚数组按从左到右的顺序包含输出引脚,因此我们可以使用一个简单的 for 循环来遍历这两个数组,并将每个引脚设置为与 binaryDigits 数组中相应的值。
由于 digitalWrite
如果第二个参数为 0,则关闭引脚,如果为 1,则打开引脚,最终结果是我们的 LED 显示当前的二进制计数:任何为零的数字都会导致 LED 关闭,任何为一的数字都会导致 LED 打开。
在遍历并打开/关闭 LED 后,我们 delete 掉 binaryDigits
数组,因为我们完成了它的使用。忘记这一步非常重要。如果这样做,你的程序将存在内存泄漏。Arduino 将很快耗尽内存并锁定。这不会损坏 Arduino,但你的计数器只能工作很短时间然后就会冻结。
接下来,我们检查计数是否达到 255,因为 255 是我们用 8 个 LED 在二进制中可以表示的最大数字。如果我们达到了 255,我们将计数器重置为 0。否则,我们将计数加 1。你可能会注意到,我们 可以 实际上跳过此检查并直接增加计数。由于 255 是 uint8_t
可以容纳的最大值,如果我们尝试在计数已经是 255 时增加它,它将只溢出到 0。
然而,在这种情况下,最好明确说明。依赖 uint8_t
从 255 溢出回 0 是可以的,但这样做会使我们的代码更难理解。即使你是唯一查看代码的人,如果你在几个月后回来查看代码时忘记了它,你也可能会感到困惑。
最后,我们 delay 500 毫秒。这将导致 Arduino 暂停半秒钟,然后继续处理下一个数字。
这就是 BinaryCounter 类的内容。我们几乎完成了!我们只需要再写几行代码来初始化我们的计数器并使其计数。
BinaryCounter *counter;
void setup()
{
counter = new BinaryCounter();
}
void loop()
{
counter->increment();
}
我们首先创建一个全局变量来存储 BinaryCounter 的指针。总的来说,全局变量是开发人员试图避免的东西。然而,Arduino 的编程环境有些局限。创建一个全局 BinaryCounter 是使其可用于 Arduino 的 loop 函数的唯一方法。
接下来,我们看到两个函数: setup 和 loop。它们都是 Arduino 编程环境的一部分。 setup 函数在 Arduino 启动并执行你的程序时运行一次。然后 Arduino 会持续运行 loop 函数。
我们的其余代码很简单:在 setup 中,我们创建了一个新的 BinaryCounter 实例。然后,每次 loop 运行时,我们调用计数器的 increment 函数来设置 LED 并递增计数器。
完成!这就是让二进制计数器工作的全部代码。
在 Tinkercad 中,点击“开始模拟”按钮。
现在,放松一下,看着你的二进制计数器投入运行!
完整代码列表
class BinaryCounter {
private:
static const uint8_t showSingleValuePin = 0;
static const uint8_t digitCount = 8;
const uint8_t pins[digitCount] = {12, 11, 10, 9, 8, 7, 6, 5};
uint8_t count = 0;
uint8_t valuetoShow = 255;
public:
BinaryCounter();
void increment();
uint8_t* getBinaryDigits(uint8_t num);
};
BinaryCounter::BinaryCounter() {
//set LED all pins to output mode
for(int i = 0; i < digitCount; i++) {
pinMode(pins[i], OUTPUT);
}
}
uint8_t* BinaryCounter::getBinaryDigits(uint8_t num) {
// Make a byte array to hold all of the binary digits.
uint8_t *digits = new uint8_t[digitCount];
memset(digits, 0, digitCount * sizeof(uint8_t));
uint8_t remaining = num;
uint8_t currentPosition = digitCount-1;
while(remaining > 0) {
digits[currentPosition] = remaining % 2;
remaining /= 2;
currentPosition--;
}
return digits;
}
void BinaryCounter::increment() {
uint8_t* binaryDigits;
if(analogRead(showSingleValuePin) > 500) {
binaryDigits = getBinaryDigits(valuetoShow );
}
else {
binaryDigits = getBinaryDigits(count);
if(count == 255) {
count = 0;
} else {
count++;
}
}
for(int i = 0; i < digitCount; i++) {
digitalWrite(pins[i], binaryDigits[i]);
}
delete binaryDigits;
delay(500);
}
BinaryCounter *counter;
void setup()
{
counter = new BinaryCounter();
}
void loop()
{
counter->increment();
}