本系列文章為作者原創,未經作者書面同意,不得轉載!
我們在電視綜藝節目里面經常看到多個選手搶答問題(其實我并不常看這種“娛樂奶嘴”節目,我也不建議你們看),一般每個選手前面都有一個搶答器,誰先按下搶答器按鍵,誰前面的燈就會點亮,然后就可以回答主持人提出的問題。
如何制作一個搶答器 ?
我們的第三個項目就是做一個搶答器,搶答器的使用一般是這樣的:在主持人和每位選手前面都有一個搶答按鈕,同時每位選手前面還有一盞燈,當主持人開始提問時,這時主持人會按一下自己前面的按鈕,讓系統準備就緒,所有選手面前的燈會閃動幾次,表示馬上要開始搶答了,然后主持人開始提問,選手在這過程中可以按下按鈕搶答問題,第一個按下按鈕的選手前面的燈會點亮,之后按下按鈕的選手前面的燈不再點亮。
1 本章您將學到
在這個項目中,您將學到的:
- 學會使用按鍵開關
- 學習讀取數字輸入信號
- 學會Arduino程序設計中的選擇結構及其實現
2 工具和組件
2.1 工具列表
本項目不需要額外的工具。
2.2 元器件列表
元器件 | 型號 | 數量 | 備注 |
---|---|---|---|
主控板 | arduino Uno | 1 | |
LED燈 | 3 | 紅黃綠各一個 | |
電阻 | 220歐姆 | 3 | |
電阻 | 10K歐姆 | 4 | |
按鍵開關 | 3 | ||
面包板 | 1 | ||
杜邦線 | 12 | ||
數據線 | Uno數據線 | 1 |
2.3 工具和元器件介紹
2.3.1 按鍵開關
按鍵開關是我們在項目中第一次使用,我們簡單介紹一下:
按鍵之類的開關有好幾種,有兩針腳、四針腳、六針腳等,兩針腳很單純,就是按下后兩個針腳會接通,四針腳或六針腳的話,實際上要看說明,了解哪些腳位是連通,而哪些是由開關控制。以本次項目使用的的四針腳開關為例,腳位突出的一邊在按鍵按下前彼此不連通,而與對面腳位是連通的,見下面的按鍵開關示意圖:
按鍵開關工作原理:在按鍵沒有按下時,四針腳開關中的1、2腳連通,3、4腳聯通;當按鍵按下時,所有針腳全部連通,如下圖所示:
我們在購買按鍵開關時記得同時購買按鍵和按鍵帽,按鍵帽可以直接扣在按鍵上,有各種不同顏色的按鍵帽,通過按鍵帽跟按鍵的搭配,能夠對按鍵進行區分標識,還有就是看起來也舒服多了(當然裸奔也不影響功能):
下圖是扣上按鍵帽后的按鍵開關的樣子:
3 電路設計
3.1 電路圖
根據我們的項目需求,設計電路圖如下:
為了區分主持人和選手,我們把主持人的按鍵開關放在了最左邊。
3.2 電路原理
三盞燈的連接就不多介紹了,上一章中有詳細的介紹,這里主要介紹一下按鍵開關的電路連接。
為了便于說明按鍵開關的電路連接,我們去掉了電路中的其它部分,單獨只看一個按鍵開關的電路連接,它是這樣的:
這個電路看起來還是比較簡單的,在按鍵沒有按下時,13引腳的輸入狀態是0(低電平),當按鍵按下后,由于跟5V高電平引腳連通,13引腳的輸入狀態變成1(高電平)。
在上面的電路中,我們使用了一個下拉電阻(10K歐姆),對于這個電阻的作用,可能有些朋友會有些迷惑,其實在有些電路中還有一種與之功能類似的電阻叫做上拉電阻(功能類似,但作用相反),這里我們介紹一下這兩種電阻的作用。
3.2.1 上拉電阻/下拉電阻
下面是上拉電阻和下拉電阻的定義:
上拉電阻:用于當輸入端無確定電平(開路)時,將輸入確定到邏輯1上,否則這個懸空的輸入端,可能由于干擾之類的,被拉到邏輯0。
下拉電阻:用于當輸入端無確定電平(開路)時,將輸入確定到邏輯0上,否則這個懸空的輸入端,可能由于干擾之類的,被拉到邏輯1。
怎么樣,這個定義是不是說得很清晰、很明白了?看了后,你是不是覺得云里霧里的。
好,別著急,俗話說“一圖解千言”,我們還是上幾張圖來說明問題,圖片來源:youtube視頻截圖。
不好意思,忘了講了,圖片中的文字是英文的,為了讓小朋友能看明白,我還是來翻譯一下:
左邊的邏輯電路兄弟(單片機)的輸入引腳:嗨,請給我一個確定的“0”,或者“1”的邏輯信號(就是低電平或者高電平信號)。
但是右邊的兄弟:輸入引腳接的是一個開關,正處在懸空狀態(“斷開”的狀態),所以右側兄弟的回答是:“對不起,我可能是邏輯“0”,嗯,可能是懸空的!”
這樣的回答顯然不能讓左側的兄弟滿意,因為你的回答太猶豫了,太沒有確定性了,讓人沒法相信你。所以,如下圖,左側的兄弟顯然很著急:“什么?!在這種情況下,我該怎么辦?”
所以說:找個靠譜的隊友有多么重要!
顯然右側的兄弟已經意識到了這一點,它開始讓自己變得靠譜起來,它增加了一個電阻,電阻另一端接在高電平VCC(邏輯1)上。
好吧,看看這時開關閉合和斷開的狀態:
左側的兄弟這時候可以得到非常明確的信號“0”,或者“1”了,“哇,它再也不是懸空的狀態了,謝謝你,電阻兄弟,我的朋友!”
你現在是不是有點明白了,還沒明白?沒關系,再看一遍,其實我也是看了幾遍才明白的!
我們來總結一下:
單片機的管腳輸入需要有明確的信號,也就是要么高電平,要么低電平。通常我們認為,你的輸入腳如果和VCC相接,那肯定是高電平;和GND相接,那肯定是低電平。然而還有一種狀態你可能忽視了,就是管腳懸空的時候。
管腳懸空的時候,由于電路中的電磁感應,可以在管腳上隨機地感應出時高時低的電平,這就使得在單片機看來,你在隨機地輸入1或0。這顯然也不是你所需要了。你所需要的是明確的高或低電平。這時候電阻來幫忙了。
如果這個電阻的一端連在了VCC上,那這個電阻就是所謂的“上拉電阻”,它可以幫助管腳肯定處于高電平。bingo!問題解決!
如果這個電阻的一端連在了GND上,那這個電阻就是所謂的“下拉電阻”,它可以幫助管腳肯定處于低電平。bingo!問題解決!上拉電阻和下拉電阻的目的是幫助電路消滅因為感應電壓帶來的隨機高低電平。
4 程序設計
我們已經完成了電路部分的設計,下面就要開始進行程序設計了,不過在開始進行主程序編寫之前,我們還要做件事情:
- 要先了解一下Arduino程序設計中的判斷結構和相應的控制語句,本項目中需要用到。
4.1 Arduino程序設計中的判斷結構
程序中的判斷結構要求程序設計者指定要由程序評估或測試的一個或多個條件,以及條件為真時要執行的語句(必需的)和條件為假時要執行的語句(可選的)。
以下是Arduino編程語言中判斷結構的一般形式:
Arduino編程語言提供了幾種類型的判斷語句:
- if 語句
- if... else 語句
- switch 語句
我們今天主要介紹 if 語句和 if..else 語句:
4.1.1 if 語句
if 語句由一個布爾表達式后跟一個或多個語句組成。
語法:
Arduino中 if 語句的語法:
if(boolean_expression) //括號中為布爾表達式
{
// 如果布爾表達式為真將執行的語句
}
如果布爾表達式為 true,則 if 語句內的代碼塊(可以是一條語句,也可以是多條語句,如果是多條語句,則必須放在大括號內,作為一個語句塊)將被執行。如果布爾表達式為 false,則 if 語句結束后的第一組代碼(閉括號后)將被執行。
if 后面小括號里求值的表達式,需要以下操作符:
比較運算操作符:
- x == y(x 等于 y)
- x != y(x 不等于 y)
- x < y(x 小于 y)
- x > y(x 大于 y)
- x <= y(x 小于等于 y)
- x >= y(x 大于等于 y)
警告:
請注意賦值運算符和比較運算符。
- 兩個“=”表示的是比較運算符運算符,如 if (x == 10),作用是判斷x是否和10相等,如果相等,則布爾表達式( x==10 )為真,程序開始執行 if 后面語句塊,否則為假,程序跳過 if 后面的語句快。
- 一個“=”表示的是賦值運算符,如 if (x = 10),作用是將10 賦值給 x,而 該布爾表達式 (x = 10)永遠為真,應為在Arduino中,非 0 值永遠為真,這時候不管發生什么,程序都將執行 if 后面的語句塊,同時 x 也被賦值為 10。顯然這都不是我們期待的結果。
流程圖:
示例
if (x > 120) digitalWrite(LEDpin, HIGH);
if (x > 120)
digitalWrite(LEDpin, HIGH);
if (x > 120){ digitalWrite(LEDpin, HIGH); }
if (x > 120){
digitalWrite(LEDpin1, HIGH);
digitalWrite(LEDpin2, HIGH);
}
以上所有書寫方式都正確,請注意語句必須以英文分號 “;” 結束。
4.1.2 if...else 語句
if...else 是比 if 更為高級的判斷流程控制語句,它可以進行多次條件判斷。比如,檢測模擬輸入的值,當它小于500時該執行哪些操作,大于或等于500時執行另外的操作。
語法
if...else 語句的語法:
if (boolean_expression) //括號中為布爾表達式
{
// 如果布爾表達式為真將執行的語句
}
else
{
// 如果布爾表達式為假將執行的語句
}
流程圖
示例
if (temperature >= 70) //第一個布爾表達式
{
//危險,關閉系統
}
else if (temperature >= 60 && temperature < 70) //第二個布爾表達式
{
//警告,用戶需要注意
}
else
{
//安全
}
這段示例代碼中,第一個布爾表達式首先對 溫度變量 temperature 進行判斷,當其大于等于70時,危險,需要關閉系統(代碼中并沒有給出執行的語句,只作為示意);如果第一個布爾表達式為假,則第二個布爾表達式再對 temperature 進行判斷,當其小于70,但大于等于60時,系統會進行告警;如果前兩個布爾表達式都為假,則執行最后一個 else 后的語句塊。
4.2 主程序設計
/*
*名稱:搶答器
*功能:
*作者:YXK
*時間:2018.5.28
*/
//定義LED燈的引腳
const int redLed = 12;
const int yellowLed = 11;
const int blueLed = 10;
//定義按鍵開關引腳
const int redButton = 7;
const int yellowButton = 6;
const int blueButton = 5;
const int startButton = 13;
int r=0,y=0,b=0,s=0; //定義三個變量存儲三個按鍵開關的狀態
bool ready = false; //定義一個變量用于記錄搶答器是否就緒的狀態
void setup() {
// put your setup code here, to run once:
// 定義引腳輸入輸出狀態
pinMode(redLed, OUTPUT);
pinMode(yellowLed, OUTPUT);
pinMode(blueLed, OUTPUT);
pinMode(redButton, INPUT);
pinMode(yellowButton, INPUT);
pinMode(blueButton, INPUT);
pinMode(startButton, INPUT);
//將LED燈的初始化狀態設定為熄滅
digitalWrite(redLed, LOW);
digitalWrite(yellowLed, LOW);
digitalWrite(blueLed, LOW);
}
void loop() {
// put your main code here, to run repeatedly:
// 讀取四個按鍵開關的狀態
r = digitalRead(redButton);
y = digitalRead(yellowButton);
b = digitalRead(blueButton);
s = digitalRead(startButton);
if(s==1){ //如果主持人按下開始搶答按鈕,選手前面的LED閃爍3次
for(int i=0;i<3;i++){
digitalWrite(redLed, HIGH);
digitalWrite(yellowLed, HIGH);
digitalWrite(blueLed, HIGH);
delay(500);
digitalWrite(redLed, LOW);
digitalWrite(yellowLed, LOW);
digitalWrite(blueLed, LOW);
delay(500);
}
ready = true;
}
//當搶答器處于就緒狀態時
//紅色按鍵按下
if(ready && r==1){
digitalWrite(redLed, HIGH);
ready = false;
}
//黃色按鍵按下
if(ready && y==1){
digitalWrite(yellowLed, HIGH);
ready = false;
}
//藍色按鍵按下
if(ready && b==1){
digitalWrite(blueLed, HIGH);
ready = false;
}
}
說明:主程序中有一個 for 循環控制語句,這部分內容后續章節會有介紹,在本項目中,您只需要知道它的功能即可:就是讓所有選手前面的燈閃爍三次。
5 安裝調試
根據電路圖,最后做出來的效果是這個樣子的:
左邊的白色按鈕是主持人用的復位按鈕,右邊分別時選手面前的燈和按鍵。
我們只是用面包板搭建了模擬系統,其實如果時間充裕,可以為每位選手做單獨做一個搶答器,每個上面有一個按鈕和一個LED燈,具體的設計大家可以發揮想象,那樣看起來就更接近真實了。
比方說,網上有兄弟做出來的效果是這個樣子的:
電路都是差不多的,只是形式不同,有空的朋友可以多動動手,讓自己的電子制作看起來更加實用或者漂亮,呵呵,這也很重要哦!
6 總結擴展
這個項目實際上并不復雜,電路設計和主程序代碼都還有改進的空間,但為了初學者理解,我們并沒有引入相對復雜的設計。
隨著學習的深入,有興趣的朋友可以對其進行改進,如,簡化電路的設計(如:采用內部下拉電阻),或者讓程序看起來更加簡潔并且適應性更好(如考慮增加選手的情況)。
另外也可以增加一個顯示模塊,讓主持人可以輕易的看到搶答的結果,當然這個需要我們一步一步的學習后再來考慮改進,呵呵,想法+努力,你就是最棒的!
如果您喜歡本文,您可以點擊一下下面的喜歡按鈕,您也可以關注我,謝謝您的支持!