最近研讀關於七段顯示器的章節,發現要顯示七段顯示器的程式還比接線路還要簡單的說!
而本演練的重點將在於以顯示七段顯示器的數字當基礎,實作出亂數選號器!
在此不會畫相關線路圖,僅以提供實際拍的圖片,也由於接的線路八成都是來自於書本內,
僅有額外接的元件,如按鍵、紅外線接收器、蜂鳴器等,但這幾個元件的線路都很簡單,因
此可以以書本為原型來接出此線路!
在此使用的素材如下:
1. Arduino Uno R3
2. 麵包板
3. 74HC595*1
4. 共陰極七段顯示器*1
5. 220Ω*7
6. 麵包線*24
7. 10KΩ*1
8. LED燈(藍)*1
9. 按鍵開關*1
10.蜂鳴器*1
11.紅外線接收器*1
12.單晶片遙控器*1
書中的實驗7-2 提供七段顯示器接74HC595藉以減少使用控制板的PIN腳,相關素材為1~6
,而7 ~ 12的部分在此自行加上以此完成亂數選號器的製作!
一、演練效果說明
1. 當板子接上電源後,顯示器初始化顯示為0
在此需注意的是
irrecv.blink13(true);表示紅外線接收器若收到訊號,則正極接13腳位的二極體會自動閃爍。randomSeed(analogRead(0)); 設定randomSeed初始化,並且assign未被連接的類比腳位
再來是loop()內使用到的全域變數部分
LEDs array的index 0 ~ 9相當於七段顯示器顯示數字的二進位表示
B → 這個base表示為binary,後面可指定 0 or 1共8 bit values (官方說明)
COUNT → 表示亂數選號是否須停止使用
DELAY_MILLISEC → 一開始選號轉動delay的時間
autoExec → 判斷是否為自動執行亂數選號動作
index → 記錄目前要顯示哪個LEDs array的index值
randNumber → 產生的亂數值
loop()程式如下:
由於顯示七段顯示器使用了74HC595,因此在呼叫shiftOut前需先將TMP_PIN set LOW
3.1 紅外線接收訊號處理
再來是呼叫convertRECVtoIndex(),以此將接收到的紅外線訊號轉換成LEDs's index
針對上述的十進位數值如何取得,乃事前先一一輸入後印出得到的值,再將它設到程式內。
當得到回傳值之後,若得到非-1表示接收到紅外線有效的訊號值
如此一來可以呼叫showLEDs();
這一段乃是課本範例使用到的,呼叫shiftOut再將TMP_PIN set to HIGH
這樣子燈號就會顯示相關的數字囉!
關於shiftOut的語法為 shiftOut(dataPin, clockPin, bitOrder, value)
dataPin and clockPin上面已經有宣告了
bitOrder,在此搭配array value及麵包板接的順序須採用最低位元先傳
以LED[0]來說 → B01111110 最低位元在最右邊的0
搭配板子上接的順序 a ~ g(七段顯示器編號) 對應 74HC595為 1 ~ 7
因此最右邊的0先傳給g,其他七段顯示器的編號都將會是1,因此最後燈號顯示的是0
PS. 這邊可以搭配書本7-11的圖片說明及7-14的電路圖來參考較好理解
value表示LEDs's value
再來當接收到符合的紅外線訊號後,若當下已經在自動選號的情況下將會停止
並判斷index若為0需累計1,表示當按下按鍵後可以顯示燈號1
3.2 初始化顯示
當程式初始化時判斷if(COUNT == 0 && index == 0)成立後會顯示0
3.3 亂數選號
從if(on || autoExec)判斷可以得知,進去的條件為按下按鍵或者是自動選號執行當下
當從停下的燈號,第一次按下按鍵後(on => 1)才會開始執行選號動作
請看註解2. about switch這一段code,滿足此時autoExec為false
若index == 1表示目前燈號停留在0,此時呼叫initialize()
並呼叫generateRandomNum()取得一亂數值
取得亂數值越大,數字就會轉動越久,因為每一次的loop會進行COUNT累加,然後再判斷
是否已等於亂數值,同時為了要製造轉動後越來越慢等於快得到結果的效果,因此delay內
的數值會越來越大! 取得亂數值時range是設成50 ~ 300之間,並做簡單的判斷來使亂數值相
對應縮小!
若index != 1表示停下來的燈號是顯示0以外的數值,因此按鍵按下會先歸零且不動
再來請看註解3. if auto execute and get stop condition,此時呼叫checkAutoExecState()
這邊就是在檢查自動選號當下,自動累加DELAY_MILLISEC變數使得數字變換會越來越
慢,並且判斷COUNT的計數是否等於亂數值了,原本一開始只設定這個條件,後來發現
每次選號停下來的index會有重複性高的情況! 因此再加上第二個條件,那就是前者成立後
選號還是不會停止,直到COUNT(相當於亂數值)的個位數等於index後才會停止!
如此一來,若此次的亂數值為129,表示最後選號會落在9這個數值! 完全由亂數值來決定
最後的index值,這樣子的效果就比較不會有重複性選到一樣的數字!
註解4. change 七段顯示器燈號 by index已重複提過,顯示燈號並且做delay間隔的效果
註解5. condition calculation,只不過是一些變數的累加
最後則是註解1. about Beating device
這段code是搭配蜂鳴器的使用,程式碼也很簡單。目的是當使用者按下按鍵後,此時已開始
自動選號,若還按著按鍵不放蜂鳴器就會開始響!! 做一個警示作用!
DEMO影片如下:
參考資料
1. 葉難的Arduino練習:紅外線傳送與接收
2. 趙英傑著 超圖解 arduino 互動設計入門第3版第七章節
而本演練的重點將在於以顯示七段顯示器的數字當基礎,實作出亂數選號器!
在此不會畫相關線路圖,僅以提供實際拍的圖片,也由於接的線路八成都是來自於書本內,
僅有額外接的元件,如按鍵、紅外線接收器、蜂鳴器等,但這幾個元件的線路都很簡單,因
此可以以書本為原型來接出此線路!
在此使用的素材如下:
1. Arduino Uno R3
2. 麵包板
3. 74HC595*1
4. 共陰極七段顯示器*1
5. 220Ω*7
6. 麵包線*24
7. 10KΩ*1
8. LED燈(藍)*1
9. 按鍵開關*1
10.蜂鳴器*1
11.紅外線接收器*1
12.單晶片遙控器*1
書中的實驗7-2 提供七段顯示器接74HC595藉以減少使用控制板的PIN腳,相關素材為1~6
,而7 ~ 12的部分在此自行加上以此完成亂數選號器的製作!
實際電路接法一
實際電路接法二
遙控器發射訊號 → 紅外線接收器
一、演練效果說明
1. 當板子接上電源後,顯示器初始化顯示為0
2. 當使用者按下按鍵,此時顯示器會從0開始,一路由0 ~ 9自動選號,當過了很多輪之後直到
程式符合相關條件後才會停下!
3. 當顯示器已經在選號時,若持續按著按鍵將發出聲響提醒已開始選號了,不用再按囉!
4. 當顯示器已經在選號時,若此時利用遙控器點選數字,板子上的LED二極體將發光表示收
到訊號了,顯示器的選號將立即停止並顯示該數字!
二、簡單說明一下電路接法
排除七段顯示器接74HC595的部分之後,剩下要接為紅外線接收器、按鍵開關、蜂鳴器等!
紅外線接收器(正面)左 Vout → 數位 2
紅外線接收器(正面)中 GND → 接地
紅外線接收器(正面)右 Vcc → 正極
74HC595序列輸入腳 → 數位 3
74HC595暫存時脈腳 → 數位 4
74HC595序列時脈腳 → 數位 5
按鍵開關 → 數位 6
蜂鳴器(+) → 數位 7
遙控器發射訊號 → 輸入數字 0 ~ 9(不相關硬加上XD)
三、程式說明
這邊由於需要使用到紅外線訊號接收的功能,因此需要載入相關程式庫
請將解壓縮後的IRremote目錄放至 Arduino安裝目錄下的libraries\
首先在setup method內進行相關初始化動作及宣告相關全域變數
紅外線接收器(正面)左 Vout → 數位 2
紅外線接收器(正面)中 GND → 接地
紅外線接收器(正面)右 Vcc → 正極
74HC595序列輸入腳 → 數位 3
74HC595暫存時脈腳 → 數位 4
74HC595序列時脈腳 → 數位 5
按鍵開關 → 數位 6
蜂鳴器(+) → 數位 7
遙控器發射訊號 → 輸入數字 0 ~ 9(不相關硬加上XD)
三、程式說明
這邊由於需要使用到紅外線訊號接收的功能,因此需要載入相關程式庫
請將解壓縮後的IRremote目錄放至 Arduino安裝目錄下的libraries\
首先在setup method內進行相關初始化動作及宣告相關全域變數
#include <IRremote.h>
int RECV_PIN = 2;
const byte DATA_PIN = 3;
const byte TMP_PIN = 4;
const byte CLOCK_PIN = 5;
const byte SW_PIN = 6;
const byte BUZZER_PIN = 7;
IRrecv irrecv(RECV_PIN);
void setup() {
// put your setup code here, to run once:
//Serial.begin(9600);
pinMode(DATA_PIN, OUTPUT);
pinMode(TMP_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(SW_PIN, INPUT);
irrecv.blink13(true);
irrecv.enableIRIn();
randomSeed(analogRead(0));
}
在此需注意的是
irrecv.blink13(true);表示紅外線接收器若收到訊號,則正極接13腳位的二極體會自動閃爍。randomSeed(analogRead(0)); 設定randomSeed初始化,並且assign未被連接的類比腳位
再來是loop()內使用到的全域變數部分
//七段顯示器 共陰極 0 ~ 9
const byte LEDs[10] = {
B01111110,
B00110000,
B01101101,
B01111001,
B00110011,
B01011011,
B01011111,
B01110000,
B01111111,
B01111011
};
int COUNT = 0;
int DELAY_MILLISEC = 20;
boolean autoExec = false;
int index = 0;
long randNumber;
LEDs array的index 0 ~ 9相當於七段顯示器顯示數字的二進位表示
B → 這個base表示為binary,後面可指定 0 or 1共8 bit values (官方說明)
COUNT → 表示亂數選號是否須停止使用
DELAY_MILLISEC → 一開始選號轉動delay的時間
autoExec → 判斷是否為自動執行亂數選號動作
index → 記錄目前要顯示哪個LEDs array的index值
randNumber → 產生的亂數值
loop()程式如下:
void loop() {
// put your main code here, to run repeatedly:
boolean on = digitalRead(SW_PIN);
digitalWrite(TMP_PIN, LOW);
//Get remote control signal and convert to LEDs's index
int sendRECV = convertRECVtoIndex();
if(sendRECV != -1){
index = sendRECV;
showLEDs();
autoExec = false; //interrupt auto exec
if(index == 0){
index++;
}
}
if(COUNT == 0 && index == 0){
showLEDs();
index++;
}
//Auto execute selection number
if(on || autoExec){
//1. about Beating device
if(on && autoExec){
unsigned char i;
for(i=0;i<80;i++){
digitalWrite(BUZZER_PIN, HIGH);
delay(1);
digitalWrite(BUZZER_PIN, LOW);
delay(1);
}
}
//2. about switch
if(on && !autoExec){
if(index == 1){ //current number display 0
initialize();
autoExec = true;
randNumber = generateRandomNum();
//Serial.println(randNumber);
}else{
index = 0;
}
delay(300);
}
//3. if auto execute and get stop condition
checkAutoExecState();
//4. change 七段顯示器燈號 by index
showLEDs();
delay(DELAY_MILLISEC);
//5. condition calculation
index++;
if(index == 10){
index = 0;
}
if(autoExec && COUNT != randNumber){
COUNT++;
}
}
}
由於顯示七段顯示器使用了74HC595,因此在呼叫shiftOut前需先將TMP_PIN set LOW
3.1 紅外線接收訊號處理
再來是呼叫convertRECVtoIndex(),以此將接收到的紅外線訊號轉換成LEDs's index
int convertRECVtoIndex(){
int cindex = -1;
if (irrecv.decode(&results)) { // 接收紅外線訊號並解碼
long receive = results.value;
switch(receive){
case 16738455:{//0
cindex = 0;
break;
}
case 16724175:{//1
cindex = 1;
break;
}
case 16718055:{//2
cindex = 2;
break;
}
case 16743045:{//3
cindex = 3;
break;
}
case 16716015:{//4
cindex = 4;
break;
}
case 16726215:{//5
cindex = 5;
break;
}
case 16734885:{//6
cindex = 6;
break;
}
case 16728765:{//7
cindex = 7;
break;
}
case 16730805:{//8
cindex = 8;
break;
}
case 16732845:{//9
cindex = 9;
break;
}
}
irrecv.resume(); // 準備接收下一個訊號
}
return cindex;
}
針對上述的十進位數值如何取得,乃事前先一一輸入後印出得到的值,再將它設到程式內。
當得到回傳值之後,若得到非-1表示接收到紅外線有效的訊號值
如此一來可以呼叫showLEDs();
void showLEDs(){
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, LEDs[index]);
digitalWrite(TMP_PIN, HIGH);
}
這一段乃是課本範例使用到的,呼叫shiftOut再將TMP_PIN set to HIGH
這樣子燈號就會顯示相關的數字囉!
關於shiftOut的語法為 shiftOut(dataPin, clockPin, bitOrder, value)
dataPin and clockPin上面已經有宣告了
bitOrder,在此搭配array value及麵包板接的順序須採用最低位元先傳
以LED[0]來說 → B01111110 最低位元在最右邊的0
搭配板子上接的順序 a ~ g(七段顯示器編號) 對應 74HC595為 1 ~ 7
因此最右邊的0先傳給g,其他七段顯示器的編號都將會是1,因此最後燈號顯示的是0
PS. 這邊可以搭配書本7-11的圖片說明及7-14的電路圖來參考較好理解
value表示LEDs's value
再來當接收到符合的紅外線訊號後,若當下已經在自動選號的情況下將會停止
並判斷index若為0需累計1,表示當按下按鍵後可以顯示燈號1
3.2 初始化顯示
當程式初始化時判斷if(COUNT == 0 && index == 0)成立後會顯示0
3.3 亂數選號
從if(on || autoExec)判斷可以得知,進去的條件為按下按鍵或者是自動選號執行當下
當從停下的燈號,第一次按下按鍵後(on => 1)才會開始執行選號動作
請看註解2. about switch這一段code,滿足此時autoExec為false
若index == 1表示目前燈號停留在0,此時呼叫initialize()
void initialize(){
DELAY_MILLISEC = 20;
COUNT = 0;
}
並呼叫generateRandomNum()取得一亂數值
long generateRandomNum(){
long num = random(50,300);
if(num > 150 && num < 200){
num = num - 50;
}else if(num >= 200 && num < 250){
num = num - 100;
}else if(num >= 250){
num = num - 150;
}
return num;
}
取得亂數值越大,數字就會轉動越久,因為每一次的loop會進行COUNT累加,然後再判斷
是否已等於亂數值,同時為了要製造轉動後越來越慢等於快得到結果的效果,因此delay內
的數值會越來越大! 取得亂數值時range是設成50 ~ 300之間,並做簡單的判斷來使亂數值相
對應縮小!
若index != 1表示停下來的燈號是顯示0以外的數值,因此按鍵按下會先歸零且不動
再來請看註解3. if auto execute and get stop condition,此時呼叫checkAutoExecState()
void checkAutoExecState(){
if(autoExec){
DELAY_MILLISEC += 2;
if(COUNT == randNumber && COUNT % 10 == index){
autoExec = false;
}
}
}
這邊就是在檢查自動選號當下,自動累加DELAY_MILLISEC變數使得數字變換會越來越
慢,並且判斷COUNT的計數是否等於亂數值了,原本一開始只設定這個條件,後來發現
每次選號停下來的index會有重複性高的情況! 因此再加上第二個條件,那就是前者成立後
選號還是不會停止,直到COUNT(相當於亂數值)的個位數等於index後才會停止!
如此一來,若此次的亂數值為129,表示最後選號會落在9這個數值! 完全由亂數值來決定
最後的index值,這樣子的效果就比較不會有重複性選到一樣的數字!
註解4. change 七段顯示器燈號 by index已重複提過,顯示燈號並且做delay間隔的效果
註解5. condition calculation,只不過是一些變數的累加
最後則是註解1. about Beating device
這段code是搭配蜂鳴器的使用,程式碼也很簡單。目的是當使用者按下按鍵後,此時已開始
自動選號,若還按著按鍵不放蜂鳴器就會開始響!! 做一個警示作用!
DEMO影片如下:
參考資料
1. 葉難的Arduino練習:紅外線傳送與接收
2. 趙英傑著 超圖解 arduino 互動設計入門第3版第七章節
留言
張貼留言