哇奧,今天才發現上一次建造的紅綠燈居然不對,綠燈一般在下方,當紅燈變綠燈時黃燈閃爍,我做的是綠燈變紅燈時黃燈閃爍!。這在我們開發時也會碰到,就像找bug一樣,對于發現的問題要及時修正。在修正問題之前,我們還是先看看如何讓紅綠燈更快的響應按鈕操作,然后修正紅綠燈問題。
要想更快的響應按鈕,則需要找出原因,上一講提到因為程序運行時沒有及時檢測按鈕是不是被按下了,那么我們第一反應可能是在程序中加上更多的檢測語句,但這樣程序將變得特別臃腫,也不容易被別人理解。其實,計算機設計者早就考慮到了這個問題,他們利用一個叫做“中斷”的概念來對需要及時響應的事情進行處理。
什么是中斷
中斷是指計算機運行過程中,出現某些需要及時處理時,計算機能自動暫停正在運行的程序并轉入處理新情況的程序,處理完畢后又返回原被暫停的程序繼續運行。中斷發生時運行的程序叫做中斷程序。
在我們的紅綠燈程序中,當按鈕被按下時,我們希望計算機可以把它作為一個中斷,然后運行中斷程序,及時修改運行狀態。
研究gpiozero的文檔,我們發現Button類有一個when_pressed的方法,說明如下
意思是說當按鈕按下時將調用一個函數(function)。那么什么是函數呢?
函數是什么
函數是可以完成某些任務的代碼塊,而且這些代碼塊可以被重復使用,就像我們玩具里的積木塊一樣。在python中,用def來定義或者說創建函數,其語法如下
def 函數名(參數): #注意最后的冒號
函數代碼(完成工作需要的代碼)
return 返回值 #不是必須的,當需要向調用函數的程序返回數值或對象時使用
函數是編程語言非常重要的一部分內容,參數有形參和實參,參數也可以是多個,返回值可以是各種數據類型,有了函數后,變量也就分為全局 變量和局部變量了,這些內容我們會逐步涉及到。今天我們先從最簡單的無參數函數開始,顧名思義,這樣的函數沒有參數。
創建參數
回過頭來看我們的紅綠燈程序,只閃爍黃燈還是正常工作取決于其中的一個變量kaiguan。
from gpiozero import LED,Button
from time import sleep
kaiguan = False
red = LED(26) #紅燈鏈接了GPIO26
yellow= LED(5) #黃燈鏈接了GPIO5
green = LED(22) #綠燈連接了GPIO22
control = Button(17) #按鈕連接了GPIO17
while True:
if kaiguan == False: #當kaiguan變量為False時,黃燈閃爍
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
else: #當kaiguan變量為True時
green.on()
sleep(3) #綠燈亮3秒
green.off()
yellow.on() #黃燈亮1秒
sleep(1)
yellow.off()
red.on() #紅燈亮3秒
sleep(3)
red.off()
if control.is_pressed: ##判斷按鈕是否被按下
print("Pressed")
kaiguan = bool(1-kaiguan)
所以,利用中斷,我們的需要在按鈕按下時及時改變kaiguan這個變量的數值,然后在程序中及時判斷這個值是否已經變化了,從而作出正確的邏輯控制。
現在我們創建一個叫做changeKaiguan的函數:
def changeKaiguan(): #創建無參數函數:修改kaiguan變量,從而控制紅綠燈
print("Pressed")
global kaiguan #kaiguan是全局變量,在主程序中已經聲明
kaiguan = bool(1 - kaiguan) #取反操作
print(kaiguan) #打印kaiguan的數值,True或False
因為kaiguan變量是在主函數聲明的,函數如果要使用它,需要用global關鍵字,表示它是一個全局變量 。
當控制按鈕按下時,調用changeKaiguan函數,通過如下代碼實現:
control.when_pressed = changeKaiguan #按下按鈕時調用changeKaiguan函數
注意: 這一個語句應該在changeKaiguan函數創建之后才行,否則就會報變量沒有定義的錯誤。
驗證中斷程序
通過上面的代碼,我們創建了一個中斷函數,當按鈕按下時,每次都調用changeKaiguan函數。讓我們來測試一下,完整代碼如下:
from gpiozero import LED,Button
from time import sleep
kaiguan = False
green = LED(26) #green燈鏈接了GPIO26
yellow= LED(5) #黃燈鏈接了GPIO5
red = LED(22) #red燈連接了GPIO22
control = Button(17) #按鈕連接了GPIO17
def changeKaiguan(): #創建無參數函數:修改kaiguan變量,從而控制紅綠燈
print("Pressed")
global kaiguan #kaiguan是全局變量,在主程序中已經聲明
kaiguan = bool(1 - kaiguan) #取反操作
print(kaiguan) #打印kaiguan的數值,True或False
control.when_pressed = changeKaiguan #按鈕按下時調用changeKaiguan函數
while True:
if kaiguan == False: #當kaiguan變量為False時,黃燈閃爍
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
else: #當kaiguan變量為True時,
red.on()
sleep(3) #綠燈亮3秒
red.off()
yellow.on() #黃燈亮1秒
sleep(1)
yellow.off()
green.on() #紅燈亮3秒
sleep(3)
green.off()
運行上面的程序,可以發現,無論程序運行在那個階段,當按下按鈕時,都可以馬上在Shell界面看到打印“Pressed"以及最新的kaiguan參數數值。
我們發現每次按鈕按下,都馬上進入了中斷程序changeKaiguan,在程序中修改了kaiguan變量的值并打印了出來,當前程序運行在sleep還是其他語句都沒有影響。
進階版紅綠燈程序
現在,是時候完成我們的進階版程序,讓紅綠燈可以在按鈕按下后及時切換工作狀態。在此之前,我們需要調整紅綠燈連接線,把紅燈和綠燈互換位置,同時修改程序。最新的電路圖:
電路實物照片:
要修改程序,需要考慮在什么時候探測kaiguan變量值,然后作出邏輯調整,原程序紅綠燈正常工作時不能及時探測kaiguan變量才造成對按鈕的反應遲鈍,所以需要修改這部分代碼,為了保證控制操作的完整性,我們不能在某個燈還亮著時進行切換,需要在燈滅后進行,所以修改如下:
from gpiozero import LED,Button
from time import sleep
kaiguan = False
green = LED(26) #green燈鏈接了GPIO26
yellow= LED(5) #黃燈鏈接了GPIO5
red = LED(22) #red燈連接了GPIO22
control = Button(17) #按鈕連接了GPIO17
def changeKaiguan():
print("Pressed")
global kaiguan
kaiguan = bool(1 - kaiguan)
print(kaiguan)
control.when_pressed = changeKaiguan
while True:
if kaiguan == False: #當kaiguan變量為False時,黃燈閃爍
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
else: #當kaiguan變量為True時,
red.on()
sleep(3) #綠燈亮3秒
red.off()
if kaiguan == False: #判斷kaiguan是否已經變為False,如果是,則跳出當前操作,繼續下一個循環
continue #跳過下面的代碼,開始下一個循環
yellow.on() #黃燈亮1秒
sleep(1)
yellow.off()
if kaiguan == False: #判斷kaiguan是否已經變為False,如果是,則跳出當前操作,繼續下一個循環
continue
green.on() #紅燈亮3秒
sleep(3)
green.off()
運行程序,看看是不是按我們期望的正常運作了呢?
是的,現在只要我們按下按鈕,程序都可以及時切換,即使在紅燈或綠燈亮時按下按鈕,當燈滅時也會判斷出kaiguan值變為False,從而中止當前循環,進入下一個循環中。如此,進階版的紅綠燈大功告成!
-
計算機
+關注
關注
19文章
7430瀏覽量
87733 -
中斷
+關注
關注
5文章
895瀏覽量
41401 -
python
+關注
關注
56文章
4783瀏覽量
84473 -
紅綠燈
+關注
關注
2文章
34瀏覽量
11946 -
樹莓派
+關注
關注
116文章
1699瀏覽量
105537
發布評論請先 登錄
相關推薦
評論