我们要结合 数字输入输出功能,制作一个可控制的LED。实现按住按键时,点亮LED,放开按键后,熄灭LED的效果。实验中我们将用到按键或者按键模块,常见的有2脚按键和4脚按键,其内部如图1所示。当按下按键时,就会接通按键两端,放开时,两端会再次断开。
图1
所需材料
Arduino、面包板、LED一个、按键一个、220Ω电阻一个、10KΩ电阻一个
连接示意图
原理图
如上图所示,我们使用了两个电阻。LED的一端,我们使用了220Ω的电阻,按键一端,我们使用了10K的电阻,两个电阻的作用分别如下:
限流电阻
一般LED的最大能承受的电流为25mA,如若直接将LED连接到电路中,当其点亮时,如果电流过大,很容易烧毁。我们在LED一端串联了一个电阻R2,这样做可以控制流过LED的电流,防止损坏LED。这个电阻我们称之为限流电阻。
下拉电阻
在Arduino的2号引脚到GND之前,连接了一个阻值10K的电阻。如果没有该电阻,当未按下按键时,2号引脚会一直处于悬空 状态,此时使用digitalRead() 读取2号引脚状态,会得到一个不稳定的值(可能是高,也可能是低)。添加这个R1电阻到地就是为了稳定引脚的电平,当引脚悬空时,就会识别为低电平。而这种将某节点通过电阻接地的做法,叫做下拉,这个电阻叫做下拉电阻。
实现方法分析
当未按下按键时,2号引脚检测到的输入电压为低电平;当按下按键时,会导通2号引脚和VCC,此时2号引脚检测到的输入电压为高电平。通过判断按键是否被按下,来控制LED的亮灭。
示例程序
int buttonPin = 2; //定义2号端口为连接按键的端口
int ledPin =13; //定义13号端口为连接LED灯的端口
void setup() { //初始化各个端口的输入输出模式
pinMode(buttonPin,INPUT);//
pinMode(ledPin,OUTPUT);
}
void loop() {
/********************************************
digital————数字信号
analog————模拟信号
Read()————读操作
Write()————写操作
digitalRead(端口)————读取括号里端口的数字信号
digitalWrite(端口,信号)————给端口写一个数字信号
********************************************/
/********************************************
*if—else判断语句:
if(条件){
语句1;
}
else{
语句2;
}
当满足()里的条件时执行语句1的代码,否则执行语句2的代码
********************************************/
if(digitalRead(buttonPin) == HIGH){
digitalWrite(ledPin,HIGH);
}
else{
digitalWrite(ledPin,LOW);
}
}
编译并上传该程序后,按下按键,你会观察到LED会被点亮,松开按键,LED又会熄灭。
接下来我们要对控制程序做一个升级,完成一个新的控制效果。按一下按键,点亮LED;再按一下按键,熄灭LED。
程序代码如下:
int buttonPin = 2;
int ledPin =13;
int ledState = false; //定义一个变量来判断LED灯的状态,初始状态为false表示灯灭的状态
void setup() {
Serial.begin(9600); //建立一个串口
pinMode(buttonPin,INPUT);
pinMode(ledPin,OUTPUT);
}
void loop() {
//等待按键按下
/*********************************************************************
* while(条件)循环语句,满足条件则进入循环
{}里没有代码则是保持原来的状态
**********************************************************************/
while(digitalRead(buttonPin)==LOW)
{
}
//当按键按下时改变LED灯的状态
/*********************************************************************
* !ledState——变量逻辑非
即ledState为false时!ledState为true;ledState为true时!ledState为false。
* ledState = !ledState;——刷新LED灯的状态(把改变后的状态重新赋给ledState)
**********************************************************************/
if(ledState == false)
{
digitalWrite(ledPin,HIGH);
ledState = !ledState;
}
else
{
digitalWrite(ledPin,LOW);
ledState = !ledState;
}
Serial.println(ledState); //通过串口观察ledState的值是否发生改变
delay(500);
}
编译并上传该程序后,每按一下按键,LED状态都会改变。以上程序中,使用了
while( digitalRead(buttonPin)==LOW ) { }
因为在初始化时,我们已经将buttonPin引脚设为了输入下拉状态。如果没有按下按键,使用digitalRead(buttonPin) 读出的值始终为低电平,这个循环也将一直运行;当你按下按键后,digitalRead(buttonPin) 读出了高电平,while循环的判断条件为假,程序会退出这个循环,并开始运行此后的语句。这样我们就实现了一个等待用户按下按键的效果。
程序末尾有一个delay(500) 的延时,它在这里是极其重要的。可以尝试删去这个延时操作,再上传程序到Arduino。你会发现按键经常出现控制失灵的情况。这是因为程序运行的非常快,没有了延时操作,你按下按键到放开按键的间隔时间虽然极短,但loop中的语句可能已经运行了很多次,很难确定你放开按键时正在运行的loop() 循环是点亮还是熄灭LED。正是这样的原因,程序变得不那么好用了。
上面程序中,我们使用延时操作来使两次按键间产生一定的间隔时间,在间隔时间内Arduino会忽略按键按下情况,从而达到区分两次按键的目的。
项目进阶
对于在以上项目,我们还可以做如下修改。
连接示意图
如上,我们去掉了原来电路中2号引脚连接的下拉电阻,并将按键的一端连接到GND;
原理图
同时,我们需要将原程序setup() 部分中的pinMode (buttonPin,INPUT); 修改为 pinMode (buttonPin,INPUT_PULLUP):
这样能使能该引脚上的内部上拉电阻,等效于在该引脚到VCC之间连接一个外部上拉电阻。
上拉电阻
同下拉电阻一样,可以稳定I/O口电平,不同的是电阻连接到VCC,将引脚稳定在高电位。这种电阻叫做上拉电阻。
这里使用的是内部上拉电阻,也可以使用外部上拉电阻替代。稳定悬空引脚的电平所用电阻应该选择合适的阻值,例如10K。
此时上面的程序则需要作如下修改:
程序1
pinMode (buttonPin,INPUT); 修改为 pinMode (buttonPin,INPUT_PULLUP);
程序2
pinMode (buttonPin,INPUT); 修改为 pinMode (buttonPin,INPUT_PULLUP):
while(digitalRead(buttonPin)==LOW) 修改为 while(digitalRead(buttonPin)==HIGH)
digitalWrite(ledPin,HIGH); 修改为 digitalWrite(ledPin,LOW);
digitalWrite(ledPin,LOW); 修改为 digitalWrite(ledPin,HIGH);
编译并上传该程序后,每按一下按键,LED状态都会改变。以上程序中,使用了
while( digitalRead(buttonPin)==HIGH ) { }
因为在初始化时,我们已经将buttonPin引脚设为了输入上拉状态。如果没有按下按键,使用digitalRead(buttonPin) 读出的值始终为高电平,这个循环也将一直运行;当你按下按键后,digitalRead(buttonPin) 读出了低电平,while循环的判断条件为假,程序会退出这个循环,并开始运行此后的语句。这样我们就实现了一个等待用户按下按键的效果。