微控制器(MCU)幾乎存在于你日常使用的所有電子產(chǎn)品中,例如交通燈。交通燈在控制器的作用下,控制器確保整個交通網(wǎng)絡(luò)保持順暢。
雖然構(gòu)建大型交通管理系統(tǒng)是一個非常高級的項(xiàng)目,但構(gòu)建由樹莓派 Pico 驅(qū)動的微型模擬器本身就很簡單。通過這個項(xiàng)目,你將看到如何控制多個 LED,設(shè)置不同的時 間,以及如何在程序的其余部分繼續(xù)運(yùn)行時監(jiān)控一個按鈕輸入,使用一種稱為線程的技術(shù)。
搭建這個項(xiàng)目,你需要:
– 樹莓派 Pico
– 面包板
– 紅色、黃色、綠色的 LED
– 330Ω 電阻 3 個
– 一個有源蜂鳴器
– 一組公對公跳線
– microUSB 數(shù)據(jù)線
將 Pico 連接到樹莓派或其他運(yùn)行 Thonny MicroPython IDE 的計(jì)算機(jī)。
簡易的交通燈
首先用面包板搭建一個簡單的紅綠燈系統(tǒng)電路,如圖所示。拿起你的紅色LED燈,把紅色 LED 插到面包板上,讓它跨過中間的分割線。使用一個 330Ω 電阻和跳線串連到 Pico 上。其中,LED 較長的腳和電阻連接,較短的腳和 Pico 的 GND 引腳通過跳線連通。
黃色和綠色的 LED 也類似處理,但使用的 Pico 引腳不同,參考圖片所示。
啟動 Thonny。創(chuàng)建一個新的程序,然后開始導(dǎo)入 machine 庫,以便你可以控制你的 GPIO 引腳:
import machine
你還需要導(dǎo)入 utime 庫,以便你可以在亮燈與滅燈之間添加延遲:
import utime
在你控制你 Pico 的 GPIO 口的任何程序里,在使用前都你將需要對它進(jìn)行設(shè)置:
led_red = machine.Pin(15, machine.Pin.OUT) led_amber = machine.Pin(14, machine.Pin.OUT) led_green = machine.Pin(13, machine.Pin.OUT)
這些線將 GP15、GP14 和 GP13 引腳設(shè)置為輸出,每個引腳都有一個述性的名稱,以便于代碼通俗易懂。
真正的紅綠燈不會一閃而過然后停下來,它們會不停地開著,即使那里不塞車,但為了讓你 的程序?qū)崿F(xiàn)類似的效果,你需要建立一個無限循環(huán):
while True:
下面的每一行都需要縮進(jìn)四個空格,這樣 MicroPython 就知道它們是循環(huán)的一部分:
led_red.value(1) utime.sleep(5) led_amber.value(1) utime.sleep(2) led_red.value(0) led_amber.value(0) led_green.value(1) utime.sleep(5) led_green.value(0) led_amber.value(1) utime.sleep(5) led_amber.value(0)
單擊 Run 并將程序保存到 Pico 中,文件名為 Traffic_Lights.py。觀察 LED,首先紅色的 LED 燈會亮起來,告訴交通停止;接下來,黃色 LED 將會亮起,警告司機(jī)信號燈即將改變;接下來,兩個 LED 都關(guān)閉,綠色 LED 亮起,讓車輛知道它可以通過;然后綠色的 LED 熄滅,黃色的 LED 亮起來,警告司機(jī)信號燈又要變了;最后,黃色 LED 熄滅,回路從開始重新啟動,紅色 LED 亮起。
這個顯示狀態(tài)會一直循環(huán)直到你按下停止按鈕,因?yàn)樗纬闪艘粋€無限循環(huán)。它是基于現(xiàn)實(shí) 世界中英國交通控制系統(tǒng)中使用的交通燈模式。
然而,真正的紅綠燈不僅僅是道路車輛的紅綠燈,它們也在那里保護(hù)行人,讓他們有機(jī)會安全 地穿過繁忙的道路。在英國,最常見的類型這些燈被稱為行人操作用戶友好型智能交叉口。行人要過馬路的時候手動按下按鈕,蜂鳴器發(fā)出提示讓行人過馬路。
要實(shí)現(xiàn)這個功能,需要兩樣?xùn)|西:一個按鈕開關(guān),這樣行人就可以要求車燈讓他們過馬路;一個蜂鳴器,讓行人知道什么時候輪到他們穿越馬路。將這些連接到你的面包板,如圖所示。
開關(guān)通過面包板連接 Pico 的 GP16 和 3V3 上,蜂鳴器則連接 GP12 和 GND 上。
如果你再次運(yùn)行你的程序,你會發(fā)現(xiàn)按鈕和蜂鳴器沒有什么反應(yīng)。那是因?yàn)槟氵€沒有告訴你的 程序如何使用它們。在 Thonny 中,請返回編輯控制 LED 的行,并在下面添加以下兩條新行:
button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN) buzzer = machine.Pin(12, machine.Pin.OUT)
程序?qū)⒁_ GP16 上的按鈕設(shè)置為輸入模式,控制蜂鳴器引腳的引腳 GP12 上的設(shè)置為輸出。請記住,Pico 有內(nèi)置的可編程電阻的輸入,我們?yōu)楸緯械捻?xiàng)目設(shè)置為下拉模式。這 意味著引腳的電壓被拉到 0V(它的邏輯電平是0),除非它連接到 3.3V 電源(在這種情況下,它 的邏輯電平將是1,直到斷開)。
接下來,你需要一種方法來讓程序不斷監(jiān)控按鈕的價值。以前,你的所有程序都通過一系列說 明一步一步地工作,一次只做一件事。你的紅綠燈程序同樣,當(dāng)它運(yùn)行時,MicroPython 會一步一步地瀏覽你的指示,打開和關(guān)閉 LED。
對于一套基本的紅綠燈,這就足夠了。不過,對于設(shè)置了行人手動按鈕的交叉口,你的程序需要能夠記錄按鈕是否以不中斷紅綠燈的方式按下。要做到這一點(diǎn),你需要使用到一個新的庫:_thread。返回到程序的開始部分,在那里你導(dǎo)入 machine 和 utime 庫,并導(dǎo)入 _thread 庫:
import _thread
線程實(shí)際上是一個小的、部分獨(dú)立的程序。你可以將前面編寫的控制燈的循環(huán)視為程序的主線程,并使用 _thread 庫創(chuàng)建一個同時運(yùn)行的額外線程。
可視化線程的簡單方法是將每個線程都想象成廚房里的獨(dú)立人員,當(dāng)廚師準(zhǔn)備主菜時,其 他人正在制作醬汁。目前,你的程序只有一個線程:控制紅綠燈的線程。然而,為 Pico 提供算力的 RP2040 微控制器有兩個處理核心,意思是,就像廚房中的廚師和副廚師一樣,你可以同時運(yùn)行兩個線程來完成更多的工作。
在制作另一個線程之前,你需要一種方法讓新線程將信息傳回主線程,并且你可以使用全局 變量做到這一點(diǎn)。在此之前,你一直在處理的變量稱為局部變量,并且僅在程序的一個部分工作:一個全局變量在任何地方都有效,這意味著一個線程可以更改值,另一個線程可以檢查它是否已更改。
首先,你需要創(chuàng)建一個全局變量。在 buzzer = 這行下面,添加以下內(nèi)容:
global button_pressed button_pressed = False
這將把 button_pressed 設(shè)置為一個全局變量,并給它一個默認(rèn)值 False,意思是當(dāng)程序啟動時,按鈕還沒有被按下。下一步是定義線程,通過添加下面的行讓程序更具有可讀性:
def button_reader_thread(): global button_pressed while True: if button.value() == 1: button_pressed = True
添加的第一行定義了線程,并給它一個名稱來述它的用途:讀取按鈕輸入的線程。就像在編寫 循環(huán)時,MicroPython 需要將線程中包含的所有內(nèi)容縮進(jìn) 4 個空格,這樣它就知道線程從哪里開始和結(jié)束。
下一行讓 MicroPython 知道你將更改全局 button_pressed 變量的值。如果你只想檢查該值,則不需要這一行—但是沒有這一行,你就不能對變量進(jìn)行任何更改。
接下來,你設(shè)置了一個新的循環(huán),這意味著接下來需要一個新的四空格縮進(jìn),總共是八個縮進(jìn),這樣 MicroPython 就知道循環(huán)是線程的一部分,下面的代碼也是循環(huán)的一部分。這個嵌套代碼在多個水平 MicroPython 縮進(jìn)是很常見的。
下一行是一個條件語句,用于檢查按鈕的值是否為 1。因?yàn)?Pico 使用一個內(nèi)部下拉電 阻,當(dāng)按鈕沒有被按下時,讀取的值是 0,表示在條件下的代碼永遠(yuǎn)不會運(yùn)行。只有當(dāng)按鈕被按下時,線程的最后一行才會運(yùn)行:這一行將 button_pressed 變量設(shè)置為 True,讓程序的其余部分知道按鈕已被按下。
你可能注意到,在線程中沒有任何東西可以將 button_pressed 變量重置回當(dāng)按鈕被按下后 釋放時為 False。這是有原因的,雖然你可以在交通燈周期的任何時候按下過馬路的按鈕,但它只有在交通燈變紅、你可以安全過馬路時才會生效。你的新線程需要做的就是在按鈕被按下時改變變量;當(dāng)行人安全過馬路時,主線程會將其重置為 False。
定義一個線程并不會使它自動運(yùn)行,可以在程序中的任何地方啟動一個線程,并且需要明確地告訴 _thread 庫何時啟動線程。與運(yùn)行普通代碼不同,運(yùn)行線程不會停止程序的其余部分,當(dāng)線程啟動時,MicroPython 將繼續(xù)運(yùn)行程序的下一行。
在你的線程下面新建一行,刪除所有 Thonny 為你自動添加的縮進(jìn),如下所示:
_thread.start_new_thread(button_reader_thread, ())
這告訴 _thread 庫啟動前面定義的線程。此時,線程將開始運(yùn)行,并迅速進(jìn)入循環(huán):每秒檢查按鈕數(shù)千次,看它是否被按下。與此同時,主線程將繼續(xù)執(zhí)行程序的主要部分。
現(xiàn)在點(diǎn)擊 Run 按鈕。你會看到交通燈和以前一樣,沒有延遲或停頓。但是,如果你按下按鈕,什么也不會發(fā)生,因?yàn)槟氵€沒有添加代碼來實(shí)際響應(yīng)按鈕。
轉(zhuǎn)到你的主循環(huán)的開始,在 True: 的正下方,添加以下代碼:記住要注意嵌套縮進(jìn):
if button_pressed == True: led_red.value(1) for i in range(10): buzzer.value(1) utime.sleep(0.2) buzzer.value(0) utime.sleep(0.2) global button_pressed button_pressed = False
這段代碼檢查 button_pressed 全局變量,以查看自上次循環(huán)運(yùn)行以來,按鈕開關(guān)是否在任何時候被按下。如果有,就像你之前的按鈕閱讀線程報(bào)告的那樣,它開始運(yùn)行一段代碼,首先打開紅色 LED 燈來阻止交通,然后蜂鳴器響十次——讓行人知道該過馬路了。
最后,最后兩行將 button_pressed 變量重置為 False,因此下次循環(huán)運(yùn)行時,除非再次按下按鈕,否則不會觸發(fā)行人過馬路代碼。你將看到,在條件語句中不需要使用 global button_pressed 來檢查變量的狀態(tài);只有當(dāng)你想要更改變量并使該更改影響程序的其他部 分時,才需要使用它。
最終程序如下:
import machine import utime import _thread led_red = machine.Pin(15, machine.Pin.OUT) led_amber = machine.Pin(14, machine.Pin.OUT) led_green = machine.Pin(13, machine.Pin.OUT) button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN) buzzer = machine.Pin(12, machine.Pin.OUT) global button_pressed button_pressed = False def button_reader_thread(): global button_pressed while True: if button.value() == 1: button_pressed = True _thread.start_new_thread(button_reader_thread, ()) while True: if button_pressed == True: led_red.value(1) for i in range(10): buzzer.value(1) utime.sleep(0.2) buzzer.value(0) utime.sleep(0.2) global button_pressed button_pressed = False led_red.value(1) utime.sleep(5) led_amber.value(1) utime.sleep(2) led_red.value(0) led_amber.value(0) led_green.value(1) utime.sleep(5) led_green.value(0) led_amber.value(1) utime.sleep(5) led_amber.value(0)
點(diǎn)擊 Run 圖標(biāo)。首先,程序?qū)⒄_\(yùn)行,交通燈將按照通常的模式亮和關(guān)。按下按鈕開關(guān):如果程序當(dāng)前在它的循環(huán)過程中,在到達(dá)終點(diǎn)并再次循環(huán)之前不會發(fā)生任何事情,這時紅燈會變亮,蜂鳴器會提示你可以在道路上安全通過了。
過馬路的時候按下按鈕,紅燈保持點(diǎn)亮,蜂鳴器響 10 次。之后蜂鳴器不再響了,紅燈仍然亮著,所以任何在蜂鳴器發(fā)出時開始過馬路的人 都有時間在車輛允許通行之前到達(dá)另一邊。
恭喜你!你已經(jīng)建立了你自己的海雀交叉口!
-
微控制器
+關(guān)注
關(guān)注
48文章
7394瀏覽量
150624 -
mcu
+關(guān)注
關(guān)注
146文章
16796瀏覽量
349325 -
交通燈
+關(guān)注
關(guān)注
13文章
323瀏覽量
39678 -
樹莓派
+關(guān)注
關(guān)注
116文章
1683瀏覽量
105389 -
控制程序
+關(guān)注
關(guān)注
1文章
49瀏覽量
9001
原文標(biāo)題:樹莓派 Pico 實(shí)現(xiàn)交通燈控制程序
文章出處:【微信號:趣無盡,微信公眾號:趣無盡】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論