在物聯網時代,用得最多的是什麼?答案無疑是傳感器!相信大家都入手過不少傳感器,DHT11作為一款比較常用的溫濕度傳感器,估計沒人會說「沒聽過」或者「不會用」吧?最近我帶兒子玩樹莓派的時候,發現了一個問題,那就是網上使用樹莓派讀取DHT11的python代碼同質化太嚴重。而且說是給樹莓派使用的,但實際上,每段代碼只適合少許型號的樹莓派使用,例如下面這段代碼:
這段代碼在樹莓派3b上工作的不錯,但在樹莓派4b上就完全不能用了,讀出的結果為255(全1)。對照Datasheet,我們很容易就能分析出原因。但這裡就不大段抄文了,簡單說一下原理,在讀取數據的時候,如果有一個較長時間的持續高電平,讀取此位為1,否則就是0,如下圖所示:
根據手冊來說:「0」的高電位持續時間是26~28us,「1」的高電位持續時間是70us。在上面的代碼中,是以循環是否超過8次作為該位0、1的區分,這是樹莓派3b中比較適合的數字了(相信也是反覆試驗出來的)。但是,因為不同樹莓派的SoC主頻不同,顯然如果換一款樹莓派(比如樹莓派4b)這個數值肯定是需要根據實際修改的,將其循環次數k記錄下來:[7, 8, 8, 25, 25, 8, 8, 9, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 26, 26, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 24, 24, 8, 8, 8, 8]從數值上來看,7、8、9應該是0;24、25、26應該是1,那麼直接把剛才的代碼第25行改成if k<15:再嘗試。根據傳感器的要求,每次讀取時間間隔超過1s,多次讀取,發現大多數時候讀取的結果都是正確的,但也有錯得比較離譜的情況,比如下面這種情況:
其實原因很簡單,樹莓派的SoC工作頻率並不固定,因此循環周期也是不同的。以樹莓派4b為例,它的頻率可以在600MHz~1500MHz間變化。
如果不用循環,那麼直接讀取兩次時間差值是否可行呢?經過驗證,這是可以的,只要使用time.time.time_ns()函數就行。不過,這裡有個小問題,那就是python的效率比較低,在樹莓派上,即使原始值是「0」(只有不到30us),經過兩次調用這個函數並且做差值運算以後,花費的時間依然超過了70us。當然,這並不是什麼大問題,我們直接嘗試將兩次調用的時間相減(實測大概是50us),作為基礎數值加到30us中,因此將上述循環計數改成時間計數:
這樣在一定程度上,可以抵禦樹莓派主頻自動變化造成讀數錯誤的風險。實測,依然有一定出錯概率,因此最合適的方案就是:多讀幾次,把校驗錯誤和明顯不符合常識的數值(比如濕度大於100)丟棄,這樣結果相對準確一些。代碼很簡單,這裡就不獻醜了,僅提出一個思路,請大家自行展開嘗試。另外,如果有需要查看原圖和代碼的小夥伴,請點擊底部「閱讀原文」進行下載。21ic獨家「修煉寶典」|電子必看公眾號|電子「設計錦囊」
鑽石舞台 發表在 痞客邦 留言(0) 人氣()