這篇文章將為大家詳細講解有關(guān)SensorTile中如何使用MicroPython,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
為柴桑等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務,及柴桑網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務為成都網(wǎng)站設(shè)計、成都網(wǎng)站制作、柴桑網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!
SensotTile簡介
SensorTile核心板非常緊湊小巧,看起來就是一個可穿戴的原型(智能手表),因此它配置的傳感器也是和運動相關(guān)的。SensorTile核心板上有4個傳感器,它們分別是:
LPS22HB,氣壓+溫度傳感器
LSM6DSM,三軸加速度+三軸角速度傳感器
LSM303AGR,三軸角速度+三軸磁場傳感器
MP34DT04,MEMS麥克風傳感器
我們先從最簡單的LPS22HB開始,逐步介紹傳感器的使用和移植方法。而MP34DT04傳感器這次沒有使用到,它的接口也和其他傳感器不同,所以暫時先不看。
LPS22HB氣壓傳感器
硬件接口
LPS22HB的原理圖如上,從上面我們可以看到,傳感器使用了SPI連接方式,但是只用了CS、SCL/SPC、SDA/SDI/SDO這幾個腳,SDO腳沒有使用,說明它沒有使用標準的SPI接口方式。此外,還可以看到INT信號也沒有連接,所以也就不能使用INT模式了。通常在INT模式下,可以預先設(shè)置一個門限參數(shù),當傳感器的輸出超過這個門限時,就會自動產(chǎn)生一個INT信號,用來喚醒MCU,然后讀取并處理參數(shù),這有助于簡化編程,降低系統(tǒng)功耗。
從傳感器的用戶手冊中可以看到,傳感器支持SPI/I2C兩種接口。這兩種接口方式是通過CS腳進行切換的,當CS為低電平時是SPI方式,CS是高電平時是I2C方式。SensorTile在硬件設(shè)計時,使用了半雙工的SPI接口(又叫3-wire模式),這個模式下主機只使用MOSI做數(shù)據(jù)線,而從機使用MISO。它的好處在于可以節(jié)約一個數(shù)據(jù)線,缺點就是犧牲了速度。
因為MicroPython目前不支持半雙工的SPI接口方式(硬件SPI和軟件SPI都不支持這個方式),因此要用SPI方式驅(qū)動傳感器就只能自己通過軟件模擬這種SPI方式,這不但增加了軟件的復雜性,同時速度也會比較慢,所以我采用了I2C接口方式。因為SPI_SDA(PB15)和SPI_CLK(PB13)引腳并不是硬件I2C接口,所以需要用軟件I2C方式。好在micropython底層已經(jīng)支持軟件I2C,使用方法和硬件I2C一樣,速度也不慢。
這里先介紹一下軟件I2C。為了使用軟件I2C,我們需要使用到micropython的machine庫,而不能使用pyb庫。大家可能也注意到了,CC3200、ESP8266、STM32等分支在硬件底層函數(shù)接口上有很多不同,這給我們編程和程序移植帶來很多不便。從v1.8版開始,micropython開始增強了machine庫的功能,這樣有助于統(tǒng)一底層接口。軟件I2C的使用方法如下:
import machine
i2c = machine.I2C(-1, sda=machine.Pin('PB15'), scl=machine.Pin('PB13'))其中-1就代表使用了軟件I2C,sda和scl就是使用的GPIO,可以使用任何GPIO,在SensorTile上就必須使用PB15和PB13。
直接這樣定義后,大家會發(fā)現(xiàn)I2C還是不能工作,這是因為在SensorTile內(nèi)部沒有設(shè)置I2C的上拉電阻,這樣I2C總線的狀態(tài)無法確定,所以我們還需要使能GPIO內(nèi)部的上拉電阻。注意這個步驟需要放在I2C初始化之后,因為在I2C初始化的時候,會重新設(shè)置GPIO狀態(tài)和參數(shù)。直接在I2C定義中的sda=machine.Pin('PB15', pull=Pin.PULL_UP)加入上拉電阻定義也是不能工作的,因為在設(shè)置I2C時會忽略這個參數(shù)。在I2C定義后,再加入下面的定義,I2C就可以正常工作了,如果這時使用i2c.scan()函數(shù),就可以搜索到4個設(shè)備。
sda=machine.Pin('PB15', Pin.OPEN_DRAIN, pull=Pin.PULL_UP)
scl=machine.Pin('PB13', Pin.OPEN_DRAIN, pull=Pin.PULL_UP)
傳感器寄存器
ST公司為SensorTile kit提供了多個例程,例程中包含了傳感器的底層驅(qū)動函數(shù)。如果使用C++編程,可以使用這些驅(qū)動函數(shù)。而我們要使用micropython進行編程,所以無法直接使用ST的底層函數(shù),需要自己對寄存器進行操作(其實ST的底層驅(qū)動函數(shù)也是對這些寄存器進行操作,只是它已經(jīng)封裝好了,不用再看寄存器說明了)。為了使用LPS22HB,需要對傳感器的寄存器有初步的了解。
上圖是LPS22HB的寄存器列表,它的寄存器不是太多,除去保留的寄存器(Reserved)外,一共大約有二十幾個。每個寄存器都有一個地址,寄存器輸出是8位的,大部分寄存器可以讀寫(RW),少量寄存器是只讀的(R)。如果按照功能進行劃分,傳感器的寄存器大致可以分為下面幾類:
功能設(shè)置
傳感器狀態(tài)
參數(shù)輸出
功能設(shè)置寄存器可以設(shè)置傳感器的工作模式、參數(shù)輸出頻率、參數(shù)范圍、中斷等參數(shù),只有設(shè)置了正確的參數(shù)后,傳感器才能工作。在上電/復位后,我們也需要先設(shè)置功能寄存器(初始化),否則傳感器是沒有輸出的,因為默認情況下傳感器是處于掉電模式(Power down)。
狀態(tài)寄存器通常是只讀的,可以通過它查詢傳感器當前的狀態(tài)或者某種標志位。特別在中斷工作模式下,需要通過狀態(tài)寄存器查詢發(fā)生的中斷。
參數(shù)輸出就是傳感器的輸出,如氣壓、溫度等參數(shù)。很多參數(shù)使用了雙字節(jié)甚至更多字節(jié),需要讀取后在組合起來。
因為寄存器較多,所以我們只介紹主要使用到的傳感器,其他傳感器大家可以慢慢研究(寄存器說明請見LPS22HB數(shù)據(jù)手冊的第9節(jié):Register description)。
設(shè)備識別寄存器:WHO_AM_I (0Fh)
可以用來識別芯片的型號。這個寄存器是只讀的,輸出是 0xB1,也就是十進制的177。
控制寄存器:CTRL_REG1 (10h)
這是最重要的一個寄存器,主要參數(shù)都在這里設(shè)置
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| 0 | ODR2 | ODR1 | ODR0 | EN_LPFP | LPFP_CFG | BDU | SIM |
ODR代表采樣頻率,當ODR=0時,傳感器進入掉電模式,設(shè)置成其它參數(shù)時,傳感器就按照指定頻率開始采樣。
EN_LPFP代表使用內(nèi)部低通濾波器,默認是關(guān)閉的。
LPFP_CFG是低通濾波器帶寬設(shè)置,它需要和EN_LPFP配合使用。
BDU是Block data update的縮小,它代表只有讀取輸出數(shù)據(jù)后才更新寄存器
SIM是選擇3線/4線SPI方式。
氣壓寄存器
氣壓參數(shù)由三個寄存器組成,分別是PRESS_OUT_XL (28h)、PRESS_OUT_L (29h)、PRESS_OUT_H (2Ah)
氣壓的計算方法是
氣壓 = PRESS_OUT_H·PRESS_OUT_L·PRESS_OUT_XL / 4096
就是將三個寄存器的值組合起來,然后除以4096。如果精度要求不高,也可以只取PRESS_OUT_H和PRESS_OUT_L,然后除以16。氣壓傳感器的精度是±0.1hPa,所以保留一位小數(shù)就可以了。
如果希望通過氣壓計算高度,通常是用查表計算。不過因為氣壓容易受到溫度、濕度、風力等多個條件影響,通過氣壓計算絕對高度的誤差較大,所以通常是測量相對高度(高度變化)。
溫度寄存器
溫度參數(shù)由兩個寄存器組成:
溫度的計算方法是:
溫度 = TEMP_OUT_H·TEMP_OUT_L / 100
考慮到低于0°時是負數(shù),所以需要將這個參數(shù)做為有符號數(shù)處理。溫度傳感器的精度是±1.5℃。
如果沒有特殊要求,使用上述幾個寄存器就可以實現(xiàn)基本的數(shù)據(jù)采集功能。如果希望進一步降低功耗、改變模式、使用中斷、使用FIFO、使用參考值等功能,還需要進一步研究其它寄存器才行。
LPS22HB 的 Micropython 程序移植
前面介紹了傳感器的接口、主要寄存器、參數(shù)計算等方面的內(nèi)容,下面就介紹用MicroPython驅(qū)動LPS22HB的方法。
為了讓程序具有通用性,以及系統(tǒng)模塊化的要求,我們將為 LPS22HB 單獨建立一個 Module,這樣也方便其它程序使用。python語言中,一個module和C++的子程序差不多,里面可以包含多個對象(class),每個對象提供一系列函數(shù)或方法。但是python語言沒有C++那么復雜,也不是面向?qū)ο蟮恼Z言,使用起來簡單得多。
一個典型的mudule的結(jié)構(gòu)如下,它由若干class組成,每個class下又由多個函數(shù)組成。其中比較特殊的是__init__()函數(shù),它類似C++的構(gòu)造函數(shù)初始化,在定義class變量后就會自動調(diào)用__init__()函數(shù),默認需要進行初始化的內(nèi)容都放在這個函數(shù)中。此外,class下的每個函數(shù)在定義時的默認第一個參數(shù)都是self,但是調(diào)用時并不需要使用它,self參數(shù)由python系統(tǒng)內(nèi)部使用。更多關(guān)于python語法部分的內(nèi)容,請大家參考python教程或者參考書,這里就不重復了。
對于LPS22HB傳感器,我們先定義一個基本的LPS22HB類:
class LPS22HB(object): def __init__(self): xxxx def func1(): xxxx def func2(): xxxx
然后再將初始化、其它功能函數(shù)逐步添加進去,最后就是一個完整的驅(qū)動了。
首先需要添加的就是初始化部分,在__init__()函數(shù)中,先添加GPIO部分,將CS的GPIO設(shè)置為輸出,并設(shè)置為高電平,這樣I2C才能正常工作:
# set CS high CS_LPS22HB = Pin(LPS22HB_CS_PIN, Pin.OUT) CS_LPS22HB(1) CS_AG = Pin(LSM6DSM_CS_PIN, Pin.OUT) CS_AG(1) CS_A = Pin(LSM303AGR_CS_A_PIN, Pin.OUT) CS_A(1) CS_M = Pin(LSM303AGR_CS_M_PIN, Pin.OUT) CS_M(1)
然后再添加I2C初始化部分的代碼:
# soft I2C
self.i2c = machine.I2C(-1, sda=machine.Pin('PB15'), scl=machine.Pin('PB13'))
# set open drain and pull up
sda=machine.Pin('PB15', Pin.OPEN_DRAIN, pull=Pin.PULL_UP)
scl=machine.Pin('PB13', Pin.OPEN_DRAIN, pull=Pin.PULL_UP)
再設(shè)置LPS22HB的CTRL1_REG寄存器,讓LPS22HB默認處于工作模式:
# start LPS22HB self.setreg(0x18, LPS22HB_CTRL_REG1, LPS22HB_ADDRESS) self.temp0 = 0 self.press = 0 self.LPS22HB_ON = True
self.temp0、self.press、self.LPS22HB_ON是內(nèi)部變量,用于后面的參數(shù)計算和狀態(tài)設(shè)置。它們不是必須的,這里定義它們主要是為了方便同一模塊下其它函數(shù)調(diào)用。
初始化部分完成后,就是添加其它功能函數(shù)了。大家可以發(fā)現(xiàn)在上面的初始化部分我們使用了一個設(shè)置寄存器的函數(shù),因為設(shè)置和讀取寄存器是一個通用性的操作,所以我們將寄存器的操作也設(shè)置成函數(shù),這樣也方便將底層和應用層分離。為了方便讀取參數(shù),我們還設(shè)置了一個讀取兩個相鄰寄存器的函數(shù)get2reg,這個函數(shù)沒有使用傳感器自動遞增寄存器地址的功能,是因為在傳感器的BUD模式下,地址自動遞增的功能是無效的,為了讓程序有更好的兼容性,所以稍微犧牲了一點性能。
def setreg(self, dat, reg, addr): buf = bytearray(2) buf[0] = reg buf[1] = dat self.i2c.writeto(addr, buf) def getreg(self, reg, addr): buf = bytearray(1) buf[0] = reg self.i2c.writeto(addr, buf) t = self.i2c.readfrom(addr, 1) return t[0] def get2reg(self, reg, addr): l = self.getreg(reg, addr) h = self.getreg(reg+1, addr) return l+h*256
為了增加程序的可讀性和可維護下,我們將寄存器的名稱定義為常量,并且將它放在class的前面,這類似于C語言中的#define。寄存器名稱前面還加上LPS22HB前綴,這樣可以在一個Module中存在多個芯片定義時防止和其它芯片的定義相沖突。
# LPS22HB register LPS22HB_INTERRUPT_CFG= const(0x0B) LPS22HB_THS_P_L = const(0x0C) LPS22HB_THS_P_H = const(0x0D) LPS22HB_WHO_AM_I = const(0x0F) LPS22HB_CTRL_REG1 = const(0x10) LPS22HB_CTRL_REG2 = const(0x11) LPS22HB_CTRL_REG3 = const(0x12) LPS22HB_FIFO_CTRL = const(0x14) LPS22HB_REF_P_XL = const(0x15) LPS22HB_REF_P_L = const(0x16) LPS22HB_REF_P_H = const(0x17) LPS22HB_RPDS_L = const(0x18) LPS22HB_RPDS_H = const(0x19) LPS22HB_RES_CONF = const(0x1A) LPS22HB_INT_SOURCE = const(0x25) LPS22HB_FIFO_STATUS = const(0x26) LPS22HB_STATUS = const(0x27) LPS22HB_PRESS_OUT_XL = const(0x28) LPS22HB_PRESS_OUT_L = const(0x29) LPS22HB_PRESS_OUT_H = const(0x2A) LPS22HB_TEMP_OUT_L = const(0x2B) LPS22HB_TEMP_OUT_H = const(0x2C) LPS22HB_LPFP_RES = const(0x33)
前面的寄存器操作、初始化等可以看成是準備工作,準備工作完成了,就是具體傳感器的操作了。我們使用傳感器最重要的目的就是需要獲得傳感器的參數(shù),因此再定義兩個函數(shù),一個用于獲取氣壓,一個獲取溫度。
def LPS22HB_temp(self): self.temp0 = self.get2reg(LPS22HB_TEMP_OUT_L, LPS22HB_ADDRESS) if(self.temp0 > 0x7FFF): self.temp0 -= 65536 return self.temp0/100 def LPS22HB_press(self): self.press = self.getreg(LPS22HB_PRESS_OUT_XL, LPS22HB_ADDRESS) self.press += self.get2reg(LPS22HB_PRESS_OUT_L, LPS22HB_ADDRESS) * 256 return self.press/4096
氣壓函數(shù)是先讀取三個寄存器的參數(shù),然后將結(jié)果除以4096,這就是按照前面介紹的計算方法進行換算的。而溫度函數(shù)稍微麻煩一點,因為存在負數(shù)的問題。在python語言中不像C語言那樣可以自動進行類型轉(zhuǎn)換,寄存器的參數(shù)不能直接轉(zhuǎn)換為負數(shù),所以需要自己判斷和轉(zhuǎn)換。因為這里是一個雙字節(jié)的數(shù)據(jù),最高位就是符號位,因此如果數(shù)據(jù)大于0x7FFF或者最高位是1,那么就認為它是負數(shù)。
另外在一些情況下,需要同時讀取溫度和氣壓兩個數(shù)據(jù),所以我們可以將兩個參數(shù)放到一個函數(shù)中,通過一個列表返回。這里可以直接將前面兩個函數(shù)放在return的列表中。
def LPS22HB(self): return [self.LPS22HB_temp(), self.LPS22HB_press()]
最后,為了降低功耗,還需要讓傳感器可以進入掉電模式,因此我們還需要增加兩個功耗管理函數(shù):
def LPS22HB_poweron(self): t = self.getreg(LPS22HB_CTRL_REG1, LPS22HB_ADDRESS) & 0x0F self.setreg(t|0x10, LPS22HB_CTRL_REG1, LPS22HB_ADDRESS) self.LPS22HB_ON = True def LPS22HB_poweroff(self): t = self.getreg(LPS22HB_CTRL_REG1, LPS22HB_ADDRESS) & 0x0F self.setreg(t, LPS22HB_CTRL_REG1, LPS22HB_ADDRESS) self.LPS22HB_ON = False
在掉電模式下(Power down),傳感器的最低功耗是1uA。其實LPS22HB的功耗也不高,在ODR和LC_EN都是1時也只有3uA。
完成上面的工作后,我們就實現(xiàn)了一個最基本的LPS22HB驅(qū)動。我們可以把它保存到一個LPS22HB.py文件中,然后用下面的方法使用它:
>>> from LPS22HB import LPS22HB
>>> lp=LPS22HB()
>>> lp.LPS22HB_temp()
16.17
>>> lp.LPS22HB_press()
1025.827
>>> lp.LPS22HB()
[16.14, 1025.839]
如果用dir(LPS22HB),可以查看全部的函數(shù)
>>> dir(LPS22HB)
['__qualname__', 'LPS22HB_poweron', '__module__', 'LPS22HB_press', 'LPS22HB_temp', 'LPS22HB', 'getreg', 'setreg', 'get2reg', 'LPS22HB_poweroff', '__init__']
關(guān)于SensorTile中如何使用MicroPython就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
當前題目:SensorTile中如何使用MicroPython
文章源于:http://www.chinadenli.net/article6/gicjig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務器、企業(yè)建站、ChatGPT、品牌網(wǎng)站設(shè)計、做網(wǎng)站、用戶體驗
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)