加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 一、前言
    • 二、硬件連接
    • 三、寄存器介紹
    • 四、編程原理介紹
    • 五、使能樹莓派IIC接口
    • 六、IIC通訊測試
    • 七、編寫代碼并運行
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

樹莓派從零開始快速入門第10講——IIC(以BMP280為例)

07/10 15:25
2773
閱讀需 24 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

一、前言

上一講介紹了串口的使用,那這一講就介紹一下IIC,IIC由時鐘線(SCL)和數(shù)據(jù)線(SDA)組成,時鐘線提供了通訊的時序,只能由主機發(fā)給從機,而數(shù)據(jù)線和單總線類似,數(shù)據(jù)傳輸是雙向的。具體的原理就不多說了,感興趣的同學可以自行查閱相關(guān)資料,也可以看我之前寫的那兩篇光照傳感器的博客。

BH1750光照傳感器超詳細攻略(從原理到代碼講解)

OPT3001光照傳感器驅(qū)動教學

這一講主要以BMP280為例,其實在傳感器的選擇上面我糾結(jié)了一會。因為我現(xiàn)在手上有的傳感器都在一塊擴展板上面,而用IIC的傳感器就兩個,另外一個比較特殊,相比正常IIC缺少了一些東西,不適合做例子,就只能選BMP280,但是BMP280的寄存器多了點,數(shù)據(jù)處理也較復(fù)雜,其實也不適合做零基礎(chǔ)入門教程。但手上暫時也沒用其他傳感器了,就先將就用吧,我盡量把編程部分講詳細些。

二、硬件連接

BMP280是一款氣壓檢測芯片,同時也可以測量溫度,通訊方式有兩種:IIC和SPI,選擇不同的方式接線不一樣,我這里用的是擴展板,硬件已經(jīng)連接好了,連接的硬件接口是IIC1。具體硬件的介紹就不多說了,感興趣的同學可以去看下數(shù)據(jù)手冊。

注:IIC接口一定要接對,并且記住IIC的編號,樹莓派3B+的IIC接口有兩組,IIC0和IIC1,我這里用的是IIC1。

在這里插入圖片描述

BMP280引腳定義如下:

在這里插入圖片描述

引腳我就不一一介紹了,我只講一下SDO這個引腳,用IIC方式通訊時,該引腳決定了IIC的器件地址(直接影響代碼),原文如下:

在這里插入圖片描述

翻譯一下,意思就是SDO拉低的話器件地址是1110110(0x76),拉高的話器件地址是1110111(0x77)。

三、寄存器介紹

BMP280寄存器其實不多,不過對于初學者來說可能會有點懵,不要慌,且聽我慢慢道來。

BMP280內(nèi)存分布如下:

在這里插入圖片描述

注:因為上圖的地址是反過來寫的,那我的順序也反一下。

寄存器地址 說明
0xA1-0x88 校準數(shù)據(jù)
0xE0 用來重啟傳感器的
0xF3 指示傳感器當前狀態(tài)
0xF4 設(shè)置數(shù)據(jù)采集選項
0xF5 設(shè)置基本配置參數(shù)
0xF7-0xF9 氣壓原始數(shù)據(jù)
0xFA-0xFC 溫度原始數(shù)據(jù)

每個寄存器每個位代表的意義我就不具體解釋,自行查閱數(shù)據(jù)手冊。

四、編程原理介紹

編程的步驟大致如下:

1)讀取ID寄存器,判斷讀取到的值和傳感器實際的值是否一致(這一步可以確認傳感器和樹莓派通訊是否正常)

2)讀取校準數(shù)據(jù)

3)設(shè)置數(shù)據(jù)采集選項

4)設(shè)置基本配置參數(shù)

5)分別讀取氣壓和溫度的原始數(shù)據(jù)(三個寄存器的值合并拼接到一起才是完整的數(shù)據(jù))

6)把原始數(shù)據(jù)和校準數(shù)據(jù)代入公式計算出最終的氣壓和溫度

五、使能樹莓派IIC接口

方法1:通過配置命令

sudo raspi-config    // 打開配置
sudo reboot          // 重啟,如果之前沒有使能,配置完之后要重啟才能生效

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

方法2:在可視化界面的設(shè)置里面修改

在這里插入圖片描述
在這里插入圖片描述

如果之前沒有使能,配置完之后要重啟才能生效

六、IIC通訊測試

我們可以使用i2c-tool工具來查詢IIC設(shè)備是否正常連接,我這個系統(tǒng)鏡像是自帶i2c-tool,如果沒有下載,可以通過下面的命令下載。

sudo apt-get install i2c-tools

用i2c-tool查詢i2c設(shè)備

i2cdetect -y 1 // -y:取消用戶交互過程,直接執(zhí)行指令; 1:I2C的總線編號為1(根據(jù)自己的接口選擇)

在這里插入圖片描述

注:我這里有多個IIC設(shè)備,器件地址為76的這個才是BMP280(BMP280的地址只可能是76或者77,具體取決于SD0引腳的電平,我前面有講過)。

七、編寫代碼并運行

IIC的通信部分主要是調(diào)用了smbus這個庫,關(guān)于這個庫的相關(guān)函數(shù)和解釋,可以參考下面這個鏈接。

https://pypi.org/project/smbus2/

示例代碼如下:

import time
import smbus

# BMP280 iic address.
BMP280_I2C_ADDRESS = 0x76        # SDO = 0

# Registers value
BMP280_ID_Value = 0x58           # BMP280 ID
BMP280_RESET_VALUE = 0xB6

# BMP280 Registers definition
BMP280_TEMP_XLSB_REG = 0xFC      # Temperature XLSB Register
BMP280_TEMP_LSB_REG = 0xFB       # Temperature LSB Register
BMP280_TEMP_MSB_REG = 0xFA       # Temperature LSB Register
BMP280_PRESS_XLSB_REG = 0xF9     # Pressure XLSB  Register
BMP280_PRESS_LSB_REG = 0xF8      # Pressure LSB Register
BMP280_PRESS_MSB_REG = 0xF7      # Pressure MSB Register
BMP280_CONFIG_REG = 0xF5         # Configuration Register
BMP280_CTRL_MEAS_REG = 0xF4      # Ctrl Measure Register
BMP280_STATUS_REG = 0xF3         # Status Register
BMP280_RESET_REG = 0xE0          # Softreset Register
BMP280_ID_REG = 0xD0             # Chip ID Register

# calibration parameters
BMP280_DIG_T1_LSB_REG = 0x88
BMP280_DIG_T1_MSB_REG = 0x89
BMP280_DIG_T2_LSB_REG = 0x8A
BMP280_DIG_T2_MSB_REG = 0x8B
BMP280_DIG_T3_LSB_REG = 0x8C
BMP280_DIG_T3_MSB_REG = 0x8D
BMP280_DIG_P1_LSB_REG = 0x8E
BMP280_DIG_P1_MSB_REG = 0x8F
BMP280_DIG_P2_LSB_REG = 0x90
BMP280_DIG_P2_MSB_REG = 0x91
BMP280_DIG_P3_LSB_REG = 0x92
BMP280_DIG_P3_MSB_REG = 0x93
BMP280_DIG_P4_LSB_REG = 0x94
BMP280_DIG_P4_MSB_REG = 0x95
BMP280_DIG_P5_LSB_REG = 0x96
BMP280_DIG_P5_MSB_REG = 0x97
BMP280_DIG_P6_LSB_REG = 0x98
BMP280_DIG_P6_MSB_REG = 0x99
BMP280_DIG_P7_LSB_REG = 0x9A
BMP280_DIG_P7_MSB_REG = 0x9B
BMP280_DIG_P8_LSB_REG = 0x9C
BMP280_DIG_P8_MSB_REG = 0x9D
BMP280_DIG_P9_LSB_REG = 0x9E
BMP280_DIG_P9_MSB_REG = 0x9F


class BMP180(object):
    def __init__(self, address=BMP280_I2C_ADDRESS):
        self._address = address
        self._bus = smbus.SMBus(1)    # 1: iic編號為1(根據(jù)自己的硬件接口選擇對應(yīng)的編號)
        # Load calibration values.
        if self._read_byte(BMP280_ID_REG) == BMP280_ID_Value: # read bmp280 id
            self._load_calibration()                          # load calibration data
            # BMP280_T_MODE_1 << 5 | BMP280_P_MODE_1 << 2 | BMP280_SLEEP_MODE;
            ctrlmeas = 0xFF
            # BMP280_T_SB1 << 5 | BMP280_FILTER_MODE_1 << 2;
            config = 0x14
            self._write_byte(BMP280_CTRL_MEAS_REG, ctrlmeas)  # write bmp280 config
            # sets the data acquisition options
            self._write_byte(BMP280_CONFIG_REG, config)
        else:
            print("Read BMP280 id error!rn")

    def _read_byte(self, cmd):
        return self._bus.read_byte_data(self._address, cmd)

    def _read_u16(self, cmd):
        LSB = self._bus.read_byte_data(self._address, cmd)
        MSB = self._bus.read_byte_data(self._address, cmd+1)
        return (MSB << 8) + LSB

    def _read_s16(self, cmd):
        result = self._read_u16(cmd)
        if result > 32767:
            result -= 65536
        return result

    def _write_byte(self, cmd, val):
        self._bus.write_byte_data(self._address, cmd, val)

    def _load_calibration(self):                           # load calibration data
        "load calibration"

        """ read the temperature calibration parameters """
        self.dig_T1 = self._read_u16(BMP280_DIG_T1_LSB_REG)
        self.dig_T2 = self._read_s16(BMP280_DIG_T2_LSB_REG)
        self.dig_T3 = self._read_s16(BMP280_DIG_T3_LSB_REG)
        """ read the pressure calibration parameters """
        self.dig_P1 = self._read_u16(BMP280_DIG_P1_LSB_REG)
        self.dig_P2 = self._read_s16(BMP280_DIG_P2_LSB_REG)
        self.dig_P3 = self._read_s16(BMP280_DIG_P3_LSB_REG)
        self.dig_P4 = self._read_s16(BMP280_DIG_P4_LSB_REG)
        self.dig_P5 = self._read_s16(BMP280_DIG_P5_LSB_REG)
        self.dig_P6 = self._read_s16(BMP280_DIG_P6_LSB_REG)
        self.dig_P7 = self._read_s16(BMP280_DIG_P7_LSB_REG)
        self.dig_P8 = self._read_s16(BMP280_DIG_P8_LSB_REG)
        self.dig_P9 = self._read_s16(BMP280_DIG_P9_LSB_REG)

        # print(self.dig_T1)
        # print(self.dig_T2)
        # print(self.dig_T3)
        # print(self.dig_P1)
        # print(self.dig_P2)
        # print(self.dig_P3)
        # print(self.dig_P4)
        # print(self.dig_P5)
        # print(self.dig_P6)
        # print(self.dig_P7)
        # print(self.dig_P8)
        # print(self.dig_P9)

    def compensate_temperature(self, adc_T):
        """Returns temperature in DegC, double precision. Output value of "1.23"equals 51.23 DegC."""
        var1 = ((adc_T) / 16384.0 - (self.dig_T1) / 1024.0) * (self.dig_T2)
        var2 = (((adc_T) / 131072.0 - (self.dig_T1) / 8192.0) *
                ((adc_T) / 131072.0 - (self.dig_T1) / 8192.0)) * (self.dig_T3)
        self.t_fine = var1 + var2
        temperature = (var1 + var2) / 5120.0
        return temperature

    def compensate_pressure(self, adc_P):
        """Returns pressure in Pa as double. Output value of "6386.2"equals 96386.2 Pa = 963.862 hPa."""
        var1 = (self.t_fine / 2.0) - 64000.0
        var2 = var1 * var1 * (self.dig_P6) / 32768.0
        var2 = var2 + var1 * (self.dig_P5) * 2.0
        var2 = (var2 / 4.0) + ((self.dig_P4) * 65536.0)
        var1 = ((self.dig_P3) * var1 * var1 / 524288.0 +
                (self.dig_P2) * var1) / 524288.0
        var1 = (1.0 + var1 / 32768.0) * (self.dig_P1)

        if var1 == 0.0:
            return 0  # avoid exception caused by division by zero

        pressure = 1048576.0 - adc_P
        pressure = (pressure - (var2 / 4096.0)) * 6250.0 / var1
        var1 = (self.dig_P9) * pressure * pressure / 2147483648.0
        var2 = pressure * (self.dig_P8) / 32768.0
        pressure = pressure + (var1 + var2 + (self.dig_P7)) / 16.0

        return pressure

    def get_temperature_and_pressure(self):
        """Returns pressure in Pa as double. Output value of "6386.2"equals 96386.2 Pa = 963.862 hPa."""
        xlsb = self._read_byte(BMP280_TEMP_XLSB_REG)
        lsb = self._read_byte(BMP280_TEMP_LSB_REG)
        msb = self._read_byte(BMP280_TEMP_MSB_REG)

        adc_T = (msb << 12) | (lsb << 4) | (
            xlsb >> 4)      # temperature registers data
        temperature = self.compensate_temperature(
            adc_T)    # temperature compensate

        xlsb = self._read_byte(BMP280_PRESS_XLSB_REG)
        lsb = self._read_byte(BMP280_PRESS_LSB_REG)
        msb = self._read_byte(BMP280_PRESS_MSB_REG)

        adc_P = (msb << 12) | (lsb << 4) | (
            xlsb >> 4)      # pressure registers data
        pressure = self.compensate_pressure(
            adc_P)          # pressure compensate
        return temperature, pressure


if __name__ == '__main__':

    import time

    print("BMP280 Test Program ...n")

    bmp280 = BMP180()

    while True:
        time.sleep(1)
        temperature, pressure = bmp280.get_temperature_and_pressure()
        print(' Temperature = %.2f C Pressure = %.3f kPa' %
              (temperature, pressure/1000))

示例代碼運行結(jié)果:

在這里插入圖片描述

八、結(jié)束語

IIC的學習和使用歸結(jié)起來其實就三點,1:IIC通訊原理(硬件原理和底層編程),2:寄存器(不同的芯片寄存器也有區(qū)別,需要了解每個寄存器的作用),3:應(yīng)用(配置寄存器、讀取數(shù)據(jù)、數(shù)據(jù)處理)

其中,第一點其實可以不學。為什么這么說呢?我在上一講有講過了樹莓派和單片機的區(qū)別,樹莓派想快速入門,可以先忽略底層,從應(yīng)用層開始。上面的三點內(nèi)容的第一點的底層編程其實在樹莓派的庫里面已經(jīng)做好了,我們只要調(diào)用iic的讀取和寫入的函數(shù),做我們自己應(yīng)用層的編程即可。

好了,這一講的內(nèi)容就這么多了,如果對你有幫助,可以給個收藏,如果想了解更多樹莓派的知識可以關(guān)注我,后續(xù)我會繼續(xù)更新更多的教程。

教程相關(guān)的軟件和源碼:https://pan.baidu.com/s/1-lVAZyH2s-VTn5qeSnEPhA ,提取碼:qwer

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風險等級 參考價格 更多信息
511BCA100M000BAG 1 Silicon Laboratories Inc Oscillator, 0.1MHz Min, 250MHz Max, 100MHz Nom,

ECAD模型

下載ECAD模型
$4.11 查看
CPC1560G 1 IXYS Corporation Transistor Output SSR, 1-Channel, 3750V Isolation, DIP-8
$4.67 查看
Q13MC1462000200 1 Seiko Epson Corporation Parallel - Fundamental Quartz Crystal, 0.032768MHz Nom,
$1 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜