樹莓派使用Python檢測連續脈衝

樹莓派使用Python檢測連續脈衝

1、應用場景

使用樹莓派作爲智能小車主控制器時,需要對輪子進行測速,採用的是馬達+霍爾傳感器的形式,小車運動時霍爾傳感器會輸出連續脈衝信號,通過轉換就可以得到小車的速度,前行的距離等等。本博文用於流量傳感器檢測連續脈衝場景,通過轉換可以得到流量大小。

2、檢測方式

使用到了樹莓派GPIO的輸入(Input)功能,可分爲以下幾種情況(需要先安裝RPi.GPIO)。

# Python 2.X
pip install RPi.GPIO
# Python 3.X
pip3 install RPi.GPIO

上拉/下拉電阻

當GPIO沒有連接任何元件時,其狀態是不可控的,爲解決這一問題,需要使用到上拉和下拉電阻,用於設定輸入的默認值。使用硬件方式,通常需要將一個 10K 的電阻連接在輸入通道與 3.3V(上拉)或 0V(下拉)之間。而樹莓派可以通過軟件實現GPIO的上拉和下拉:

GPIO.setup(channel, GPIO.IN, pull_up_down``=``GPIO.PUD_UP)

或者

GPIO.setup(channel, GPIO.IN, pull_up_down``=``GPIO.PUD_DOWN)

輪詢(Polling)

可在某一時刻獲取GPIO輸入值:

if GPIO.input(channel):
    print('Input was HIGH')
else:
    print('Input was LOW')

也可以循環判斷:

while GPIO.input(channel) == GPIO.LOW:
    time.sleep(0.01)# 爲 CPU 留出 10 毫秒,供其處理其它事物

中斷和邊緣檢測

可使用中斷或者邊緣檢測監測GPIO狀態,可用到以下兩個函數:

  • wait_for_edge() 函數
  • event_detected() 函數

wait_for_edge()

用於在檢測到邊緣之前阻止程序的運行。換句話說,上面的示例中,等待按鈕被按下的語句可以改寫爲:

GPIO.wait_for_edge(channel, GPIO.RISING)
  • GPIO.RISING:上升沿觸發
  • GPIO.FALLING:下降沿觸發
  • GPIO.BOTH:都觸發

event_detected()

設計用於循環中有其它東西時使用,但不同於輪詢的是,它不會錯過當 CPU 忙於處理其它事物時輸入狀態的改變。這在類似使用 Pygame 或 PyQt 時主循環實時監聽和響應 GUI 的事件是很有用的。

GPIO.add_event_detect(channel, GPIO.RISING) # 在通道上添加上升臨界值檢測
do_something()
if GPIO.event_detected(channel):
    print('Button pressed')

觸發方式也有三種,同上。

線程回調

RPi.GPIO 在第二條線程中執行回調函數。這意味着回調函數可以同您的主程序同時運行,並且可以立即對邊緣進行響應。例如:

def my_callback(channel):
    print('這是一個邊緣事件回調函數!')
    print('在通道 %s 上進行邊緣檢測'%channel)
    print('該程序與您的主程序運行在不同的進程中')
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) # 在通道上添加上升臨界值檢測``... 其它程序代碼 ...

如果您需要多個回調函數:

def my_callback_one(channel):
    print('回調 1')
def my_callback_two(channel):
    print('回調 2')
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)

【注意】在該示例中,回調函數爲順序運行而不是同時運行。這是因爲當前只有一個進程供回調使用,而回調的運行順序是依據它們被定義的順序。

開關防抖

按鍵按下時,回調操作調用不止一次,這種現象稱爲“開關抖動”,有兩種方式可以解決:

  • 將一個0.1uf電容連接到開關上
  • 軟件去抖

軟件去抖可以在回調函數中添加bouncetime參數:

# 在通道上添加上升臨界值檢測,忽略由於開關抖動引起的小於 200ms 的邊緣操作
GPIO.add_event_detect(channel, GPIO.RISING, callback = my_callback, bouncetime = 200)

或者

GPIO.add_event_callback(channel, my_callback, bouncetime=200)
remove_event_detect()

由於某種原因,您不希望您的程序檢測邊緣事件,您可以將它停止:

GPIO.remove_event_detect(channel)

3、檢測代碼

#霍爾脈衝讀取函數
GPIO.setup(18, GPIO.IN,pull_up_down=GPIO.PUD_UP)   #通過18號引腳讀取左輪脈衝數據
GPIO.setup(35, GPIO.IN,pull_up_down=GPIO.PUD_UP)   #通過35號引腳讀取右輪脈衝數據
counter=0      #左輪脈衝初值
counter1=0     #右輪脈衝初值
def my_callback(channel):          #邊緣檢測回調函數,詳情在參見鏈接中
    global counter                 #設置爲全局變量
    if GPIO.event_detected(18):        #檢測到一個脈衝則脈衝數加1
        counter=counter+1
#這裏的channel和channel1無須賦確定值,不能不寫。
def my_callback1(channel1):            
    global counter1
    if GPIO.event_detected(35):
        counter1=counter1+1
GPIO.add_event_detect(18,GPIO.RISING,callback=my_callback) #在引腳上添加上升臨界值檢測再回調
GPIO.add_event_detect(35,GPIO.RISING,callback=my_callback1)

參考連接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章