电子入门教程[01]—我的代码流成了灯

电子入门教程[01]—我的代码流成了灯

在浏览此文之前,可能你需要先康康这个:

电子入门教程[00]—Beginning from Zero.

在正式开始学习Arduino之前,你需要先自学以下知识:

  • C语言或C++
  • 安装Arduino IDE
  • 认识Arduino Uno开发板
  • 懂得如何使用面包板连接电路

推荐学习资源站


本系列面向初入电子的童鞋,用语尽量做到简洁易懂,同时慢慢引进专业的概念,让零基础的童鞋也能轻松读懂并具有制作价值。这期我们来讲讲我们最常见的———— 流水灯

Step1: 点亮一个LED

什么是LED?

LED是英文Light Emitter Diode的缩写,就是大家熟知的发光二极管~
这是一颗常见的LED↓↓↓ 长脚是正极(阳极),断脚是负极(阴极)。

n38yaq.jpg

常见的LED有很多种颜色,在消费电子领域,LED的工作电压多为1.5v-3.0v,发不同颜色光的LED的工作电压不尽相同。比如常见的蓝光和白光是3v左右,红光是1.8v左右。在电子电路中,LED常用作状态指示灯。今天我们来尝试自己做一个基础但炫酷的流水灯。

如何点亮一个LED

要想让一个LED工作,你就必须给它一个合适的工作电压和工作电流。LED是非常娇弱的元件,对工作电流非常敏感~!一般的LED工作电流被限制在10mA以下。
一般对于电压在3v-12v之间的电源来说,给一颗LED串上一颗1kΩ的电阻就足矣。
只要按下图↓来连接电路(图中R1的阻值常用1kΩ,根据不同电压可能有所变动),这颗LED就会亮起来啦~

n38hM4.jpg

既然我们已经知道了如何让一颗LED工作起来,那我们就可以点一串LED来玩辣!

Step2: 流水灯的原理

流水灯的原理

-流水灯,顾名思义,一串灯像流水一般闪烁,故称之为流水灯

n38OzD.gif

既然我们要做到上图的流水闪烁的效果,我们就需要让每个LED按照一定的工作顺序来发光。也就是说,不停地改变他们的供电(电平)状态,达到我们的目的,这种不停变化的电平信号我们称之为一种控制信号。

控制信号的产生

我们在此介绍一种易于上手的方法—利用单片机来产生控制信号。相比于利用数字电路来产生,它更加容易操作,只需要一点点C语言基础,并且会连线你就可以驾驭你的流水灯了!

Step3: 吃掉(雾)Arduino

Arduino是什么?能吃吗!

Arduino是一个简单易学的单片机开发平台,用Arduino系列开发板可以肥肠方便地快速实现你的各种电子创意,是学习单片机入门的最佳选择之一!(当然不能吃啊QAQ)

如下是经典的Arduino UNO开发板。

n3Gmes.png

点亮一个灯的实例

点亮一个灯所需要的电信号,不能单纯地在电压这一个维度上思考。
在上面的电路图中,我们使用了一个理想电源(输出恒定的12v电压,可以无限制地满足负载所需要的电流)串联一个电阻来使LED工作,这时流过LED的电流由我们的电阻来决定,它既不能太大,也不能太小,比如我们想让电路总电流为5mA,那么我们需要阻值 R = (12-Vd)V / 5mA 的电阻(式中Vd是LED压降)。

呀,说到现在我好像什么都没说…那让我们换个思路,先来了解一下单片机的GPIO。
GPIO:General Purpose input/output,通用输入输出(端口)的简写,一个GPIO可以任由代码控制,可以用作输入模式,输出模式,或两者兼用。Arduino UNO主控单片机ATMEGA328P的I/O口简图可以是这样的:


uIax1S.jpg

在前传中我们提到了晶体三极管用作数字电路的基础部件,其实随着芯片工艺制程的提升,现在的多数芯片都是由场效应管(MOSFET)作为电路基本部件,它的功耗更低,性能更好,可以达到的频率也更高(虽然它们的原理都可以等效成一个可以被控制的开关)。

上图描述了一个I/O口的基本结构,它的输出状态主要是由右边框内的场效应管控制的。I/O从芯片内部电路引出,作为芯片的一个引脚(Pin,图中Pxn代表此意,虽然俺也不知道为什么手册里标了个xn…)
那么你可能要问了,单片机是如何通过代码来控制硬件的呢?

这一切都归功于一个叫 寄存器(Register) 的东西,感兴趣的话可以看看 这个回答

Arduino UNO上的ATMEGA328P的数字IO口是5V电平标准(因为该单片机的供电电压是5V),即输出高电平时对地电压为5V,低电平和地等电位(0V)。但是 输出电流呢?

这是一个值得令人思考的问题。设想一下,在如此小的芯片里集成的这么多线路和元件,那么元件之间的导线必定是非常非常细的,这么细的导线能承载多大的电流?假如我们在I/O口上串联一个10欧姆的电阻并将电阻另一端接地,当我们控制I/O输出高电平时这个I/O口的电流理论上来说高达0.5A,单片机真的可以承受这样的工作压力吗?

查阅数据手册(Datasheet)

这种时候我们需要新的信息,而且是芯片级别的,我们需要查阅单片机的数据手册。

ATMEGA328P的数据手册里的第258页,我们找到了关于I/O口电流承载力的数据表格。(如果PDF太长不好找的话,请按Ctrl+F开启搜索框,输入关键词并按回车进行跳转,这样查找的效率更高)


uIaz6g.jpg

DC current per I/O Pin: Typical. 40.0mA
DC current Vcc and GND Pins: Typical. 200.0mA
译:每个I/O口的最大电流一般是40mA,整个单片机同一时间所有I/O口的电流总和最大值一般是200mA(这个200mA包含了单片机内部电路正常工作所消耗的电流)

真相大白。我们在UNO的一个I/O口上接上一颗LED,串联电阻使它的工作电流保持在10mA以下是完全木有问题的~

假如我们在8个I/O上都接了一个LED,并控制它们的工作电流保持在10mA左右,当我们控制LED们全部点亮时,整个单片机I/O总线上的电流为80mA左右,虽然超出了单个I/O的最高额定电流,但80mA小于200mA,这样使用是安全的~

哈哈哈哈说了这么多,绕了一大圈终于绕回来了(我可能有点话痨)。相信你已经对刚开头那句话有了深刻的理解。

点亮一个灯所需要的电信号,不能单纯地在电压这一个维度上思考。


以下是一段Arduino的官方示例代码,实现的功能是让连接到数字端口3口的LED每隔1s切换一次

//初始化函数,单片机在启动时只运行一次
void setup() {
  //将数字端口3口设置为输出模式
  pinMode(3, OUTPUT);
}

//主循环函数,单片机在执行过初始化函数之后,就会不断地运行这一段函数,相当于在main函数里的while(1)
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

相信上面的程序对于有一定C语言基础的你来说十分简单易懂。它所实现的功能就是先让一颗LED亮起来(对端口写高电平),然后间隔1秒钟(1000毫秒),让它熄灭(对端口写低电平),再间隔1秒,让它重新亮起来,然后如此一直循环下去…

如果看不太懂上面的程序,不用着急,会在后续的章节中慢慢讲解。
不过我还是推荐你自学一些Arduino C++常用函数。

踩坑预警!

Arduino UNO有0-13,共计14个数字端口可用。但是,请尽量不要使用数字0和1端口,可以从板上的白色字(丝印)看到,上面标注了RX、TX字样,即这2个端口被用于单片机和USB转串口芯片的通信,而Arduino UNO开发板下载程序的途径一般是通过串口下载,如果在这2个端口上连接外围电路,很可能会在下载程序的时候出现问题qwq

看到这里,你的心中是不是已经有了大胆的想法?#滑稽

是的,如果我们多用几个数字端口来控制几个LED,再用一点点简单的逻辑,不就能实现流水灯了吗§( ̄▽ ̄

这就来实现!

//初始化函数,只运行一次
void setup() {
  char i;
  //偷了个懒,用循环给数字端口0-4口设置了输出模式qwq
  for (i = 0; i < 5; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
  }
}

//主循环函数
void loop() {
    //聪明的你一定看得懂吧23333
  digitalWrite(0, LOW);
  delay(300);
  digitalWrite(0, HIGH);
  digitalWrite(1, LOW);
  delay(300);
  digitalWrite(1, HIGH);
  digitalWrite(2, LOW);
  delay(300);
  digitalWrite(2, HIGH);
  digitalWrite(3, LOW);
  delay(300);
  digitalWrite(3, HIGH);
  digitalWrite(4, LOW);
  delay(300);
  digitalWrite(4, HIGH);
}

最终效果是这样滴↓↓↓↓↓

n3GOkq.gif

看到这里,有没有想要做一个狂拽炫酷吊炸天的流水灯?

下节预告

既然我们搞定了流水灯,下次我萌来做一个会呼吸的灯叭ε=ε=ε=(~ ̄▽ ̄)~

敬请期待!

已经写完辣 点击我查看

发表回复

这篇文章有 2 个评论

  1. 第 楼主啊页

    //void setup()里面
    char i = 1;
    //为什么是char 不是 int

    1. 第 Floyd-Fish页

      在Arduino语言里char可表示的范围是+-2^7,而int是+-2^15,int占用的内存空间(也就是RAM)会更大一些。如果我们在循环里使用的时候数值不超过127,就可以用char来节省空间啦。
      当然还有unsigned char型,可表示0-255,unsigned int型可表示0-65535