您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)SensorTile中如何使用MicroPython,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
SensotTile簡介
SensorTile核心板非常緊湊小巧,看起來就是一個(gè)可穿戴的原型(智能手表),因此它配置的傳感器也是和運(yùn)動(dòng)相關(guān)的。SensorTile核心板上有4個(gè)傳感器,它們分別是:
LPS22HB,氣壓+溫度傳感器
LSM6DSM,三軸加速度+三軸角速度傳感器
LSM303AGR,三軸角速度+三軸磁場傳感器
MP34DT04,MEMS麥克風(fēng)傳感器
我們先從最簡單的LPS22HB開始,逐步介紹傳感器的使用和移植方法。而MP34DT04傳感器這次沒有使用到,它的接口也和其他傳感器不同,所以暫時(shí)先不看。
LPS22HB氣壓傳感器
硬件接口
LPS22HB的原理圖如上,從上面我們可以看到,傳感器使用了SPI連接方式,但是只用了CS、SCL/SPC、SDA/SDI/SDO這幾個(gè)腳,SDO腳沒有使用,說明它沒有使用標(biāo)準(zhǔn)的SPI接口方式。此外,還可以看到INT信號(hào)也沒有連接,所以也就不能使用INT模式了。通常在INT模式下,可以預(yù)先設(shè)置一個(gè)門限參數(shù),當(dāng)傳感器的輸出超過這個(gè)門限時(shí),就會(huì)自動(dòng)產(chǎn)生一個(gè)INT信號(hào),用來喚醒MCU,然后讀取并處理參數(shù),這有助于簡化編程,降低系統(tǒng)功耗。
從傳感器的用戶手冊(cè)中可以看到,傳感器支持SPI/I2C兩種接口。這兩種接口方式是通過CS腳進(jìn)行切換的,當(dāng)CS為低電平時(shí)是SPI方式,CS是高電平時(shí)是I2C方式。SensorTile在硬件設(shè)計(jì)時(shí),使用了半雙工的SPI接口(又叫3-wire模式),這個(gè)模式下主機(jī)只使用MOSI做數(shù)據(jù)線,而從機(jī)使用MISO。它的好處在于可以節(jié)約一個(gè)數(shù)據(jù)線,缺點(diǎn)就是犧牲了速度。
因?yàn)镸icroPython目前不支持半雙工的SPI接口方式(硬件SPI和軟件SPI都不支持這個(gè)方式),因此要用SPI方式驅(qū)動(dòng)傳感器就只能自己通過軟件模擬這種SPI方式,這不但增加了軟件的復(fù)雜性,同時(shí)速度也會(huì)比較慢,所以我采用了I2C接口方式。因?yàn)镾PI_SDA(PB15)和SPI_CLK(PB13)引腳并不是硬件I2C接口,所以需要用軟件I2C方式。好在micropython底層已經(jīng)支持軟件I2C,使用方法和硬件I2C一樣,速度也不慢。
這里先介紹一下軟件I2C。為了使用軟件I2C,我們需要使用到micropython的machine庫,而不能使用pyb庫。大家可能也注意到了,CC3200、ESP8266、STM32等分支在硬件底層函數(shù)接口上有很多不同,這給我們編程和程序移植帶來很多不便。從v1.8版開始,micropython開始增強(qiáng)了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。
直接這樣定義后,大家會(huì)發(fā)現(xiàn)I2C還是不能工作,這是因?yàn)樵赟ensorTile內(nèi)部沒有設(shè)置I2C的上拉電阻,這樣I2C總線的狀態(tài)無法確定,所以我們還需要使能GPIO內(nèi)部的上拉電阻。注意這個(gè)步驟需要放在I2C初始化之后,因?yàn)樵贗2C初始化的時(shí)候,會(huì)重新設(shè)置GPIO狀態(tài)和參數(shù)。直接在I2C定義中的sda=machine.Pin('PB15', pull=Pin.PULL_UP)加入上拉電阻定義也是不能工作的,因?yàn)樵谠O(shè)置I2C時(shí)會(huì)忽略這個(gè)參數(shù)。在I2C定義后,再加入下面的定義,I2C就可以正常工作了,如果這時(shí)使用i2c.scan()函數(shù),就可以搜索到4個(gè)設(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提供了多個(gè)例程,例程中包含了傳感器的底層驅(qū)動(dòng)函數(shù)。如果使用C++編程,可以使用這些驅(qū)動(dòng)函數(shù)。而我們要使用micropython進(jìn)行編程,所以無法直接使用ST的底層函數(shù),需要自己對(duì)寄存器進(jìn)行操作(其實(shí)ST的底層驅(qū)動(dòng)函數(shù)也是對(duì)這些寄存器進(jìn)行操作,只是它已經(jīng)封裝好了,不用再看寄存器說明了)。為了使用LPS22HB,需要對(duì)傳感器的寄存器有初步的了解。
上圖是LPS22HB的寄存器列表,它的寄存器不是太多,除去保留的寄存器(Reserved)外,一共大約有二十幾個(gè)。每個(gè)寄存器都有一個(gè)地址,寄存器輸出是8位的,大部分寄存器可以讀寫(RW),少量寄存器是只讀的(R)。如果按照功能進(jìn)行劃分,傳感器的寄存器大致可以分為下面幾類:
功能設(shè)置
傳感器狀態(tài)
參數(shù)輸出
功能設(shè)置寄存器可以設(shè)置傳感器的工作模式、參數(shù)輸出頻率、參數(shù)范圍、中斷等參數(shù),只有設(shè)置了正確的參數(shù)后,傳感器才能工作。在上電/復(fù)位后,我們也需要先設(shè)置功能寄存器(初始化),否則傳感器是沒有輸出的,因?yàn)槟J(rèn)情況下傳感器是處于掉電模式(Power down)。
狀態(tài)寄存器通常是只讀的,可以通過它查詢傳感器當(dāng)前的狀態(tài)或者某種標(biāo)志位。特別在中斷工作模式下,需要通過狀態(tài)寄存器查詢發(fā)生的中斷。
參數(shù)輸出就是傳感器的輸出,如氣壓、溫度等參數(shù)。很多參數(shù)使用了雙字節(jié)甚至更多字節(jié),需要讀取后在組合起來。
因?yàn)榧拇嫫鬏^多,所以我們只介紹主要使用到的傳感器,其他傳感器大家可以慢慢研究(寄存器說明請(qǐng)見LPS22HB數(shù)據(jù)手冊(cè)的第9節(jié):Register description)。
設(shè)備識(shí)別寄存器:WHO_AM_I (0Fh)
可以用來識(shí)別芯片的型號(hào)。這個(gè)寄存器是只讀的,輸出是 0xB1,也就是十進(jìn)制的177。
控制寄存器:CTRL_REG1 (10h)
這是最重要的一個(gè)寄存器,主要參數(shù)都在這里設(shè)置
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0 | ODR2 | ODR1 | ODR0 | EN_LPFP | LPFP_CFG | BDU | SIM |
ODR代表采樣頻率,當(dāng)ODR=0時(shí),傳感器進(jìn)入掉電模式,設(shè)置成其它參數(shù)時(shí),傳感器就按照指定頻率開始采樣。
EN_LPFP代表使用內(nèi)部低通濾波器,默認(rèn)是關(guān)閉的。
LPFP_CFG是低通濾波器帶寬設(shè)置,它需要和EN_LPFP配合使用。
BDU是Block data update的縮小,它代表只有讀取輸出數(shù)據(jù)后才更新寄存器
SIM是選擇3線/4線SPI方式。
氣壓寄存器
氣壓參數(shù)由三個(gè)寄存器組成,分別是PRESS_OUT_XL (28h)、PRESS_OUT_L (29h)、PRESS_OUT_H (2Ah)
氣壓的計(jì)算方法是
氣壓 = PRESS_OUT_H·PRESS_OUT_L·PRESS_OUT_XL / 4096
就是將三個(gè)寄存器的值組合起來,然后除以4096。如果精度要求不高,也可以只取PRESS_OUT_H和PRESS_OUT_L,然后除以16。氣壓傳感器的精度是±0.1hPa,所以保留一位小數(shù)就可以了。
如果希望通過氣壓計(jì)算高度,通常是用查表計(jì)算。不過因?yàn)闅鈮喝菀资艿綔囟?、濕度、風(fēng)力等多個(gè)條件影響,通過氣壓計(jì)算絕對(duì)高度的誤差較大,所以通常是測量相對(duì)高度(高度變化)。
溫度寄存器
溫度參數(shù)由兩個(gè)寄存器組成:
溫度的計(jì)算方法是:
溫度 = TEMP_OUT_H·TEMP_OUT_L / 100
考慮到低于0°時(shí)是負(fù)數(shù),所以需要將這個(gè)參數(shù)做為有符號(hào)數(shù)處理。溫度傳感器的精度是±1.5℃。
如果沒有特殊要求,使用上述幾個(gè)寄存器就可以實(shí)現(xiàn)基本的數(shù)據(jù)采集功能。如果希望進(jìn)一步降低功耗、改變模式、使用中斷、使用FIFO、使用參考值等功能,還需要進(jìn)一步研究其它寄存器才行。
LPS22HB 的 Micropython 程序移植
前面介紹了傳感器的接口、主要寄存器、參數(shù)計(jì)算等方面的內(nèi)容,下面就介紹用MicroPython驅(qū)動(dòng)LPS22HB的方法。
為了讓程序具有通用性,以及系統(tǒng)模塊化的要求,我們將為 LPS22HB 單獨(dú)建立一個(gè) Module,這樣也方便其它程序使用。python語言中,一個(gè)module和C++的子程序差不多,里面可以包含多個(gè)對(duì)象(class),每個(gè)對(duì)象提供一系列函數(shù)或方法。但是python語言沒有C++那么復(fù)雜,也不是面向?qū)ο蟮恼Z言,使用起來簡單得多。
一個(gè)典型的mudule的結(jié)構(gòu)如下,它由若干class組成,每個(gè)class下又由多個(gè)函數(shù)組成。其中比較特殊的是__init__()函數(shù),它類似C++的構(gòu)造函數(shù)初始化,在定義class變量后就會(huì)自動(dòng)調(diào)用__init__()函數(shù),默認(rèn)需要進(jìn)行初始化的內(nèi)容都放在這個(gè)函數(shù)中。此外,class下的每個(gè)函數(shù)在定義時(shí)的默認(rèn)第一個(gè)參數(shù)都是self,但是調(diào)用時(shí)并不需要使用它,self參數(shù)由python系統(tǒng)內(nèi)部使用。更多關(guān)于python語法部分的內(nèi)容,請(qǐng)大家參考python教程或者參考書,這里就不重復(fù)了。
對(duì)于LPS22HB傳感器,我們先定義一個(gè)基本的LPS22HB類:
class LPS22HB(object): def __init__(self): xxxx def func1(): xxxx def func2(): xxxx
然后再將初始化、其它功能函數(shù)逐步添加進(jìn)去,最后就是一個(gè)完整的驅(qū)動(dòng)了。
首先需要添加的就是初始化部分,在__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默認(rèn)處于工作模式:
# 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ù)計(jì)算和狀態(tài)設(shè)置。它們不是必須的,這里定義它們主要是為了方便同一模塊下其它函數(shù)調(diào)用。
初始化部分完成后,就是添加其它功能函數(shù)了。大家可以發(fā)現(xiàn)在上面的初始化部分我們使用了一個(gè)設(shè)置寄存器的函數(shù),因?yàn)樵O(shè)置和讀取寄存器是一個(gè)通用性的操作,所以我們將寄存器的操作也設(shè)置成函數(shù),這樣也方便將底層和應(yīng)用層分離。為了方便讀取參數(shù),我們還設(shè)置了一個(gè)讀取兩個(gè)相鄰寄存器的函數(shù)get2reg,這個(gè)函數(shù)沒有使用傳感器自動(dòng)遞增寄存器地址的功能,是因?yàn)樵趥鞲衅鞯腂UD模式下,地址自動(dòng)遞增的功能是無效的,為了讓程序有更好的兼容性,所以稍微犧牲了一點(diǎn)性能。
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
為了增加程序的可讀性和可維護(hù)下,我們將寄存器的名稱定義為常量,并且將它放在class的前面,這類似于C語言中的#define。寄存器名稱前面還加上LPS22HB前綴,這樣可以在一個(gè)Module中存在多個(gè)芯片定義時(shí)防止和其它芯片的定義相沖突。
# 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)
前面的寄存器操作、初始化等可以看成是準(zhǔn)備工作,準(zhǔn)備工作完成了,就是具體傳感器的操作了。我們使用傳感器最重要的目的就是需要獲得傳感器的參數(shù),因此再定義兩個(gè)函數(shù),一個(gè)用于獲取氣壓,一個(gè)獲取溫度。
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ù)是先讀取三個(gè)寄存器的參數(shù),然后將結(jié)果除以4096,這就是按照前面介紹的計(jì)算方法進(jìn)行換算的。而溫度函數(shù)稍微麻煩一點(diǎn),因?yàn)榇嬖谪?fù)數(shù)的問題。在python語言中不像C語言那樣可以自動(dòng)進(jìn)行類型轉(zhuǎn)換,寄存器的參數(shù)不能直接轉(zhuǎn)換為負(fù)數(shù),所以需要自己判斷和轉(zhuǎn)換。因?yàn)檫@里是一個(gè)雙字節(jié)的數(shù)據(jù),最高位就是符號(hào)位,因此如果數(shù)據(jù)大于0x7FFF或者最高位是1,那么就認(rèn)為它是負(fù)數(shù)。
另外在一些情況下,需要同時(shí)讀取溫度和氣壓兩個(gè)數(shù)據(jù),所以我們可以將兩個(gè)參數(shù)放到一個(gè)函數(shù)中,通過一個(gè)列表返回。這里可以直接將前面兩個(gè)函數(shù)放在return的列表中。
def LPS22HB(self): return [self.LPS22HB_temp(), self.LPS22HB_press()]
最后,為了降低功耗,還需要讓傳感器可以進(jìn)入掉電模式,因此我們還需要增加兩個(gè)功耗管理函數(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。其實(shí)LPS22HB的功耗也不高,在ODR和LC_EN都是1時(shí)也只有3uA。
完成上面的工作后,我們就實(shí)現(xiàn)了一個(gè)最基本的LPS22HB驅(qū)動(dòng)。我們可以把它保存到一個(gè)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)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。