2025年1月30日 星期四

溫濕度感測器實作 – NSHT30數位式溫濕度感測器

 溫濕度感測器實作 – NSHT30數位式溫濕度感測器

電路圖

 

程式列表

MicroPython - NSHT30.py

"""

  NSHT30

  Number Name

  ------------

   6      VCC

   5

   4      AL

   3      SDA

   2      SCL

   1      GND

  ------------

"""

 

from machine import Pin, I2C

import utime

 

NSHT30_I2C_ADDRESS = 0x44 # I2C address B 0x44 ADDR (pin 2) connected to GND

# NSHT30_I2C_ADDRESS = 0x45 # I2C address B 0x45 ADDR (pin 2) connected to VDD

 

class NSHT30:

  """

  NSHT30 sensor driver in pure python based on I2C bus

  """

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

 

  ALERT_PENDING_MASK = 0x8000 # 15

  HEATER_MASK        = 0x2000 # 13

  RH_ALERT_MASK      = 0x0800 # 11

  T_ALERT_MASK       = 0x0400 # 10

  RESET_MASK         = 0x0010 # 4

  CMD_STATUS_MASK    = 0x0002 # 1

  WRITE_STATUS_MASK  = 0x0001 # 0

 

  #NSHT30驅動代碼

  MEAS_SINGLE_H_CMD  = b'\x24\x00' # measurement: SINGLE Mode high repeatability

  MEAS_SINGLE_M_CMD  = b'\x24\x0B' # measurement: SINGLE Mode medium repeatability

  MEAS_SINGLE_L_CMD  = b'\x24\x16' # measurement: SINGLE Mode low repeatability

  MEAS_PERI_05_H_CMD = b'\x20\x32' # measurement: periodic Mode 0.5 mps high repeatability

  MEAS_PERI_05_M_CMD = b'\x20\x24' # measurement: periodic Mode 0.5 mps medium repeatability

  MEAS_PERI_05_L_CMD = b'\x20\x2F' # measurement: periodic Mode 0.5 mps low repeatability

  MEAS_PERI_1_H_CMD  = b'\x21\x30' # measurement: periodic Mode 1 mps high repeatability

  MEAS_PERI_1_M_CMD  = b'\x21\x26' # measurement: periodic Mode 1 mps medium repeatability

  MEAS_PERI_1_L_CMD  = b'\x21\x2D' # measurement: periodic Mode 1 mps low repeatability

  MEAS_PERI_2_H_CMD  = b'\x22\x36' # measurement: periodic Mode 2 mps high repeatability

  MEAS_PERI_2_M_CMD  = b'\x22\x20' # measurement: periodic Mode 2 mps medium repeatability

  MEAS_PERI_2_L_CMD  = b'\x22\x2B' # measurement: periodic Mode 2 mps low repeatability

  MEAS_PERI_4_H_CMD  = b'\x23\x34' # measurement: periodic Mode 4 mps high repeatability

  MEAS_PERI_4_M_CMD  = b'\x23\x22' # measurement: periodic Mode 4 mps medium repeatability

  MEAS_PERI_4_L_CMD  = b'\x23\x29' # measurement: periodic Mode 4 mps low repeatability

  MEAS_PERI_10_H_CMD = b'\x27\x37' # measurement: periodic Mode 10 mps high repeatability

  MEAS_PERI_10_M_CMD = b'\x27\x21' # measurement: periodic Mode 10 mps medium repeatability

  MEAS_PERI_10_L_CMD = b'\x27\x2A' # measurement: periodic Mode 10 mps low repeatability

  PERIODIC_MODE_READ_CMD = b'\xE0\x00'

  PERIODIC_MODE_BREAK_CMD = b'\x30\x93'

 

  STATUS_CMD = b'\xF3\x2D'

  RESET_CMD = b'\x30\xA2'

  CLEAR_STATUS_CMD = b'\x30\x41'

  ENABLE_HEATER_CMD = b'\x30\x6D'

  DISABLE_HEATER_CMD = b'\x30\x66'

 

  HAL_OK = 0

  HAL_ERROR = 1

 

  def __init__(self, i2c=None, i2c_address=None):

    # construct an I2C bus

    if i2c is None:

      i2c = I2C(0,I2C.MASTER,baudrate=100000)     #Create I2C0 Master Mode, Baudrate=100kHz

    if i2c_address is None:

      i2c_address = 0x44

    self.i2c = i2c

    self.i2c_addr = i2c_address

    utime.sleep_ms(50)

 

  def is_present(self):

    """

    Return true if the sensor is correctly conneced, False otherwise

    """

    return self.i2c_addr in self.i2c.scan()

 

  def _check_crc(self, data):

    # calculates 8-Bit checksum with given polynomial

    crc = 0xFF

 

    for b in data[:-1]:

      crc ^= b

      for _ in range(8, 0, -1):

        if crc & 0x80:

          crc = (crc << 1) ^ NSHT30.POLYNOMIAL

        else:

          crc <<= 1

    crc_to_check = data[-1]

    return crc_to_check == crc

 

  def send_cmd(self, cmd_request, response_size=6, read_delay_ms=100):

    """

    Send a command to the sensor and read (optionally) the response

    The responsed data is validated by CRC

    """

    try:

      self.i2c.send(cmd_request, self.i2c_addr)  # write the given buffer to the peripheral

      if not response_size:

        return

      data =  bytearray(response_size) #

      utime.sleep_ms(read_delay_ms)

      self.i2c.recv(data,self.i2c_addr)

 

      for i in range(response_size//3):

        if not self._check_crc(data[i*3:(i+1)*3]):  # pos 2 and 5 are CRC

          raise NSHT30Error(SHT30Error.CRC_ERROR)

      if data == bytearray(response_size):

        raise NSHT30Error(SHT30Error.DATA_ERROR)

      return data

    except OSError:

      raise NSHT30Error(SHT30Error.BUS_ERROR)

    except Exception as ex:

      raise ex

 

  def clear_status(self):

    """

    Clear the status register

    """

    return self.send_cmd(NSHT30.CLEAR_STATUS_CMD, None)

 

  def reset(self):

    """

    Send a soft-reset to the sensor

    """

    return self.send_cmd(NSHT30.RESET_CMD, None)

 

  def status(self, raw=False):

    """

    Get the sensor status register.

    It returns a int value or the bytearray(3) if raw==True

    """

    data = self.send_cmd(NSHT30.STATUS_CMD, 3, read_delay_ms=20)

 

    if raw:

      return data

 

    status_register = data[0] << 8 | data[1]

    return status_register

 

  def measure(self, cmd, read_delay_ms=100, raw=False):

    """

    If raw==True returns a bytearrya(6) with sensor direct measurement otherwise

    It gets the temperature (T) and humidity (RH) measurement and return them.

 

    The units are Celsius and percent

    """

    if cmd is None:

      cmd = NSHT30.MEAS_SINGLE_L_CMD

    data = self.send_cmd(cmd, 6, read_delay_ms) # read 6 bytes

 

    if raw:

      return data

 

    t_celsius = (((data[0] << 8 | data[1]) * 175) / 0xFFFF) - 45

    rh = (((data[3] << 8 | data[4]) * 100.0) / 0xFFFF)

    return t_celsius, rh

 

class NSHT30Error(Exception):

  """

  Custom exception for errors on sensor management

  """

  BUS_ERROR = 0x01

  DATA_ERROR = 0x02

  CRC_ERROR = 0x03

 

  def __init__(self, error_code=None):

    self.error_code = error_code

    super().__init__(self.get_message())

 

  def get_message(self):

    if self.error_code == NSHT30Error.BUS_ERROR:

      return "Bus error"

    elif self.error_code == NSHT30Error.DATA_ERROR:

      return "Data error"

    elif self.error_code == NSHT30Error.CRC_ERROR:

      return "CRC error"

    else:

      return "Unknown error"

 

MicroPython - NSHT30_main.py

"""

            NSHT30

  ePy-Lite  Number Name

  -------------------------

  3V3        6      VCC

             5

             4      AL

  P16_SDA0   3      SDA

  P17_SCL0   2      SCL

  GND        1      GND

  -------------------------

"""

 

from machine import Switch  #Get button KEY library

from machine import Pin, LED, I2C ,UART

import utime

from NSHT30 import NSHT30

 

BLEOUT = False

DEBUG = True

KeyADone = None

 

I2C_FREQ = 100000

 

NSHT30_I2C_ADDRESS = 0x44 # I2C address B 0x44 ADDR (pin 2) connected to GND

# NSHT30_I2C_ADDRESS = 0x45 # I2C address B 0x45 ADDR (pin 2) connected to VDD

 

INTERVAL = 5000  # millisecond

 

def key_int():

  global KeyADone

  KeyADone = True

 

# Start Function

if __name__ == '__main__':

  ledY = LED('ledy')

  ledR = LED('ledr')

  ledY.off()

  ledR.off()

 

  KeyA = Switch('keya')    # Create button A

  KeyA.callback(key_int)

  KeyADone = False

 

  i2c = I2C(0,I2C.MASTER,baudrate=I2C_FREQ)     # Create I2C0 Master Mode, Baudrate=100kHz

  sensor = NSHT30(i2c)

 

  if(BLEOUT):

    ble = UART(1,115200)

    ble.write('AT+MODE_DATA\r\n')

 

  utime.sleep(2)

  print("Start humidity measurement.")

  lastTime=0

  while True:

    currTime = utime.ticks_ms()

    if (currTime - lastTime > INTERVAL):

      lastTime = currTime

      ledY.toggle()

      temperature, humidity = sensor.measure(sensor.MEAS_SINGLE_L_CMD)

      print('Temperature: %.2f*C, Humidity: %.2f%%' %(temperature,humidity))

      if(BLEOUT):

        ble.write('T = {}*C, H = {}%\r\n'.format (temperature,humidity))

      ledY.toggle()

 

    if KeyADone == True:      # Press A Key

      break

 

  if(BLEOUT):

    ble.deinit()

  i2c.deinit() # close the connection to the module

  KeyA.callback(None)

  print("Exit humidity measurement.")

 

執行結果

Thonny訊息列表

 

LightBlue APP畫面

 

 

參考文獻

l   溫濕度感測器NSHT30使用設計指南(AN-12-0010) - https://www.novosns.com/files/ApplicationNote_wenshiduchuanganqiNSHT30shiyongshejizhinan.pdf

 

沒有留言:

張貼留言