哇奧,今天才發(fā)現(xiàn)上一次建造的紅綠燈居然不對,綠燈一般在下方,當(dāng)紅燈變綠燈時(shí)黃燈閃爍,我做的是綠燈變紅燈時(shí)黃燈閃爍!。這在我們開發(fā)時(shí)也會(huì)碰到,就像找bug一樣,對于發(fā)現(xiàn)的問題要及時(shí)修正。在修正問題之前,我們還是先看看如何讓紅綠燈更快的響應(yīng)按鈕操作,然后修正紅綠燈問題。
要想更快的響應(yīng)按鈕,則需要找出原因,上一講提到因?yàn)槌绦蜻\(yùn)行時(shí)沒有及時(shí)檢測按鈕是不是被按下了,那么我們第一反應(yīng)可能是在程序中加上更多的檢測語句,但這樣程序?qū)⒆兊锰貏e臃腫,也不容易被別人理解。其實(shí),計(jì)算機(jī)設(shè)計(jì)者早就考慮到了這個(gè)問題,他們利用一個(gè)叫做“中斷”的概念來對需要及時(shí)響應(yīng)的事情進(jìn)行處理。
什么是中斷
中斷是指計(jì)算機(jī)運(yùn)行過程中,出現(xiàn)某些需要及時(shí)處理時(shí),計(jì)算機(jī)能自動(dòng)暫停正在運(yùn)行的程序并轉(zhuǎn)入處理新情況的程序,處理完畢后又返回原被暫停的程序繼續(xù)運(yùn)行。中斷發(fā)生時(shí)運(yùn)行的程序叫做中斷程序。
在我們的紅綠燈程序中,當(dāng)按鈕被按下時(shí),我們希望計(jì)算機(jī)可以把它作為一個(gè)中斷,然后運(yùn)行中斷程序,及時(shí)修改運(yùn)行狀態(tài)。
研究gpiozero的文檔,我們發(fā)現(xiàn)Button類有一個(gè)when_pressed的方法,說明如下
意思是說當(dāng)按鈕按下時(shí)將調(diào)用一個(gè)函數(shù)(function)。那么什么是函數(shù)呢?
函數(shù)是什么
函數(shù)是可以完成某些任務(wù)的代碼塊,而且這些代碼塊可以被重復(fù)使用,就像我們玩具里的積木塊一樣。在python中,用def來定義或者說創(chuàng)建函數(shù),其語法如下
def 函數(shù)名(參數(shù)): #注意最后的冒號
函數(shù)代碼(完成工作需要的代碼)
return 返回值 #不是必須的,當(dāng)需要向調(diào)用函數(shù)的程序返回?cái)?shù)值或?qū)ο髸r(shí)使用
函數(shù)是編程語言非常重要的一部分內(nèi)容,參數(shù)有形參和實(shí)參,參數(shù)也可以是多個(gè),返回值可以是各種數(shù)據(jù)類型,有了函數(shù)后,變量也就分為全局 變量和局部變量了,這些內(nèi)容我們會(huì)逐步涉及到。今天我們先從最簡單的無參數(shù)函數(shù)開始,顧名思義,這樣的函數(shù)沒有參數(shù)。
創(chuàng)建參數(shù)
回過頭來看我們的紅綠燈程序,只閃爍黃燈還是正常工作取決于其中的一個(gè)變量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: #當(dāng)kaiguan變量為False時(shí),黃燈閃爍
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
else: #當(dāng)kaiguan變量為True時(shí)
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)
所以,利用中斷,我們的需要在按鈕按下時(shí)及時(shí)改變kaiguan這個(gè)變量的數(shù)值,然后在程序中及時(shí)判斷這個(gè)值是否已經(jīng)變化了,從而作出正確的邏輯控制。
現(xiàn)在我們創(chuàng)建一個(gè)叫做changeKaiguan的函數(shù):
def changeKaiguan(): #創(chuàng)建無參數(shù)函數(shù):修改kaiguan變量,從而控制紅綠燈
print("Pressed")
global kaiguan #kaiguan是全局變量,在主程序中已經(jīng)聲明
kaiguan = bool(1 - kaiguan) #取反操作
print(kaiguan) #打印kaiguan的數(shù)值,True或False
因?yàn)閗aiguan變量是在主函數(shù)聲明的,函數(shù)如果要使用它,需要用global關(guān)鍵字,表示它是一個(gè)全局變量 。
當(dāng)控制按鈕按下時(shí),調(diào)用changeKaiguan函數(shù),通過如下代碼實(shí)現(xiàn):
control.when_pressed = changeKaiguan #按下按鈕時(shí)調(diào)用changeKaiguan函數(shù)
注意: 這一個(gè)語句應(yīng)該在changeKaiguan函數(shù)創(chuàng)建之后才行,否則就會(huì)報(bào)變量沒有定義的錯(cuò)誤。
驗(yàn)證中斷程序
通過上面的代碼,我們創(chuàng)建了一個(gè)中斷函數(shù),當(dāng)按鈕按下時(shí),每次都調(diào)用changeKaiguan函數(shù)。讓我們來測試一下,完整代碼如下:
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(): #創(chuàng)建無參數(shù)函數(shù):修改kaiguan變量,從而控制紅綠燈
print("Pressed")
global kaiguan #kaiguan是全局變量,在主程序中已經(jīng)聲明
kaiguan = bool(1 - kaiguan) #取反操作
print(kaiguan) #打印kaiguan的數(shù)值,True或False
control.when_pressed = changeKaiguan #按鈕按下時(shí)調(diào)用changeKaiguan函數(shù)
while True:
if kaiguan == False: #當(dāng)kaiguan變量為False時(shí),黃燈閃爍
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
else: #當(dāng)kaiguan變量為True時(shí),
red.on()
sleep(3) #綠燈亮3秒
red.off()
yellow.on() #黃燈亮1秒
sleep(1)
yellow.off()
green.on() #紅燈亮3秒
sleep(3)
green.off()
運(yùn)行上面的程序,可以發(fā)現(xiàn),無論程序運(yùn)行在那個(gè)階段,當(dāng)按下按鈕時(shí),都可以馬上在Shell界面看到打印“Pressed"以及最新的kaiguan參數(shù)數(shù)值。
我們發(fā)現(xiàn)每次按鈕按下,都馬上進(jìn)入了中斷程序changeKaiguan,在程序中修改了kaiguan變量的值并打印了出來,當(dāng)前程序運(yùn)行在sleep還是其他語句都沒有影響。
進(jìn)階版紅綠燈程序
現(xiàn)在,是時(shí)候完成我們的進(jìn)階版程序,讓紅綠燈可以在按鈕按下后及時(shí)切換工作狀態(tài)。在此之前,我們需要調(diào)整紅綠燈連接線,把紅燈和綠燈互換位置,同時(shí)修改程序。最新的電路圖:
電路實(shí)物照片:
要修改程序,需要考慮在什么時(shí)候探測kaiguan變量值,然后作出邏輯調(diào)整,原程序紅綠燈正常工作時(shí)不能及時(shí)探測kaiguan變量才造成對按鈕的反應(yīng)遲鈍,所以需要修改這部分代碼,為了保證控制操作的完整性,我們不能在某個(gè)燈還亮著時(shí)進(jìn)行切換,需要在燈滅后進(jìn)行,所以修改如下:
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: #當(dāng)kaiguan變量為False時(shí),黃燈閃爍
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
else: #當(dāng)kaiguan變量為True時(shí),
red.on()
sleep(3) #綠燈亮3秒
red.off()
if kaiguan == False: #判斷kaiguan是否已經(jīng)變?yōu)镕alse,如果是,則跳出當(dāng)前操作,繼續(xù)下一個(gè)循環(huán)
continue #跳過下面的代碼,開始下一個(gè)循環(huán)
yellow.on() #黃燈亮1秒
sleep(1)
yellow.off()
if kaiguan == False: #判斷kaiguan是否已經(jīng)變?yōu)镕alse,如果是,則跳出當(dāng)前操作,繼續(xù)下一個(gè)循環(huán)
continue
green.on() #紅燈亮3秒
sleep(3)
green.off()
運(yùn)行程序,看看是不是按我們期望的正常運(yùn)作了呢?
是的,現(xiàn)在只要我們按下按鈕,程序都可以及時(shí)切換,即使在紅燈或綠燈亮?xí)r按下按鈕,當(dāng)燈滅時(shí)也會(huì)判斷出kaiguan值變?yōu)镕alse,從而中止當(dāng)前循環(huán),進(jìn)入下一個(gè)循環(huán)中。如此,進(jìn)階版的紅綠燈大功告成!
-
計(jì)算機(jī)
+關(guān)注
關(guān)注
19文章
7295瀏覽量
87532 -
中斷
+關(guān)注
關(guān)注
5文章
894瀏覽量
41322 -
python
+關(guān)注
關(guān)注
54文章
4759瀏覽量
84294 -
紅綠燈
+關(guān)注
關(guān)注
2文章
34瀏覽量
11933 -
樹莓派
+關(guān)注
關(guān)注
116文章
1684瀏覽量
105397
發(fā)布評論請先 登錄
相關(guān)推薦
評論