搜尋程式碼

第17/31課:如何喺Arduino中斷延遲同光敏電阻LDR | Robojax

第17/31課:如何喺Arduino中斷延遲同光敏電阻LDR | Robojax

喺呢個指南入面,我哋會探討兩個重要嘅Arduino概念:中斷同光敏電阻(LDR)。你會學識點樣中斷你程式碼入面嘅延遲,令你嘅Arduino可以即時回應按鈕撳掣,然後我哋會整一個感光電路,可以喺夜晚自動開蜂鳴器或者燈。呢個項目好適合任何想超越基本閃爍LED程式,開始整有反應、真實世界自動化項目嘅人。你可以運用呢啲技巧嚟整一個走廊嘅智能夜燈、一個門打開時會響嘅簡單防盜警報、一個喺黃昏啟動嘅太陽能花園燈,或者一個太陽落山時會自動關埋嘅窗簾。呢堂課係基於SunFounder 3合1 Arduino套件,但係呢啲概念適用於任何標準Arduino板。

LDR_12708_orig
LDR Illustration and symbol

硬件同零件

要跟住呢個項目做,你需要以下零件。一個標準嘅Arduino Uno或者Nano好適合呢個製作。

  • Arduino Uno或者Nano
  • 光敏電阻(LDR),例如Kweeds KM601
  • 10k歐姆電阻
  • 按鈕
  • 蜂鳴器
  • 麵包板同跳線

了解Arduino中斷

喺一個標準嘅Arduino程式入面,loop()函數會不斷運行,逐行執行任務。當你用delay()嘅時候,Arduino會喺嗰段時間停止做任何其他嘢。如果你需要喺另一個任務運行緊嘅時候回應一個重要事件,好似撳掣咁,呢個就係一個問題。例如,如果你用一秒延遲嚟閃爍LED,撳掣可能要等成秒先至被偵測到,感覺上好唔靈敏(喺影片08:13)。

Arduino中斷可以解決呢個問題。中斷係一個硬件功能,容許一個特定引腳「中斷」主程式,暫停佢做緊嘅嘢,然後運行一個叫做中斷服務常式(ISR)嘅特殊函數。咁樣你嘅Arduino就可以即時回應高優先級事件,無論其他嘢做緊乜都得。要注意嘅係,唔係所有引腳都支援中斷。喺Arduino Uno同Nano上面,只有引腳2同3可以用嚟做呢個用途(喺影片02:37)。其他板好似Mega有更多選擇,但係喺呢個項目入面,我哋會用引腳2。

中斷可以由引腳上唔同嘅狀態變化觸發:LOWCHANGERISINGFALLINGCHANGE模式會喺引腳狀態由HIGH變LOW或者LOW變HIGH嘅時候觸發中斷,呢個好適合用嚟做按鈕切換。

接線指南

buzzer_push_button_schematic
lcd1602_I2C_wiring_sunfounder

我哋會喺呢堂課整兩個電路。第一個示範用按鈕同蜂鳴器嘅中斷,第二個用LDR嚟感應光線水平。我哋由中斷電路開始。

電路1:用嚟示範中斷嘅按鈕同蜂鳴器

呢個電路好直接。按鈕連接到引腳2,即係我哋嘅中斷引腳。一個10k歐姆下拉電阻確保當按鈕冇撳嘅時候引腳讀到LOW,撳嘅時候讀到HIGH。蜂鳴器連接到引腳8。

對於中斷示範,跟以下方式連接零件:

  • 按鈕:將一隻腳連接到5V,另一隻腳連接到數碼引腳2。由引腳2到GND連接一個10k歐姆電阻。
  • 蜂鳴器:將負極連接到GND,正極連接到數碼引腳8。

電路2:用嚟感光嘅LDR同蜂鳴器

對於LDR電路,我哋用一個分壓器配置。LDR嘅電阻會隨光線改變,從而改變模擬引腳嘅電壓。當黑暗嘅時候,LDR有高電阻(大約10k歐姆),當光猛嘅時候,電阻會顯著下降(喺影片16:25)。呢個電阻變化就係我哋量度嘅嘢。

分壓器係必須嘅,因為Arduino只可以讀電壓,唔可以讀電阻。將LDR同一個固定10k歐姆電阻串聯,佢哋之間嗰點嘅電壓會按比例隨LDR嘅電阻變化。呢個電壓跟住被Arduino嘅模擬轉數碼轉換器(ADC)讀取。

對於LDR示範,跟以下方式連接零件:

  • LDR:將一隻腳連接到5V,另一隻腳連接到模擬引腳A0。
  • 10k歐姆電阻:由連去A0嘅LDR腳向下連接到GND。咁樣就形成分壓器。
  • 蜂鳴器:將負極連接到GND,正極連接到數碼引腳8。

注意:確切嘅引腳分配喺程式碼入面定義,可以按你嘅設置更改。

程式碼解釋

我哋會集中睇提供嘅程式碼入面用戶可配置嘅部分,呢啲部分控制項目嘅行為。完整程式可以喺文章下面下載。

程式碼設計成容易修改。喺程式最頂部,你會搵到可以調整嘅主要變數。

const byte buzzerPin = 8;
const byte interruptPin = 2;
volatile byte state = LOW;
int count=0;

呢度,buzzerPin 設定做 pin 8,即係你連接蜂鳴器嘅位置。interruptPin 設定做 pin 2,即係用嚟監聽按鈕按下嘅引腳。state 變數係一個 volatile byte,用嚟保存蜂鳴器嘅當前狀態(HIGH 或者 LOW)。佢標記做 volatile 係因為佢會喺中斷服務常式(ISR)入面被修改,而呢個關鍵字確保 Arduino 永遠讀取最新嘅值。count 變數係一個簡單嘅計數器,會喺主迴圈入面遞增,用嚟示範當 interrupt 啟動時,主迴圈仍然喺度運行。

setup() 函數入面,蜂鳴器引腳設定做 OUTPUT,而 interrupt 引腳設定做 INPUT。最關鍵嘅一行係 attachInterrupt(),即係你配置 interrupt 嘅地方。呢個函數話畀 Arduino 知要監視邊個引腳、當 interrupt 發生時要呼叫邊個函數,以及用咩觸發條件。

attachInterrupt(digitalPinToInterrupt(interruptPin), noisy, CHANGE);

呢一行將一個 interrupt 附加到指定嘅引腳。digitalPinToInterrupt() 函數將引腳號碼轉換成正確嘅 interrupt 號碼。noisy 係當 interrupt 被觸發時會呼叫嘅函數名稱。最後,CHANGE 係模式,即係喺引腳任何狀態改變時觸發 interrupt。你可以根據需要將佢改做 RISINGFALLING 或者 LOW

noisy() 函數就係 ISR。佢係一個簡單嘅切換函數,用嚟翻轉蜂鳴器嘅狀態。當按鈕被按下時,interrupt 會觸發呢個函數,佢會反轉 state 變數並將佢寫入蜂鳴器引腳。咁樣你就可以每次按下按鈕時開關蜂鳴器,即使主迴圈忙緊計數同延遲。

要將項目嘅行為改做夜晚啟動蜂鳴器而唔係日頭,你需要修改主迴圈入面嘅條件邏輯,將 HIGH 同 LOW 狀態嘅 digitalWrite() 指令調轉。

實時項目同示範

喺示範入面,你會見到兩個關鍵實驗。首先,interrupt 電路冇載入 interrupt 程式碼嚟運行,其中迴圈入面嘅延遲令到按鈕反應遲鈍。呢個突顯咗 interrupt 要解決嘅問題。

然後,載入 interrupt 程式碼之後,序列監視器會顯示計數器每秒遞增。當按鈕被按下時,蜂鳴器會即時開關,無論主迴圈有咩延遲。呢個證明 interrupt 成功繞過等待時間並即時執行佢嘅任務(喺影片 14:07)。

對於 LDR 部分,序列監視器會打印原始模擬值。你可以見到喺光線充足時數值好高(大約 960),而當感測器被遮蓋時數值會大幅下降(到大約 400 或者更低)。呢個示範咗 LDR 嘅電阻點樣隨光強度改變。然後程式碼用一個閾值嚟判斷係「日頭」定「夜晚」,並相應控制蜂鳴器。透過遮蓋感測器嚟模擬夜晚,你可以觸發蜂鳴器,而將佢暴露喺光線下就可以關閉佢。

章節

  • [00:00] Arduino Interrupt 同 LDR 簡介
  • [01:43] Arduino 程式碼入面延遲嘅問題
  • [03:37] 理解 Interrupt 引腳同模式
  • [04:20] 接線按鈕同蜂鳴器電路
  • [06:22] 延遲示範嘅程式碼解釋
  • [07:48] 延遲問題嘅示範
  • [09:26] 實現同編寫 Interrupt
  • [11:50] Interrupt 函數點樣運作
  • [14:26] 光敏電阻(LDR)簡介
  • [15:44] 用萬用錶測量 LDR 電阻
  • [17:22] 接線 LDR 同蜂鳴器電路
  • [19:55] 讀取 LDR 數值嘅程式碼
  • [20:49] LDR 數值變化嘅示範
  • [22:08] 設定日頭同夜晚閾值
  • [23:40] 用 LDR 控制蜂鳴器嘅程式碼
  • [25:21] 自動夜燈嘅示範

圖片

An LDR
An LDR
LDR Illustration and symbol
LDR Illustration and symbol
lcd1602_I2C_wiring_sunfounder
lcd1602_I2C_wiring_sunfounder
buzzer_push_button_schematic
buzzer_push_button_schematic
buzzer_push_button_wiring
buzzer_push_button_wiring
ldr
ldr
LDR_12708_orig
LDR_12708_orig
913-Lesson 17/31: interrupt a delay in Arduino and Light Dependent Resistor LDR
語言: C++
/*
Lesson 20/31: interrupt a delay in Arduino and Light Dependent Resistor LDR
Get this code and watch video Download and resource page https://robojax.com/RJT600
YouTube video https://www.youtube.com/watch?v=N_L11m1v_yk
 
  
 * This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
 * This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
const byte buzzerPin = 8;
const byte interruptPin = 2;
volatile byte state = LOW;
int count=0;

void setup() {
  pinMode(buzzerPin, OUTPUT);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), noisy, CHANGE);
  Serial.begin(9600);
  digitalWrite(buzzerPin, state);
}

void loop() {
  count++;
  Serial.println(count);
  delay(1000);
}

void noisy() {
  state = !state;
  digitalWrite(buzzerPin, state);
}

資源與參考資料

文件📁

Arduino 函式庫 (zip)