溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SensorTile中如何使用MicroPython

發(fā)布時(shí)間:2021-08-05 17:38:55 來源:億速云 閱讀:256 作者:Leah 欄目:互聯(lián)網(wǎng)科技

這篇文章將為大家詳細(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氣壓傳感器


SensorTile中如何使用MicroPython 

硬件接口

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)就是犧牲了速度。


SensorTile中如何使用MicroPython 

因?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ì)傳感器的寄存器有初步的了解。


SensorTile中如何使用MicroPython 

上圖是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í),傳感器就按照指定頻率開始采樣。
SensorTile中如何使用MicroPython 

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)

SensorTile中如何使用MicroPython 

氣壓的計(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è)寄存器組成:
SensorTile中如何使用MicroPython 

溫度的計(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ù)了。

SensorTile中如何使用MicroPython 

對(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ò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(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)容。

AI