Nordic 藍牙芯片上開發 SHT3x系列溫溼度傳感器

第1部分 SHT31傳感器介紹

1.1芯片簡介

SHT3X系列是由瑞士Sensirion生產的高精度溫溼度傳感器,也是Sensirion公司目前主打的溫溼度傳感器系列。現在網上常見的相關資料調試的基本上以SHT30爲主,SHT31則較少。本次開發用的是更高級的SHT35系列。

                                   

 

這次採用的SHT35傳感器允許寬電壓輸入,支持2.15V~5.5V。採用IIC總線通信,最高可達1MHz的通信速度。並根據ADDR引腳的接法,提供兩個可選的地址:0x44,0x45。傳感器的精度爲1.5%RH和0.1℃。傳感器最大工作範圍-40-125℃,0-100%RH。原裝芯片有8個引腳。

還有一點要注意的是SHT3x推薦的的最佳工作環境是5℃-60℃,20%RH-80%RH。當傳感器暴露在>80%RH的工作環境下超過60小時後,會出現+3%RH的偏差。

                            

SHT3x系列提供數字接口和模擬接口兩種規格。

                            

 

    相關資料在文末給出。

 

1.2 引腳介紹

芯片總共有8個引腳

(1)SDA :IIC數據線引腳

(2)ADDR :地址引腳,可連接VSS或VDD,分別會有不同的地址。不能浮空。

(3)ALERT :報警引腳,如果使用,建議接到單片機的外部中斷。不用的話建議浮空。

(4)SCL :IIC時鐘線引腳

(5)VDD :電壓輸入引腳

(6)nRESET :復位引腳,低電平有效。如果不用,建議接到VDD。

(7)R :沒有電氣作用的“沒卵用“”引腳,連接到VSS

(8) VSS :接地

                                           

 

(附上官方推薦的典型應用電路)

 

1.3命令和模式介紹

 

首先看一下地址

                                                          

 

很明顯,當傳感器ADDR引腳接VSS時,採用地址A;當傳感器ADDR引腳接VDD時,採用地址B。本次開發的傳感器 Address=0x44.

傳感器支持單次數據採集模式和週期性數據採集模式。其實單次數據採集模式下,可選時鐘延伸,而週期性數據採集默認開始數據延伸。這裏我們默認採用週期性數據採集模式。

                                        

 

SHT3X支持12種工作模式,分別有高,中,低三檔可選刷新率。mps=0.5,1,2…時,分別代表每兩秒採集一次數據,每秒採集一次數據,每秒採集兩次數據…

 

如希望設定高刷新率,每秒採集一次。那麼向傳感器寫命令0x2130即可。注意當採用mps=10時,會導致傳感器自發熱,影響測量。

 

工作順序爲:先發送IIC通信開始標誌Start後,寫入左移一位的地址,並將空出來的位寫0表示寫數據。當收到傳感器應答後,即可發送命令的高八位,再次等待應答,再發送餘下的低八位。然後等待ACK應答即可。

其他命令同理,大部分都是同樣的寫入模式。

 

1.4 重要命令及其工作流程

那麼我們看幾條重要的命令及其工作流程。

                                                         

 

設置好工作模式後寫入此命令,可以準備好接受數據。先發送IIC通信開始標誌Start後,寫入左移一位的地址,並將空出來的位寫1表示讀數據。然後等待ACK應答即可接受數據。注意數據傳輸順序是先溫度後溼度。並且都是十六位數據。並且每個數據後都附8位的CRC校驗。在完成溼度的CRC校驗後,即可回覆NACK,傳感器將停止發送數據,釋放SDA線,以便於MCU發送Stop標誌,結束通信。

 

第2部分 SHT3x官方參考代碼簡介

2.1.官方給的參考code是基於STM32平臺的。文末有資料獲取方式。

由於Nordic藍牙芯片的I2C接口與STM32有稍微不同。本文將基於該參考code,通過修改,移植到nRF52832藍牙芯片上。

                                                  

 

2.2 參考I2C 代碼詳解

本文檔包含C語言的示例代碼,用於通過與SHT3x溼度和溫度傳感器通信

I2C接口。代碼的目的是在實現SHT3x傳感器時簡化用戶的軟件編程。除了

簡單的測量溼度和溫度,代碼包含計算CRC校驗和和計算物理溼度和溫度值。這個示例代碼是爲STM32-Discovery板編寫和優化的,但它可以很容易地應用於其他微控制器而做稍微改變。

                                             

 

至於更詳細的官方參考code和說明,不是本文的重點,系列資料在文末有獲取方式。

 

第3部分 Nordic藍牙芯片 I2C(TWI)軟件設計介紹:

關於nRF52832藍牙芯片的I2C(TWI)串行總線的原理,之前的文章已有介紹。以下主要介紹軟件設計部分。

nRF52832 片內集成的 TWI(兩線串行總線)兼容 I2C 總線,帶有 EasyDMA,可與連接到同一總線的多個從機設備通訊,主要特點如下:

(1)兼容 I2C。

(2)速率:100 kbps、250 kbps 或 400 kbps。

(3)支持時鐘延伸。

(4)帶 EasyDMA。

(5)TWI 的 SCL 和 SDA 信號可以通過配置寄存器連接到任何一個GPIO,這樣可以靈活地實現器件引腳排列,並有效利用電路板空間和信號路由。

nRF52832 的 TWI 的原理框圖如下圖所示,TWI 主機通過觸發STARTTX 或STARTRX 任務啓動TWI 傳輸,通過觸發 STOP 任務停止 TWI 傳輸。TWI 主機在掛起時無法停止,因此必須在 TWI 主機恢復後觸發 STOP 任務停止 TWI。啓動 TWI 主機後,在TWI 主機停止之前,即在 LASTRX,LASTTX 或 STOPPED 事件之後,不應再次觸發 STARTTX 任務或STARTRX 任務。如果從機產生 NACK 輸入,那麼 TWI 主機將產生ERROR 事件。

                                               

 

3.1.nRF的I2C 函數庫應用

TWI 的應用步驟如下圖所示,首先要定義 TWI 驅動程序實例,驅動程序實例對應具體的硬件 TWI 外設(TWI0 和 TWI1),驅動程序實例決定了我們使用的是 TWI0 還是 TWI1。接着初始化配置TWI 連接的引腳和速率等參數,註冊事件句柄(非堵塞模式下),初始化後使能TWI,之後就可以使用 TWI 進行傳輸數據。

                                     

 

3.2定義TWI 驅動程序實例

 

TWI 驅動程序實例使用 nrf_drv_twi_t 結構體定義,該結構體描述了具體的 TWI 外設, 當我們定義了nrf_drv_twi_t 類型的變量並對其賦值後,該變量就對應了一個具體的硬件 TWI 外設。

定義驅動程序實例代碼如下,初始化宏 NRF_DRV_TWI_INSTANCE 的輸入參數對應TWI 外設的編號,即如果我們定義 TWI0 的驅動程序實例,TWI_INSTANCE_ID 的值設置爲 0,定義 TWI1 的驅動程序實例,TWI_INSTANCE_ID 的值設置爲 1。驅動程序實例定義後,我們即可通過該驅動程序實例訪問對應的 TWI。

                                          

 

3.3 初始化TWI(I2C)

TWI 初始化的庫函數是 nrf_drv_twi_init ()函數,該函數同時也配置了 TWI 是否使用阻塞模式。

  (1)應用程序提供事件句柄:TWI 工作於非阻塞模式。

  (2)應用程序不提供事件句柄(event_handler 設置爲 NULL):TWI 工作於阻塞模式。建議使用阻塞模式。

                                 

/** TWI初始化

 * @brief TWI initialization.

 */

//I2C引腳

#define TWI_SCL_M           26         //I2C SCL

#define TWI_SDA_M           25         //I2C SDA

/* TWI instance. */

static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
void twi_init (void)
{
    ret_code_t err_code;

    const nrf_drv_twi_config_t twi_config = {
       .scl                = TWI_SCL_M,
       .sda                = TWI_SDA_M,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);
		NRF_LOG_INFO("twi_master_init ok."); 
		NRF_LOG_FLUSH();
		nrf_gpio_pin_clear(20); //ledµÆÁÁ
}

 

3.5 TWI數據傳輸函數

TWI 驅動程序提供了兩個單獨的函數nrf_drv_twi_tx() 函數 和 nrf_drv_twi_ rx() 函數 , 分別用於完成數據的發送和接收,函原型如下表所示。使tx 和 rx 函數時,尤其要注意從機地址 address,函數接收的是 7位地址,函數內部會自己加上讀寫位。因此如果某個 I2C 接口設備提供的是 8位地址,我們需要提取出 7位地址賦值給address,也就是去掉 8位地址的最低(R/W位)。

nRF52832藍牙芯片的所有I2C 通信都是通過這兩個函數接口。不需要自己去重寫I2C驅動函數。

 

3.5.1 TWI發送函數模型:nrf_drv_twi_tx()

                                   函數原型

   STATIC_INLINE ret_code_t nrf_drv_twi_tx (nrf_drv_twi_t const *                                 p_instance, uint8_t                         address,

uint8_t const *             p_data,

uint8_t                         length,

bool                             no_stop)

函數功能

向 TWI 從機發送數據,發生錯誤時將停止傳輸。 如果傳輸正在進行,則該函數返回錯誤代碼 NRF_ERROR_BUSY。

參         數

[in] p_instance:指向 TWI 驅動程序實例結構體。

[in] address:指定的從機地址(7 位 LSB)。 [in] p_data:指向傳輸數據緩存。

[in] length:發送的字節數。

[in] no_stop:如果置位,成功傳輸後總線上不會生成停止條件(允許在

下一次傳輸中重複啓動)。

返回值

NRF_SUCCESS:發送成功。

NRF_ERROR_BUSY:驅動程序尚未準備好進行新的傳輸。NRF_ERROR_INTERNAL:硬件檢測到錯誤。NRF_ERROR_INVALID_ADDR:使用了 EasyDMA,但是緩存地址沒有位於RAM 空間。

NRF_ERROR_DRV_TWI_ERR_ANACK:在輪詢模式下發送地址後收到NAC。

NRF_ERROR_DRV_TWI_ERR_DNACK:在輪詢模式下發送數據後收到

NACK。

 

 

3.5.2 TWI接收函數模型:nrf_drv_twi_rx()

 
 

函數原型

    STATIC_INLINE ret_code_t nrf_drv_twi_rx (

nrf_drv_twi_t const *    p_instance, uint8_t                         address,

uint8_t *                      p_data,

uint8_t                         length

)

函數功能

從 TWI 從機讀取數據,發生錯誤時將停止傳輸。如果傳輸正在進行,則該函數返回錯誤代碼 NRF_ERROR_BUSY。

參         數

[in] p_instance:指向 TWI 驅動程序實例結構體。

 

 

 

 

 

 

 

 

 

返回值

[in] address:指定的從機地址(7 位 LSB)。 [in] p_data:指向接收數據緩存。

[in] length:讀取的字節數。

返回值

NRF_SUCCESS:發送成功。

NRF_ERROR_BUSY:驅動程序尚未準備好進行新的傳輸。NRF_ERROR_INTERNAL:硬件檢測到錯誤。NRF_ERROR_DRV_TWI_ERR_OVERRUN:接收數據未及時讀取,被新接收的數據覆蓋。

NRF_ERROR_DRV_TWI_ERR_ANACK:在輪詢模式下發送地址後收到NAC。

NRF_ERROR_DRV_TWI_ERR_DNACK:在輪詢模式下發送數據後收到

NACK。

3.5 I2C 設備掃描

    爲什麼要掃描設備?通過掃描I2C 設備,可以確認設備是否正常工作,以及設備接入是否正常等,還可以通過打印信息,確認設備的 I2C 地址。

/* Number of possible TWI addresses. */

#define TWI_ADDRESSES      127



void iic_scan_address(void)

{

    ret_code_t err_code;

    uint8_t address;

    uint8_t sample_data;

bool detected_device = false;



    NRF_LOG_INFO("TWI scanner started.");

    NRF_LOG_FLUSH();

    twi_init();//twi init



    for (address = 1; address <= TWI_ADDRESSES; address++)

    {

        err_code = nrf_drv_twi_rx(&m_twi, address, &sample_data, sizeof(sample_data));

        if (err_code == NRF_SUCCESS)

        {

            detected_device = true;

            NRF_LOG_INFO("TWI-i2c device detected at address 0x%x.", address);

        }

        NRF_LOG_FLUSH();

    }



    if (!detected_device)

    {

        NRF_LOG_INFO("No device was found.");

        //NRF_LOG_FLUSH();

    }

        NRF_LOG_INFO("TWI device scan ended.");

        NRF_LOG_FLUSH();



}

 

I2C設備掃描的Log信息:

    由於我的I2C 總線上掛了兩個設備:

0x3C爲 0.96寸oled屏幕的I2C地址,

0x44爲,SHT35溫溼度傳感器的I2C地址。

                      

 

 

第4部分 SHT3x代碼移植到Nordic藍牙芯片:

由於Nordic藍牙芯片的I2C接口與STM32有稍微不同。本文將基於官方給的STM32代碼,通過修改,移植到nRF52832藍牙芯片上。

通過掃描,我知道我的SHT35溫溼度傳感器的I2C地址爲0x44。當然也可以通過手冊得知。掃描只是爲了確認沒錯。

 

4.1 寫SHT35寄存器函數

    這個函數非常重要,由於SHT35的命令都是16位,而nrf_drv_twi_tx()函數中,數據定義的是8位。所以關鍵點就在code中。

 

static uint8_t tx_buf[2];

tx_buf[0] = (uint8_t)(cmd>>8);  //8位放在buf0

tx_buf[1] = (uint8_t)(cmd & 0xFF);  //8位放在buf1

 

static etError  SHT3x_WriteCommand(uint16_t cmd)

{

        ret_code_t err_code;

        static uint8_t tx_buf[2];

        tx_buf[0] = (uint8_t)(cmd>>8);  //低8位

        tx_buf[1] = (uint8_t)(cmd & 0xFF);  //高8位

    //TWI傳輸完成標誌設置爲false

        //m_xfer_done = false;

        uint8_t retry_num = 20;

        do{

          err_code = nrf_drv_twi_tx(&m_twi, SHT35_ADDRESS, tx_buf, 2, false);

            APP_ERROR_CHECK(err_code);

            retry_num--;

            //等待TWI總線應答

            //UNUSED_VARIABLE(err_code);

            }

        while((NRF_SUCCESS != err_code) && (0 < retry_num));

   

        //返回寫入成功

        return NO_ERROR;

}  

 

4.2 週期測量模式

//發送命令,週期測量模式,測量頻率1Hz

void SHT3X_SetPeriodicMeasurement(void)

{

    SHT3x_WriteCommand(CMD_MEAS_PERI_2_H);

    NRF_LOG_INFO("cmd_meas_peri_2_h");

    NRF_LOG_FLUSH();

}

 

4.3 讀取溫溼度數據

//讀取溫溼度數據,函數中會校驗數據

etError SHX3X_ReadMeasurementBuffer(float* temperature, float* humidity)

{

    etError error;

    ret_code_t err_code;

    static uint8_t  bytes[6];

    //寫入命令

    SHT3x_WriteCommand(CMD_FETCH_DATA); //0xE000,readout measurements for periodic mode

    //讀出溫溼度數據

    //m_xfer_done = false;

    //嘗試20次

    uint8_t retry_num = 20;

        do{

          err_code = nrf_drv_twi_rx(&m_twi, SHT35_ADDRESS, bytes, 6);

            APP_ERROR_CHECK(err_code);

            retry_num--;

            //等待TWI總線應答

            //UNUSED_VARIABLE(err_code);

            }

        while((NRF_SUCCESS != err_code) && (0 < retry_num));

    //while (m_xfer_done == false){};

    //校驗溫溼度數據

    error = SHT3X_CheckCrc(bytes, 2, bytes[2]);

    if(error == NO_ERROR)

  {

    *temperature = SHT3X_CalcTemperature((bytes[0] << 8) | bytes[1]);

    *humidity = SHT3X_CalcHumidity((bytes[3] << 8) | bytes[4]);

  }    

    return NO_ERROR;

}

 

4.4 CRC校驗

//------------------------------CRC校驗和驗證------------------------

// Generator polynomial for CRC

#define POLYNOMIAL  0x131 // P(x) = x^8 + x^5 + x^4 + 1 = 100110001

 

//CRC校驗

static uint8_t SHT3X_CalcCrc(uint8_t data[], uint8_t nbrOfBytes)

{

  uint8_t bit;        // bit mask

  uint8_t crc = 0xFF; // calculated checksum

  uint8_t byteCtr;    // byte counter

  //用給定的多項式計算8位校驗和

  for(byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++)

  {

    crc ^= (data[byteCtr]);

    for(bit = 8; bit > 0; --bit)

    {

      if(crc & 0x80) crc = (crc << 1) ^ POLYNOMIAL;

      else           crc = (crc << 1);

    }

  }

 

  return crc;

}

 

//檢驗校驗是否正確

 

static etError SHT3X_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)

{

  uint8_t crc;     // calculated checksum

  //計算8位校驗和

  crc = SHT3X_CalcCrc(data, nbrOfBytes);

  //驗證校驗

  if(crc != checksum)

        return CHECKSUM_ERROR;

  else               

        return NO_ERROR;

}

 

 

4.5 溫溼度計算

//------------------------計算溫溼度---------------------------------

/**

 * 描述 : 計算溫度

 * 入參: rawValue:讀取的溫度信息

 * 返回值 : 計算出的溫度

 **/

static float SHT3X_CalcTemperature(uint16_t rawValue)

{

  //T = -45 + 175 * rawValue / (2^16-1)

    float temperature = 175.0f * (float)rawValue / 65535.0f - 45.0f;

  return temperature;

}

/**

* 描述 : 計算溼度[%RH]

 * 入參: dat :讀取的溼度信息

 * 返回值 : 計算出的溼度值

***/

static float SHT3X_CalcHumidity(uint16_t rawValue)

{

  // 計算相對溼度[%RH]

  // RH = rawValue / (2^16-1) * 100

    float huminity = 100.0f * (float)rawValue / 65535.0f;

     return huminity;

}

 

4.6 測試溫溼度

    先設置測量模式,再讀取數據。

//-----------------------溫溼度測試程序---------------------------------------

void sht35_c_test(void){

 

    NRF_LOG_INFO("sht35_c_test start..,measure the temperature and humidity");

    NRF_LOG_FLUSH();

   

        float   temperature; // ??

        float   humidity;    // ?? [%RH]

 

    //週期測量模式1HZ

    SHT3X_SetPeriodicMeasurement();

    nrf_delay_ms(50);

    //while(true)

    //  {

        SHX3X_ReadMeasurementBuffer(&temperature, &humidity);

        NRF_LOG_INFO("temperature:%d `C",temperature);

        NRF_LOG_INFO("humidity   :%d RH",humidity);

        NRF_LOG_FLUSH();   

    //測量頻率設置1Hz,因此讀取間隔不能小於1s

        nrf_delay_ms(1200);

    //  }

}

 

測試結果:

                          

 

用4pin的I2C OLED屏幕顯示溫溼度:

                          

 

5.結語

    下一章,介紹nRF52832上點亮4pin 0.96寸I2C的OLED屏幕。

 

白浪介紹:

(1)關於射頻、微波、天線、無線通信、智能硬件、軟件編程、滲透安全、人工智能、區塊鏈,Java、Android、C/C++、python等綜合能力的培養提升。

(2)各種學習資料、學習軟件分享。

1.掃碼關注公衆號(Geekxiaobai)

                                        

2. 在後臺發送“Python高級編程”“Python Graphics”或者“2003”,即可免費獲得電子書籍。僅供學習之用。

3. 掃碼關注後,查看往期內容,會有更多資料驚喜等着你來拿哦  

  想要更多相關學習資料,可以在公衆號留言哦。

========******=========******========******=========******==========

發佈了31 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章