參考程式碼
//---------------------------------------------------------------------------
const int pb = 34; // 按鈕開關接腳
bool lastButtonState = HIGH; // 按鈕開關前一次的狀態
unsigned long lastDebounceTime = 0; // 按鈕開關前一次狀態改變時的millis()時間
int debounceDelay = 150; // 防彈跳預設的延遲時間
unsigned long buttonDownTime = 0; // 按鈕開關被按下的時間(長按時使用)
unsigned long longPressTime = 1500; // 長按時間(長按時使用)
//---------------------------------------------------------------------------
bool startCount = 0; // (0:停止,1:開始)
int count = 9999; // 計數器,初值為9999
//---------------------------------------------------------------------------
unsigned long previousMillis = 0; // 前一次的millis()時間
const long interval = 100; // 預設計時的時間
//---------------------------------------------------------------------------
int seg[8] = {15, 16, 17, 18, 19, 21, 22, 23};
// 對應的接腳 { a, b, c, d, e, f, g, dp}
int data[]= {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x67,0x00};
// 顯示的數字 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,全滅}
int com[4] = {25, 26, 27, 14};
// 對應的接腳 {com1,com2,com3,com4}
int digit[4] = { 8 , 4 , 2 , 1 };
// 位元掃瞄 {"1000","0100","0010","0001"};
int num[4] = {0, 0, 0, 0};
// 各位元數值 {千,百,十,個}
//---------------------------------------------------------------------------
int input; // 串列埠輸入的數值
//---------------------------------------------------------------------------
void setup() {
//--------------------------------------------------
Serial.begin(9600); // 啟用串列埠監看視窗
Serial.println("Enter a number(0~9999):"); //輸入提示
//--------------------------------------------------
pinMode(pb, INPUT); // 初始化按鈕開關
//--------------------------------------------------
// 初始化七段顯示器a~g、dp接腳
for(int i=0; i<=7; i++)
{
pinMode(seg[i], OUTPUT);
digitalWrite(seg[i],0); // 全滅
}
//--------------------------------------------------
// 初始化七段顯示器com1~com4接腳
for(int i=0; i<=3; i++)
{
pinMode(com[i], OUTPUT);
digitalWrite(com[i],0); // 全滅
}
//--------------------------------------------------
}
void loop() {
// ---------------------------------------------------------------------------------------------------------------
if (Serial.available()) //若串列埠有輸入資料,則執行下列程式區塊
{
input = readNumber();
if(input >=0 && input <=9999)
{
count = input;
}
else
{
Serial.println("Error, wrong number.");
Serial.println("Enter a number(0~9999):"); //輸入提示
}
}
// ---------------------------------------------------------------------------------------------------------------
unsigned long currentTime = millis(); // 當前的millis()時間
bool buttonState = digitalRead(pb); // 當前的按鈕開關狀態:未按下(HIGH),按下(LOW)
// 若按鈕開關狀態發生變化,且超過防彈跳預設的延遲時間
if ((buttonState != lastButtonState) && (currentTime - lastDebounceTime) > debounceDelay)
{
// --------------------------------------------------------------------------------------
if (lastButtonState == HIGH && buttonState == LOW) // 若按鈕從未按下(HIGH)到按下(LOW)
{
// --------------------------------------------------
// 按鈕按下時,想做的事
// --------------------------------------------------
buttonDownTime = currentTime; //記錄按鈕按下的時間
// --------------------------------------------------
}
else if (lastButtonState == LOW && buttonState == HIGH) // 若按鈕從按下(LOW)到未按下(HIGH)
{
// --------------------------------------------------
// 按鈕放開時,想做的事
// --------------------------------------------------
startCount = !startCount; // 取反相
if(startCount==0)
{
Serial.println("Stop."); // 印出停止狀態
}
else
{
Serial.println("Start count..."); // 印出開始計數狀態
}
// --------------------------------------------------
if((currentTime - buttonDownTime) >= longPressTime)
{
Serial.println("Long press detected, count reset.");
count=9999; // 重置計數器
startCount=0; // 停止計數
Serial.print("Button pressed count: "); // 印出計數器內容
Serial.println(count); // 印出計數器內容
}
// --------------------------------------------------
}
// --------------------------------------------------------------------------------------
lastButtonState = buttonState; // 更新按鈕狀態
lastDebounceTime = currentTime; // 更新前一次狀態改變時的millis()時間
}
// ---------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------
// 每經過一個interval的時間,要做的事
// ----------------------------------------------------------------------
unsigned long currentMillis = millis(); // 當前的millis()時間
if (currentMillis - previousMillis >= interval) // 若達到預設計時的時間
{
//---------------------------------------------------------------------
// 若設定為開始計數,則執行下列程式
//---------------------------------------------------------------------
if(startCount == 1)
{
count = count - 1; // 計數器減1
Serial.println(count);
}
//---------------------------------------------------------------------
previousMillis = currentMillis; // 更新前一次的millis()時間
}
// ----------------------------------------------------------------------
//-------------------------------------
// 顯示數字
//-------------------------------------
num[0] = count / 1000 % 10; // 千位
num[1] = count / 100 % 10; // 百位
num[2] = count / 10 % 10; // 十位
num[3] = count % 10; // 個位
showNum();
//-------------------------------------
}
void showdata(int x)
{
for(int i=0; i<7; i++)
digitalWrite(seg[i],bitRead(data[x],i));
}
void scan(int x){
for(int i=0; i<4; i++)
digitalWrite(com[i],bitRead(digit[x],3-i));
}
void showNum()
{
for(int i=0; i<4; i++)
{
showdata(num[i]);
scan(i);
delay(1);
}
}
// 讀取一個整數
int readNumber()
{
while (!Serial.available()); // 等待串列埠輸入
String input = Serial.readStringUntil('\n'); //讀取一行的輸入資料,直到換行符號為止(按下enter鍵)
input.trim(); //去除輸入字串前後的空白字元
Serial.println(input); //印出輸入字串
return input.toInt(); //轉換為整數
}
作業練習:
- 開機後,4位元七段顯示器顯示欲倒數計時的初始時間(例:1200代表12:00,時間12:00→11:59→11:58→……→11:01→11:00→10:59→……→00:00)。
- 每按一下按鈕開關,可開始或停止倒數計數(每秒減1,直到0000停止)。
- 長按按鈕開關,計數器重置為初始時間。
- 任何過程中,可以透過監看視窗改變倒數計時的數值。(輸入範圍0000~5959)
- 七段顯示器的狀態必須同步顯示在監看視窗上。
- 請完成實體接線。
重點提示:
- 不可直接對 4 位數字做 count–,否則會變成 12:00 → 11:99 → 11:98… 造成顯示錯誤。
- 正確觀念:輸入格式 (MMSS) → 內部格式(秒) → 輸出格式 (MMSS)。
- 輸入數值範圍在 0~5959 之間,兩位為分、兩位為秒,分數、秒數必須小於 60。
- 將輸入值轉換為「總秒數」進行倒數計時處理。
- 顯示時,再將「總秒數」轉換為「 MM:SS 」輸出到七段顯示器。
[輸入數值 1200] (代表 12分00秒)
↓
(拆解與驗證) MM=12, SS=00
↓
(轉為總秒數) 12*60 + 0 = [720 秒] <--- 計時器的核心
↓
(每一秒鐘) 720 - 1 = 719, 718...
↓
(顯示運算) 719 秒 是幾分幾秒?
719 / 60 = 11 (分)
719 % 60 = 59 (秒)
↓
[組合成顯示] 11*100 + 59 = [1159]
↓
[七段顯示器] 11:59