Raspberry Pi Pico BME680 Máy chủ web với MicroPython

Raspberry Pi Pico BME680 Máy chủ web với MicroPython

Giới thiệu BME680

BME680 là cảm biến bốn trong một điều khiển năng lượng thấp, được tích hợp cảm biến nhiệt độ, áp suất, độ ẩm và phát hiện khí. Nó chạy trên điện áp hoạt động 1,8-3,8V và giao tiếp với các vi điều khiển khác thông qua giao thức I2C và SPI. Cảm biến này được sử dụng trong các lĩnh vực như theo dõi chất lượng không khí, chỉ báo độ ẩm, xu hướng thời tiết, tự động hóa và điều khiển gia đình và cải tiến GPS.

Phạm vi hoạt động và độ chính xác

Một số tính năng chính của BME680 bao gồm:

  • Đo nhiệt độ: đo nhiệt độ môi trường xung quanh với độ chính xác ± 1,0 ° C và phạm vi hoạt động từ -40 đến 85 ºC.

  • Đo độ ẩm tương đối: đo độ ẩm tương đối với tốc độ phản ứng nhanh và độ chính xác ±3% và phạm vi hoạt động từ 0-100%.

  • Đo áp suất: đo áp suất khí quyển với độ chính xác và độ cao tuyệt đối ±1 hPa với độ chính xác ±1 mét. Phạm vi hoạt động của áp suất dao động từ 300-1100 hPa.

  •  

Chính xác

Phạm vi hoạt động

Nhiệt độ

±1,0 °C

-40 đến 85 ºC

Độ ẩm

±3%

0-100%

Áp lực

±1 hPa

300-1100 hPa

  • Đo khí: phát hiện một loạt các loại khí bao gồm các hợp chất hữu cơ dễ bay hơi (VOC) do đó xác định chất lượng không khí trong nhà.

  • Do kích thước nhỏ gọn và hoạt động năng lượng thấp, nó phù hợp trong các ứng dụng di động, đồng hồ thông minh và hệ thống định vị.

So với BME280, BME680 là một cảm biến độc đáo và được cập nhật theo nghĩa là nó chứa cảm biến MOX (oxit kim loại) kích thước nhỏ.

Cảm biến khí

Cảm biến BME680 có thể xác định số lượng chất ô nhiễm/VOC trong môi trường như carbon monoxide, Ethane, Isopren/2-methyl-1,3 Butadiene, Acetone và Ethanol. Các VOC được phát hiện bằng sự hấp phụ của các phân tử oxy vào lớp oxit kim loại. Phát hiện thực tế của nó được thực hiện theo nguyên tắc thay đổi điện trở của cảm biến MOX. Bất cứ khi nào MOX tiếp xúc với chất ô nhiễm trong không khí, điện trở của cảm biến sẽ thay đổi theo nồng độ của các chất ô nhiễm có mặt. Điều này có nghĩa là số lượng chất ô nhiễm trong không khí cao hơn dẫn đến điện trở của cảm biến thấp hơn đáng kể. Tương tự như vậy, với nồng độ VOC trong không khí thấp hơn, điện trở của cảm biến cao hơn đáng kể.

Đầu ra và hoạt động điện trở của cảm biến khí BME680

Lưu ý: Cảm biến khí BME680 không phải là cảm biến đo CO2 hoặc ethanol. Nó có ý tưởng tương đối về CO2 từ VOC trong không khí Nhưng chúng ta không thể sử dụng nó để đo trực tiếp CO2.

Giống như tất cả các cảm biến khí khác, BME680 cũng cho kết quả thay đổi mỗi lần. Để đảm bảo độ chính xác cao hơn, chúng ta phải hiệu chỉnh nó với một nguồn đã biết và sau đó vẽ đường cong của nó. Vì mức độ nhạy không phải là hằng số trong quá trình sử dụng cảm biến ban đầu, ban đầu nên chạy nó trong bốn mươi tám giờ, sau đó có thể được điều chỉnh xuống ba mươi phút trước mỗi lần sử dụng.

Mô-đun BME680

Một số loại cảm biến BME680 với các kích cỡ và số lượng thiết bị đầu cuối khác nhau có sẵn trên thị trường. Nhưng tất cả các mô-đun đều cung cấp dữ liệu thông qua giao diện  và chúng ta có thể sử dụng cùng một tập lệnh MicroPython để có được số đọc cảm biến. Một số trong số chúng được hiển thị dưới đây:

Bạn có thể chọn mô-đun tùy theo sự tiện lợi của bạn và loại vi điều khiển bạn muốn kết nối nó. Trong bài viết này, chúng tôi sẽ sử dụng cảm biến BME680 với 6 thiết bị đầu cuối, được hiển thị bên dưới. Nó có 4 thiết bị đầu cuối SPI và 2 I2C.

Các mô-đun cảm biến BME680 khác nhau

Sơ đồ sơ đồ chân

Hình dưới đây cho thấy sơ đồ chân của cảm biến BME680:

Sơ đồ chân BME680

Tên pin

Mô tả:__________

VCC

Chân này cấp nguồn cho cảm biến.

GND ·

Đây là chân nối đất chung cho nguồn điện và logic.

SCL

Khi sử dụng giao thức I2C, chân này hoạt động như SCL hoặc chân đồng hồ nối tiếp và khi sử dụng giao thức SPI, chân này hoạt động như SCK hoặc chân nối tiếp cho SPI. Nó là đầu vào cho chip.

SDA

Khi sử dụng giao thức I2C, chân này hoạt động như chân SDA hoặc Serial Data và khi sử dụng giao thức SPI, chân này hoạt động như SDI hoặc Dữ liệu nối tiếp Còn được gọi là MOSI ('Làm chủ nô lệ trong'). Điều này được sử dụng làm đầu vào I2C / SPI cho cảm biến.

LAM

Đây là chân SDO (Slave data out) / MISO (Master in slave out) để giao tiếp SPI. Chân này được sử dụng làm đầu ra SPI từ cảm biến.

.CS

Đây là chân Chip Select được sử dụng trong giao tiếp SPI. Hoạt động như một đầu vào cho cảm biến.

Giao diện Raspberry Pi Pico với BME680 và ESP-01

Raspberry Pi Pico với sơ đồ kết nối BME680 và ESP-01

Phần này hướng dẫn cách kết nối Raspberry Pi Pico với cảm biến BME680 và ESP-01.

Chúng tôi sẽ yêu cầu các thành phần sau:

  • Raspberry Pi Pico

  • Cảm biến BME680

  • Mô-đun ESP-01

  • Dây kết nối

  • Breadboard

Raspberry Pi Pico với BME680

Như đã thảo luận trước đó, BME680 cung cấp hai giao diện như I2C và SPI. Chúng ta có thể sử dụng giao diện SPI hoặc I2C để kết nối cảm biến với Raspberry Pi Pico. SPI yêu cầu bốn chân để giao tiếp. Ngược lại, I2C yêu cầu hai chân. Do đó, chúng tôi sẽ sử dụng giao diện I2C cho bài viết này.

Kết nối của BME680 với Raspberry Pi Pico rất đơn giản. Chúng ta phải kết nối thiết bị đầu cuối VCC với 3.3V, nối đất với mặt đất (mặt bằng chung), SCL của cảm biến với SCL của bo mạch và SDA của cảm biến với chân SDA của bo mạch.

Raspberry Pi Pico Chân I2C

Raspberry Pi Pico có hai bộ điều khiển. Cả hai bộ điều khiển I2C đều có thể truy cập thông qua các chân GPIO của Raspberry Pi Pico. Bảng sau đây cho thấy kết nối của các chân GPIO với cả hai bộ điều khiển I2C. Mỗi kết nối của bộ điều khiển có thể được cấu hình thông qua nhiều chân GPIO như trong hình. Nhưng trước khi sử dụng bộ điều khiển I2C, bạn nên định cấu hình trong phần mềm chân GPIO nào bạn muốn sử dụng với bộ điều khiển I2C cụ thể.

Bộ điều khiển I2C

Chân GPIO

I2C0 - SDA

GP0 / GP4 / GP8 / GP12 / GP16 / GP20

I2C0 - SCL

GP1 / GP5 / GP9 / GP13 / GP17 / GP21

I2C1 - SDA

GP2 / GP6 / GP10 / GP14 / GP18 / GP26

I2C1 - SCL

GP3 / GP7 / GP11 / GP15 / GP19 / GP27

Các kết nối giữa hai thiết bị mà chúng tôi đang sử dụng có thể được nhìn thấy bên dưới.

BME680 ·

Quả mâm xôi Pi Pico

VCC

3.3V

SDA

GP2 (I2C1 SDA)

SCL

GP3 (I2C1 SCL)

GND ·

GND ·

Chúng tôi đã sử dụng các kết nối tương tự như được chỉ định trong bảng trên. Tuy nhiên, bạn cũng có thể sử dụng các kết hợp chân SDA / SCL khác nhưng hãy nhớ thay đổi chúng trong tập lệnh MicroPython.

Raspberry Pi Pico với ESP-01

Mô-đun ESP-01 bao gồm 8 chân. Tuy nhiên, chúng tôi sẽ sử dụng 5 chân để kết nối với bảng Pi Pico. Chúng bao gồm các chân VCC, EN, GND, RX và TX. Các chân RX và TX của mô-đun sẽ được kết nối với các chân UART của bảng Pi Pico. Trước tiên chúng ta hãy xem xét các Chân Raspberry Pi Pi UART.

Chân Raspberry Pi Pico UART

Raspberry Pi Pico chứa hai thiết bị ngoại vi giống hệt nhau với các FIFOs 32×8 Tx và 32×12 Rx riêng biệt.

Bảng sau liệt kê các chân GPIO cho cả hai thiết bị ngoại vi UART được tiếp xúc trên sơ đồ chân của bảng phát triển Raspberry Pi Pico.

Chân UART

Chân GPIO

UART0-TX

GP0 / GP12 / GP16

UART0-RX

GP1 / GP13 / GP17

UART1-TX

GP4/GP8

UART1-RX

GP5/GP9

Đối với hướng dẫn này, chúng tôi sẽ sử dụng chân UART0-TX và RX.

Làm theo sơ đồ kết nối bên dưới để kết nối hai thiết bị.

Raspberry Pi Pico

ESP-01 ·

3.3V

VCC

3.3V

EN

GND ·

GND ·

GP1 (UART0 RX)

TX

GP0 (UART0 TX)

RX

Sơ đồ kết nối Raspberry Pi Pico với BME680 và ESP-01

Chúng tôi đã sử dụng các kết nối tương tự như được đưa ra trong hai bảng trên. Cả ba thiết bị sẽ được nối đất chung và sẽ được cấp nguồn bằng cùng một chân 3.3V của Raspberry Pi Pico.

Sơ đồ dưới đây cho thấy sơ đồ kết nối của Raspberry Pi Pico với BME680 và ESP-01.

Raspberry Pi Pico với BME680 và ESP-01

Cài đặt BME680 MicroPython Library

Đối với dự án này, chúng tôi sẽ yêu cầu thư viện MicroPython BME680.

Chúng tôi sẽ sử dụng Thonny IDE để lập trình Raspberry Pi Pico của chúng tôi. Đảm bảo rằng bạn đã cài đặt phiên bản IDE mới nhất trong hệ thống của mình. Mở một tệp mới trong Thonny. Sao chép thư viện được cung cấp dưới đây. Lưu nó vào Raspberry Pi Pico với tên bme680.py trong thư mục lib.

bme680.py

# Spaces, comments and some functions have been removed from the original file to save memory

# Original source: https://github.com/adafruit/Adafruit_CircuitPython_BME680/blob/master/adafruit_bme680.py

import time

import math

from micropython import const

from ubinascii import hexlify as hex

try:

  import struct

except ImportError:

  import ustruct as struct

_BME680_CHIPID = const(0x61)

_BME680_REG_CHIPID = const(0xD0)

_BME680_BME680_COEFF_ADDR1 = const(0x89)

_BME680_BME680_COEFF_ADDR2 = const(0xE1)

_BME680_BME680_RES_HEAT_0 = const(0x5A)

_BME680_BME680_GAS_WAIT_0 = const(0x64)

_BME680_REG_SOFTRESET = const(0xE0)

_BME680_REG_CTRL_GAS = const(0x71)

_BME680_REG_CTRL_HUM = const(0x72)

_BME280_REG_STATUS = const(0xF3)

_BME680_REG_CTRL_MEAS = const(0x74)

_BME680_REG_CONFIG = const(0x75)

_BME680_REG_PAGE_SELECT = const(0x73)

_BME680_REG_MEAS_STATUS = const(0x1D)

_BME680_REG_PDATA = const(0x1F)

_BME680_REG_TDATA = const(0x22)

_BME680_REG_HDATA = const(0x25)

_BME680_SAMPLERATES = (0, 1, 2, 4, 8, 16)

_BME680_FILTERSIZES = (0, 1, 3, 7, 15, 31, 63, 127)

_BME680_RUNGAS = const(0x10)

_LOOKUP_TABLE_1 = (2147483647.0, 2147483647.0, 2147483647.0, 2147483647.0, 2147483647.0,

  2126008810.0, 2147483647.0, 2130303777.0, 2147483647.0, 2147483647.0,

  2143188679.0, 2136746228.0, 2147483647.0, 2126008810.0, 2147483647.0,

  2147483647.0)

_LOOKUP_TABLE_2 = (4096000000.0, 2048000000.0, 1024000000.0, 512000000.0, 255744255.0, 127110228.0,

  64000000.0, 32258064.0, 16016016.0, 8000000.0, 4000000.0, 2000000.0, 1000000.0,

  500000.0, 250000.0, 125000.0)

def _read24(arr):

  ret = 0.0

  for b in arr:

    ret *= 256.0

    ret += float(b & 0xFF)

  return ret

class Adafruit_BME680:

  def __init__(self, *, refresh_rate=10):

    self._write(_BME680_REG_SOFTRESET, [0xB6])

    time.sleep(0.005)

    chip_id = self._read_byte(_BME680_REG_CHIPID)

    if chip_id != _BME680_CHIPID:

      raise RuntimeError('Failed 0x%x' % chip_id)

    self._read_calibration()

    self._write(_BME680_BME680_RES_HEAT_0, [0x73])

    self._write(_BME680_BME680_GAS_WAIT_0, [0x65])

    self.sea_level_pressure = 1013.25

    self._pressure_oversample = 0b011

    self._temp_oversample = 0b100

    self._humidity_oversample = 0b010

    self._filter = 0b010

    self._adc_pres = None

    self._adc_temp = None

    self._adc_hum = None

    self._adc_gas = None

    self._gas_range = None

    self._t_fine = None

    self._last_reading = 0

    self._min_refresh_time = 1000 / refresh_rate

  @property

  def pressure_oversample(self):

    return _BME680_SAMPLERATES[self._pressure_oversample]

  @pressure_oversample.setter

  def pressure_oversample(self, sample_rate):

    if sample_rate in _BME680_SAMPLERATES:

      self._pressure_oversample = _BME680_SAMPLERATES.index(sample_rate)

    else:

      raise RuntimeError("Invalid")

  @property

  def humidity_oversample(self):

    return _BME680_SAMPLERATES[self._humidity_oversample]

  @humidity_oversample.setter

  def humidity_oversample(self, sample_rate):

    if sample_rate in _BME680_SAMPLERATES:

      self._humidity_oversample = _BME680_SAMPLERATES.index(sample_rate)

    else:

      raise RuntimeError("Invalid")

  @property

  def temperature_oversample(self):

      return _BME680_SAMPLERATES[self._temp_oversample]

  @temperature_oversample.setter

  def temperature_oversample(self, sample_rate):

    if sample_rate in _BME680_SAMPLERATES:

      self._temp_oversample = _BME680_SAMPLERATES.index(sample_rate)

    else:

      raise RuntimeError("Invalid")

  @property

  def filter_size(self):

    return _BME680_FILTERSIZES[self._filter]

  @filter_size.setter

  def filter_size(self, size):

    if size in _BME680_FILTERSIZES:

      self._filter = _BME680_FILTERSIZES[size]

    else:

      raise RuntimeError("Invalid")

  @property

  def temperature(self):

    self._perform_reading()

    calc_temp = (((self._t_fine * 5) + 128) / 256)

    return calc_temp / 100

  @property

  def pressure(self):

    self._perform_reading()

    var1 = (self._t_fine / 2) - 64000

    var2 = ((var1 / 4) * (var1 / 4)) / 2048

    var2 = (var2 * self._pressure_calibration[5]) / 4

    var2 = var2 + (var1 * self._pressure_calibration[4] * 2)

    var2 = (var2 / 4) + (self._pressure_calibration[3] * 65536)

    var1 = (((((var1 / 4) * (var1 / 4)) / 8192) *

      (self._pressure_calibration[2] * 32) / 8) +

      ((self._pressure_calibration[1] * var1) / 2))

    var1 = var1 / 262144

    var1 = ((32768 + var1) * self._pressure_calibration[0]) / 32768

    calc_pres = 1048576 - self._adc_pres

    calc_pres = (calc_pres - (var2 / 4096)) * 3125

    calc_pres = (calc_pres / var1) * 2

    var1 = (self._pressure_calibration[8] * (((calc_pres / 8) * (calc_pres / 8)) / 8192)) / 4096

    var2 = ((calc_pres / 4) * self._pressure_calibration[7]) / 8192

    var3 = (((calc_pres / 256) ** 3) * self._pressure_calibration[9]) / 131072

    calc_pres += ((var1 + var2 + var3 + (self._pressure_calibration[6] * 128)) / 16)

    return calc_pres/100

  @property

  def humidity(self):

    self._perform_reading()

    temp_scaled = ((self._t_fine * 5) + 128) / 256

    var1 = ((self._adc_hum - (self._humidity_calibration[0] * 16)) -

      ((temp_scaled * self._humidity_calibration[2]) / 200))

    var2 = (self._humidity_calibration[1] *

      (((temp_scaled * self._humidity_calibration[3]) / 100) +

       (((temp_scaled * ((temp_scaled * self._humidity_calibration[4]) / 100)) /

         64) / 100) + 16384)) / 1024

    var3 = var1 * var2

    var4 = self._humidity_calibration[5] * 128

    var4 = (var4 + ((temp_scaled * self._humidity_calibration[6]) / 100)) / 16

    var5 = ((var3 / 16384) * (var3 / 16384)) / 1024

    var6 = (var4 * var5) / 2

    calc_hum = (((var3 + var6) / 1024) * 1000) / 4096

    calc_hum /= 1000

    if calc_hum > 100:

      calc_hum = 100

    if calc_hum < 0:

      calc_hum = 0

    return calc_hum

  @property

  def altitude(self):

    pressure = self.pressure

    return 44330 * (1.0 - math.pow(pressure / self.sea_level_pressure, 0.1903))

  @property

  def gas(self):

    self._perform_reading()

    var1 = ((1340 + (5 * self._sw_err)) * (_LOOKUP_TABLE_1[self._gas_range])) / 65536

    var2 = ((self._adc_gas * 32768) - 16777216) + var1

    var3 = (_LOOKUP_TABLE_2[self._gas_range] * var1) / 512

    calc_gas_res = (var3 + (var2 / 2)) / var2

    return int(calc_gas_res)

  def _perform_reading(self):

    if (time.ticks_diff(self._last_reading, time.ticks_ms()) * time.ticks_diff(0, 1)

        < self._min_refresh_time):

      return

    self._write(_BME680_REG_CONFIG, [self._filter << 2])

    self._write(_BME680_REG_CTRL_MEAS,

      [(self._temp_oversample << 5)|(self._pressure_oversample << 2)])

    self._write(_BME680_REG_CTRL_HUM, [self._humidity_oversample])

    self._write(_BME680_REG_CTRL_GAS, [_BME680_RUNGAS])

    ctrl = self._read_byte(_BME680_REG_CTRL_MEAS)

    ctrl = (ctrl & 0xFC) | 0x01

    self._write(_BME680_REG_CTRL_MEAS, [ctrl])

    new_data = False

    while not new_data:

      data = self._read(_BME680_REG_MEAS_STATUS, 15)

      new_data = data[0] & 0x80 != 0

      time.sleep(0.005)

    self._last_reading = time.ticks_ms()

    self._adc_pres = _read24(data[2:5]) / 16

    self._adc_temp = _read24(data[5:8]) / 16

    self._adc_hum = struct.unpack('>H', bytes(data[8:10]))[0]

    self._adc_gas = int(struct.unpack('>H', bytes(data[13:15]))[0] / 64)

    self._gas_range = data[14] & 0x0F

    var1 = (self._adc_temp / 8) - (self._temp_calibration[0] * 2)

    var2 = (var1 * self._temp_calibration[1]) / 2048

    var3 = ((var1 / 2) * (var1 / 2)) / 4096

    var3 = (var3 * self._temp_calibration[2] * 16) / 16384

    self._t_fine = int(var2 + var3)

  def _read_calibration(self):

    coeff = self._read(_BME680_BME680_COEFF_ADDR1, 25)

    coeff += self._read(_BME680_BME680_COEFF_ADDR2, 16)

    coeff = list(struct.unpack('<hbBHhbBhhbbHhhBBBHbbbBbHhbb', bytes(coeff[1:39])))

    coeff = [float(i) for i in coeff]

    self._temp_calibration = [coeff[x] for x in [23, 0, 1]]

    self._pressure_calibration = [coeff[x] for x in [3, 4, 5, 7, 8, 10, 9, 12, 13, 14]]

    self._humidity_calibration = [coeff[x] for x in [17, 16, 18, 19, 20, 21, 22]]

    self._gas_calibration = [coeff[x] for x in [25, 24, 26]]

    self._humidity_calibration[1] *= 16

    self._humidity_calibration[1] += self._humidity_calibration[0] % 16

    self._humidity_calibration[0] /= 16

    self._heat_range = (self._read_byte(0x02) & 0x30) / 16

    self._heat_val = self._read_byte(0x00)

    self._sw_err = (self._read_byte(0x04) & 0xF0) / 16

  def _read_byte(self, register):

    return self._read(register, 1)[0]

  def _read(self, register, length):

    raise NotImplementedError()

  def _write(self, register, values):

    raise NotImplementedError()

class BME680_I2C(Adafruit_BME680):

  def __init__(self, i2c, address=0x77, debug=False, *, refresh_rate=10):

    self._i2c = i2c

    self._address = address

    self._debug = debug

    super().__init__(refresh_rate=refresh_rate)

  def _read(self, register, length):

    result = bytearray(length)

    self._i2c.readfrom_mem_into(self._address, register & 0xff, result)

    if self._debug:

      print("\t${:x} read ".format(register), " ".join(["{:02x}".format(i) for i in result]))

    return result

  def _write(self, register, values):

    if self._debug:

      print("\t${:x} write".format(register), " ".join(["{:02x}".format(i) for i in values]))

    for value in values:

      self._i2c.writeto_mem(self._address, register, bytearray([value & 0xFF]))

      register += 1

MicroPython Script Raspberry Pi Pico BME280 Web Server với ESP-01 (Hiển thị nhiệt độ, độ ẩm, khí và áp suất)

import uos

import machine

import utime

from machine import Pin, I2C

from bme680 import *

 

recv_buf="" # receive buffer global variable

 

print()

print("Machine: \t" + uos.uname()[4])

print("MicroPython: \t" + uos.uname()[3])



i2c=I2C(1,sda=Pin(2), scl=Pin(3), freq=400000)    #initializing the I2C method 

bme = BME680_I2C(i2c=i2c)

uart0 = machine.UART(0, baudrate=115200)

print(uart0)

 

def Rx_ESP_Data():

    recv=bytes()

    while uart0.any()>0:

        recv+=uart0.read(1)

    res=recv.decode('utf-8')

    return res

def Connect_WiFi(cmd, uart=uart0, timeout=3000):

    print("CMD: " + cmd)

    uart.write(cmd)

    utime.sleep(7.0)

    Wait_ESP_Rsp(uart, timeout)

    print()

 

def Send_AT_Cmd(cmd, uart=uart0, timeout=3000):

    print("CMD: " + cmd)

    uart.write(cmd)

    Wait_ESP_Rsp(uart, timeout)

    print()

    

def Wait_ESP_Rsp(uart=uart0, timeout=3000):

    prvMills = utime.ticks_ms()

    resp = b""

    while (utime.ticks_ms()-prvMills)<timeout:

        if uart.any():

            resp = b"".join([resp, uart.read(1)])

    print("resp:")

    try:

        print(resp.decode())

    except UnicodeError:

        print(resp)

    

Send_AT_Cmd('AT\r\n')          #Test AT startup

Send_AT_Cmd('AT+GMR\r\n')      #Check version information

Send_AT_Cmd('AT+CIPSERVER=0\r\n')      #Check version information

Send_AT_Cmd('AT+RST\r\n')      #Check version information

Send_AT_Cmd('AT+RESTORE\r\n')  #Restore Factory Default Settings

Send_AT_Cmd('AT+CWMODE?\r\n')  #Query the Wi-Fi mode

Send_AT_Cmd('AT+CWMODE=1\r\n') #Set the Wi-Fi mode = Station mode

Send_AT_Cmd('AT+CWMODE?\r\n')  #Query the Wi-Fi mode again

#Send_AT_Cmd('AT+CWLAP\r\n', timeout=10000) #List available APs

Connect_WiFi('AT+CWJAP="HUAWEI-u67E","4uF77R2n"\r\n', timeout=5000) #Connect to AP

Send_AT_Cmd('AT+CIFSR\r\n',timeout=5000)    #Obtain the Local IP Address

Send_AT_Cmd('AT+CIPMUX=1\r\n')    #Obtain the Local IP Address

utime.sleep(1.0)

Send_AT_Cmd('AT+CIPSERVER=1,80\r\n')    #Obtain the Local IP Address

utime.sleep(1.0)

print ('Starting connection to ESP8266...')

while True:

    res =""

    res=Rx_ESP_Data()

    utime.sleep(2.0)

    if '+IPD' in res: # if the buffer contains IPD(a connection), then respond with HTML handshake

        temperature = str(round(bme.temperature, 2)) + ' C'

        humidity = str(round(bme.humidity, 2)) + ' %'

        pressure = str(round(bme.pressure, 2)) + ' hPa'

        gas = str(round(bme.gas/1000, 2)) + ' KOhms'

        print('Temperature:', temperature)

        print('Humidity:', humidity)

        print('Pressure:', pressure)

        print('Gas:', gas)

        print('-------')

        id_index = res.find('+IPD')

        print("resp:")

        print(res)

        connection_id =  res[id_index+5]

        print("connectionId:" + connection_id)

        print ('! Incoming connection - sending webpage')

        uart0.write('AT+CIPSEND='+connection_id+',1440'+'\r\n')  #Send a HTTP response then a webpage as bytes the 108 is the amount of bytes you are sending, change this if you change the data sent below

        utime.sleep(1.0)

        uart0.write('HTTP/1.1 200 OK'+'\r\n')

        uart0.write('Content-Type: text/html'+'\r\n')

        uart0.write('Connection: close'+'\r\n')

        uart0.write(''+'\r\n')

        uart0.write('<!DOCTYPE HTML>'+'\r\n')

        uart0.write('<html><head>'+'\r\n')

        uart0.write('<title>BME680 Web Server</title>'+'\r\n')

        uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n')

        uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n')

        uart0.write('<link rel=\"icon\" href=\"data:,\">'+'\r\n')

        uart0.write('<style>'+'\r\n')

        uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n')

        uart0.write('p {  font-size: 1.2rem;}'+'\r\n')

        uart0.write('body {  margin: 0;}'+'\r\n')

        uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n')

        uart0.write('.content { padding: 20px; }'+'\r\n')

        uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n')

        uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n')

        uart0.write('.reading { font-size: 2.8rem; }'+'\r\n')

        uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n')

        uart0.write('.card.humidity { color: #17bebb; }'+'\r\n')

        uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n')

        uart0.write('.card.gas { color: #5c055c; }'+'\r\n')

        uart0.write('</style>'+'\r\n')

        uart0.write('</head>'+'\r\n')

        uart0.write('<body>'+'\r\n')

        uart0.write('<div class=\"topnav\">'+'\r\n')

        uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"content\">'+'\r\n')

        uart0.write('<div class=\"cards\">'+'\r\n')

        uart0.write('<div class=\"card temperature\">'+'\r\n')

        uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card humidity\">'+'\r\n')

        uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card pressure\">'+'\r\n')

        uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card gas\">' +'\r\n')

        uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n')

        uart0.write('</div></div></div>'+'\r\n')

        uart0.write('</body></html>'+'\r\n')

        utime.sleep(4.0)

        Send_AT_Cmd('AT+CIPCLOSE='+ connection_id+'\r\n') # once file sent, close connection

        utime.sleep(4.0)

        recv_buf="" #reset buffer

        print ('Waiting For connection...')

Mã hoạt động như thế nào?

Chúng tôi sẽ bắt đầu bằng cách nhập mô-đun máy và mô-đun uos. Chúng tôi cũng sẽ nhập lớp I2C và Pin từ mô-đun máy. Điều này là do chúng tôi phải chỉ định chân cho giao tiếp I2C. Chúng tôi cũng nhập mô-đun utime để chúng tôi có thể thêm độ trễ 10 giây giữa các lần đọc của chúng tôi. Ngoài ra, hãy nhập tất cả các phương thức từ thư viện bme680 mà chúng tôi đã cài đặt trước đó.

import uos

import machine

import utime

from machine import Pin, I2C

from bme680 import *

Sau đó, chúng tôi sẽ in thông tin về hệ điều hành hiện tại của chúng tôi trong thiết bị đầu cuối Thonny shell. Chúng tôi sẽ uos.uname() và in phiên bản hệ điều hành và phát hành.

print()

print("Machine: \t" + uos.uname()[4])

print("MicroPython: \t" + uos.uname()[3])

Khởi tạo giao tiếp I2C

Tiếp theo, chúng tôi sẽ khởi tạo các chân I2C GPIO cho SCL và SDA tương ứng. Chúng tôi đã sử dụng chân I2C1 SCL và I2C0 SDA.

Chúng ta đã tạo ra một phương thức I2C() lấy bốn tham số. Tham số đầu tiên là kênh I2C mà chúng ta đang sử dụng. Tham số thứ hai chỉ định chân I2C GPIO của bo mạch được kết nối với đường SDA. Tham số thứ ba chỉ định chân I2C GPIO của bo mạch được kết nối với dòng SCL. Tham số cuối cùng là kết nối tần số.

Chúng tôi đang đặt SCL trên chân 3 và SDA trên chân 2.

i2c=I2C(1,sda=Pin(2), scl=Pin(3), freq=400000)

Tiếp theo, chúng ta tạo một đối tượng của BME680 có tên bme và chỉ định giao thức truyền thông I2C để đọc dữ liệu từ cảm biến. Điều này sẽ được sử dụng để truy cập các chỉ số cảm biến.

bme = BME680_I2C(i2c=i2c)

Khởi tạo giao tiếp UART

Sau đó, chúng ta sẽ tạo một đối tượng uart bằng cách sử dụng UART() và chỉ định kênh UART làm tham số đầu tiên và tốc độ truyền làm tham số thứ hai. Chúng tôi đang sử dụng UART0 trong trường hợp này với tốc độ truyền 115200 cho giao tiếp uart. ESP8266 có tốc độ truyền mặc định là 115200, do đó chúng tôi sẽ sử dụng cùng một tốc độ truyền ở đây cho giao tiếp Raspberry Pi Pico UART để tạo đồng bộ hóa. Hơn nữa, chúng tôi cũng sẽ in các chi tiết UART trong thiết bị đầu cuối vỏ.

uart0 = machine.UART(0, baudrate=115200)

print(uart0)

Hàm Connect_WiFi() này được sử dụng để kết nối ESP8266 với WiFi.

def Connect_WiFi(cmd, uart=uart0, timeout=3000):

    print("CMD: " + cmd)

    uart.write(cmd)

    utime.sleep(7.0)

    Wait_ESP_Rsp(uart, timeout)

    print()

Tiếp theo, chúng ta sẽ định nghĩa ba hàm. Cái đầu tiên là Rx_ESP_Data(). Điều này đọc dữ liệu nối tiếp đang được nhận. Dữ liệu này được giải mã từ định dạng UTF-8 và được trả về.

def Rx_ESP_Data():

    recv=bytes()

    while uart0.any()>0:

        recv+=uart0.read(1)

    res=recv.decode('utf-8')

    return res

Hàm thứ hai là Send_AT_Cmd(cmd, uart=uart0, timeout=3000). Nó có ba tham số, lệnh AT, kênh UART và thời gian phản hồi. Chức năng này sẽ được sử dụng để nó gửi lệnh AT đến ESP8266 thông qua uart0. Thời gian phản hồi được đặt thành 3 giây.

 

def Send_AT_Cmd(cmd, uart=uart0, timeout=3000):

    print("CMD: " + cmd)

    uart.write(cmd)

    Wait_ESP_Rsp(uart, timeout)

    print()

    

Hàm Wait_ESP_Rsp(uart=uart0, timeout=3000) đợi 3 giây để nhận được phản hồi từ ESP8266. Sau khi nhận được dữ liệu từ ESP8266, nó nối các byte nhận được và in chúng trên thiết bị đầu cuối shell.

def Wait_ESP_Rsp(uart=uart0, timeout=3000):

    prvMills = utime.ticks_ms()

    resp = b""

    while (utime.ticks_ms()-prvMills)<timeout:

        if uart.any():

            resp = b"".join([resp, uart.read(1)])

    print("resp:")

    try:

        print(resp.decode())

    except UnicodeError:

        print(resp)

Lệnh AT

Bây giờ chúng ta hãy xem xét loạt lệnh AT mà chúng ta sẽ gửi qua UART0 đến ESP8266.

Send_AT_Cmd('AT\r\n')          #Test AT startup

Send_AT_Cmd('AT+GMR\r\n')      #Check version information

Send_AT_Cmd('AT+CIPSERVER=0\r\n')      #Check version information

Send_AT_Cmd('AT+RST\r\n')      #Check version information

Send_AT_Cmd('AT+RESTORE\r\n')  #Restore Factory Default Settings

Send_AT_Cmd('AT+CWMODE?\r\n')  #Query the Wi-Fi mode

Send_AT_Cmd('AT+CWMODE=1\r\n') #Set the Wi-Fi mode = Station mode

Send_AT_Cmd('AT+CWMODE?\r\n')  #Query the Wi-Fi mode again

Connect_WiFi('AT+CWJAP="HUAWEI-u67E","4uF77R2n"\r\n', timeout=5000) #Connect to AP

Send_AT_Cmd('AT+CIFSR\r\n',timeout=5000)    #Obtain the Local IP Address

Send_AT_Cmd('AT+CIPMUX=1\r\n')    #Obtain the Local IP Address

utime.sleep(1.0)

Send_AT_Cmd('AT+CIPSERVER=1,80\r\n')    #Obtain the Local IP Address

utime.sleep(1.0)

AT: Loại lệnh này được sử dụng để kiểm tra chức năng khởi động của mô-đun WiFi. Phản hồi sẽ ổn, chống lại lệnh này nếu mọi thứ đều ổn.

Send_AT_Cmd('AT\r\n')          #Test AT startup

AT + GMR : Loại lệnh AT này được sử dụng để kiểm tra phiên bản lệnh AT và chúng tôi đã sử dụng phiên bản SDK của lệnh AT trong loại mô-đun WIFI này.

Send_AT_Cmd('AT+GMR\r\n')      #Check version information

AT + CIPSERVER = 0: Điều này cấu hình ESP8266 làm máy chủ và đặt chế độ là 0, có nghĩa là xóa máy chủ (cần phải làm theo bằng cách khởi động lại)

Send_AT_Cmd('AT+CIPSERVER=0\r\n')     

AT + RST: Loại lệnh này được sử dụng để đặt lại mô-đun WiFi khi nó ở trong tình trạng hoạt động. Phản hồi sẽ ổn, khi đặt lại mô-đun.

Send_AT_Cmd('AT+RST\r\n')   

AT + RESTORE: Loại lệnh này được sử dụng để khôi phục cài đặt gốc có nghĩa là, khi lệnh này được nhập thì tất cả các tham số sẽ tự động được đặt lại về mặc định của một người.

Send_AT_Cmd('AT+RESTORE\r\n')  #Restore Factory Default Settings

AT + CWMODE? : Loại lệnh này được sử dụng để truy vấn chế độ WiFi của ESP8266.

Send_AT_Cmd('AT+CWMODE?\r\n')  #Query the WiFi mode

AT + CWMODE = 1 : Điều này đặt chế độ WiFi của ESP8266 trong trường hợp này ở chế độ trạm.

Send_AT_Cmd('AT+CWMODE=1\r\n') #Set the WiFi mode = Station mode

AT + CWJAP = "SSID", "PASSWORD"\r\n', timeout=TIME_ms : Điều này kết nối ESP8266 với một AP có SSID và mật khẩu được cung cấp, Thời gian chờ ở đây là thời gian kết nối lại.

Connect_WiFi('AT+CWJAP="HUAWEI-u67E","4uF77R2n"\r\n', timeout=5000) #Connect to AP

AT + CIFSR: Lệnh này lấy địa chỉ IP cục bộ.

Send_AT_Cmd('AT+CIFSR\r\n')

AT + CIPMUX = 1: Lệnh này được sử dụng để kích hoạt nhiều kết nối (tối đa 4)

Send_AT_Cmd('AT+CIPMUX=1\r\n')

AT + CIPSERVER = 1: Lệnh này cấu hình ESP8266 làm máy chủ.

Send_AT_Cmd('AT+CIPSERVER=1,80\r\n')

trong khi vòng lặp

Bên trong vòng lặp while, trước tiên chúng ta sẽ gọi Rx_ESP_Data() trả về dữ liệu mà ESP8266 nhận được. Điều này được lưu trong biến 'res.'

Thêm độ trễ 2 giây trước khi tiếp tục.

res =""

res=Rx_ESP_Data()

utime.sleep(2.0)

Tiếp theo, chúng tôi sẽ kiểm tra xem bộ đệm có chứa kết nối IPD hay không. Nếu có, hãy trả lời bằng một cái bắt tay HTML.

Để có được số đọc cảm biến, chúng tôi sẽ sử dụng vật thể "bme" về nhiệt độ, độ ẩm, áp suất và phương pháp khí. Các bài đọc này được lưu trong các biến tương ứng của chúng.

In số đọc cảm biến BME680 cùng với phản hồi trong đầu nối vỏ. Lấy ID kết nối và in nó.

if '+IPD' in res: # if the buffer contains IPD(a connection), then respond with HTML handshake

        temperature = str(round(bme.temperature, 2)) + ' C'

        humidity = str(round(bme.humidity, 2)) + ' %'

        pressure = str(round(bme.pressure, 2)) + ' hPa'

        gas = str(round(bme.gas/1000, 2)) + ' KOhms'

        print('Temperature:', temperature)

        print('Humidity:', humidity)

        print('Pressure:', pressure)

        print('Gas:', gas)

        print('-------')

        id_index = res.find('+IPD')

        print("resp:")

        print(res)

        connection_id =  res[id_index+5]

        print("connectionId:" + connection_id)

Sau đó, bằng cách sử dụng đối tượng uart trên phương thức write(), chúng ta sẽ gửi các byte đến UART. Đầu tiên, chúng tôi đang viết lệnh AT: AT + CIPSEND = 'ID', 'LENGTH' Điều này sẽ đặt độ dài của dữ liệu sẽ được gửi. Tiếp theo sau độ trễ 1 giây, chúng ta sẽ viết nội dung HTML sẽ xây dựng trang web vào cổng nối tiếp. Sau đó, chúng tôi sẽ đóng nhiều kết nối khi chúng tôi đang gửi lệnh AT: AT + CIPCLOSE = 'ID'. Sau đó, chúng tôi sẽ đặt lại bộ đệm và chờ kết nối.

print ('! Incoming connection - sending webpage')

        uart0.write('AT+CIPSEND='+connection_id+',1440'+'\r\n')  #Send a HTTP response then a webpage as bytes the 108 is the amount of bytes you are sending, change this if you change the data sent below

        utime.sleep(1.0)

        uart0.write('HTTP/1.1 200 OK'+'\r\n')

        uart0.write('Content-Type: text/html'+'\r\n')

        uart0.write('Connection: close'+'\r\n')

        uart0.write(''+'\r\n')

        uart0.write('<!DOCTYPE HTML>'+'\r\n')

        uart0.write('<html><head>'+'\r\n')

        uart0.write('<title>BME680 Web Server</title>'+'\r\n')

        uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n')

        uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n')

        uart0.write('<link rel=\"icon\" href=\"data:,\">'+'\r\n')

        uart0.write('<style>'+'\r\n')

        uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n')

        uart0.write('p {  font-size: 1.2rem;}'+'\r\n')

        uart0.write('body {  margin: 0;}'+'\r\n')

        uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n')

        uart0.write('.content { padding: 20px; }'+'\r\n')

        uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n')

        uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n')

        uart0.write('.reading { font-size: 2.8rem; }'+'\r\n')

        uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n')

        uart0.write('.card.humidity { color: #17bebb; }'+'\r\n')

        uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n')

        uart0.write('.card.gas { color: #5c055c; }'+'\r\n')

        uart0.write('</style>'+'\r\n')

        uart0.write('</head>'+'\r\n')

        uart0.write('<body>'+'\r\n')

        uart0.write('<div class=\"topnav\">'+'\r\n')

        uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"content\">'+'\r\n')

        uart0.write('<div class=\"cards\">'+'\r\n')

        uart0.write('<div class=\"card temperature\">'+'\r\n')

        uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card humidity\">'+'\r\n')

        uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card pressure\">'+'\r\n')

        uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card gas\">' +'\r\n')

        uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n')

        uart0.write('</div></div></div>'+'\r\n')

        uart0.write('</body></html>'+'\r\n')

        utime.sleep(4.0)

        Send_AT_Cmd('AT+CIPCLOSE='+ connection_id+'\r\n') # once file sent, close connection

        utime.sleep(4.0)

        recv_buf="" #reset buffer

        print ('Waiting For connection...')

Tạo trang Web (HTML+CSS)

Để xây dựng trang web, chúng tôi sẽ thêm mã HTML và để tạo kiểu, chúng tôi sẽ thêm tập lệnh CSS.

Bây giờ chúng ta hãy đi qua từng dòng mã HTML để hiểu cách nó xây dựng trang web.

Trong tài liệu HTML này, chúng tôi sử dụng thẻ, đoạn văn, tiêu đề và thẻ tiêu đề để tạo một trang web. Trang web này hiển thị các chỉ số về nhiệt độ, độ ẩm, áp suất và khí của cảm biến BME680.

HTML là một ngôn ngữ đánh dấu siêu văn bản được sử dụng để xây dựng các trang web. Tất cả các trình duyệt web đều hiểu ngôn ngữ này và có thể đọc các trang web dựa trên ngôn ngữ HTML.

Trong HTML, chúng tôi đặt tất cả nội dung của một trang web giữa các thẻ <html> và </html>. Thẻ <html> hiển thị phần đầu của một trang web và </html> cho biết sự kết thúc của một trang web.

Mã HTML chủ yếu bao gồm hai phần như đầu và thân. Phần đầu chứa CSS, tập lệnh, thẻ meta, liên kết của các tài nguyên bên ngoài và mã tạo kiểu. Nó được đặt giữa các thẻ <head> và </head>.

uart0.write('<!DOCTYPE HTML>'+'\r\n')

        uart0.write('<html><head>'+'\r\n')

        uart0.write('<title>BME680 Web Server</title>'+'\r\n')

        uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n')

        uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n')

        uart0.write('<link rel=\"icon\" href=\"data:,\">'+'\r\n')

        uart0.write('<style>'+'\r\n')

        uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n')

        uart0.write('p {  font-size: 1.2rem;}'+'\r\n')

        uart0.write('body {  margin: 0;}'+'\r\n')

        uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n')

        uart0.write('.content { padding: 20px; }'+'\r\n')

        uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n')

        uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n')

        uart0.write('.reading { font-size: 2.8rem; }'+'\r\n')

        uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n')

        uart0.write('.card.humidity { color: #17bebb; }'+'\r\n')

        uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n')

        uart0.write('.card.gas { color: #5c055c; }'+'\r\n')

        uart0.write('</style>'+'\r\n')

        uart0.write('</head>'+'\r\n')

Chúng tôi sẽ bắt đầu với tiêu đề của trang web. Thẻ <title> sẽ cho biết phần đầu của tiêu đề và thẻ </title> sẽ cho biết kết thúc. Ở giữa các thẻ này, chúng tôi sẽ chỉ định "Máy chủ web BME680" sẽ được hiển thị trên thanh tiêu đề của trình duyệt.

uart0.write('<title>BME680 Web Server</title>'+'\r\n')

Thẻ meta http-equiv này cung cấp các thuộc tính cho tiêu đề HTTP. Thuộc tính http-equiv lấy nhiều giá trị hoặc thông tin để mô phỏng phản hồi tiêu đề. Trong ví dụ này, chúng tôi sử dụng thuộc tính http-equiv để làm mới nội dung của trang web sau mỗi khoảng thời gian được chỉ định. Người dùng không bắt buộc phải làm mới trang web để nhận các giá trị cảm biến được cập nhật. Dòng này buộc trang HTML tự làm mới sau mỗi 10 giây. Hơn nữa, thẻ meta này sẽ đảm bảo máy chủ web của chúng tôi có sẵn cho tất cả các trình duyệt, ví dụ: điện thoại thông minh, máy tính xách tay, máy tính, v.v.

uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n')

uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n')

Tạo kiểu trang web với CSS

CSS được sử dụng để cung cấp các kiểu cho một trang web. Để thêm các tệp CSS vào thẻ head, chúng tôi sử dụng các thẻ <style></style>. Mã CSS này tạo kiểu cho các thẻ và trang web bằng cách chỉ định màu sắc, phông chữ, kích thước phông chữ, v.v.

Mã CSS này đặt căn chỉnh văn bản, đệm, lề và chiều rộng của các thẻ nội dung của tài liệu HTML cùng với kích thước phông chữ, màu sắc của thẻ, v.v. Chúng tôi muốn hiển thị các chỉ số về nhiệt độ, áp suất, độ ẩm và khí trên thẻ và muốn chúng hiển thị ở vị trí trung tâm của trang web.

        uart0.write('<style>'+'\r\n')

        uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n')

        uart0.write('p {  font-size: 1.2rem;}'+'\r\n')

        uart0.write('body {  margin: 0;}'+'\r\n')

        uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n')

        uart0.write('.content { padding: 20px; }'+'\r\n')

        uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n')

        uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n')

        uart0.write('.reading { font-size: 2.8rem; }'+'\r\n')

        uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n')

        uart0.write('.card.humidity { color: #17bebb; }'+'\r\n')

        uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n')

        uart0.write('.card.gas { color: #5c055c; }'+'\r\n')

        uart0.write('</style>'+'\r\n')

Nội dung trang web HTML

Phần quan trọng thứ hai của tài liệu HTML là phần nội dung đi vào bên trong các thẻ <body> và < / body >. Phần nội dung bao gồm nội dung chính của trang web như tiêu đề, hình ảnh, nút, biểu tượng, bảng, biểu đồ, v.v. Ví dụ: trong máy chủ web dựa trên Raspberry Pi Pico BME680 MicroPython này, phần thân máy bao gồm tiêu đề và bốn thẻ để hiển thị số đọc cảm biến BME680.

        uart0.write('<body>'+'\r\n')

        uart0.write('<div class=\"topnav\">'+'\r\n')

        uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"content\">'+'\r\n')

        uart0.write('<div class=\"cards\">'+'\r\n')

        uart0.write('<div class=\"card temperature\">'+'\r\n')

        uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card humidity\">'+'\r\n')

        uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card pressure\">'+'\r\n')

        uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card gas\">' +'\r\n')

        uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n')

        uart0.write('</div></div></div>'+'\r\n')

        uart0.write('</body></html>'+'\r\n')

Chúng tôi sẽ bao gồm tiêu đề của trang web của chúng tôi bên trong các thẻ <h3>< / h3> và nó sẽ là "Raspberry Pi Pico BME680 WEB SERVER".

uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n')

Tiếp theo, chúng tôi sẽ bao gồm các dòng mã sau để hiển thị văn bản và thẻ để đọc nhiệt độ, áp suất, độ ẩm và khí.

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"content\">'+'\r\n')

        uart0.write('<div class=\"cards\">'+'\r\n')

        uart0.write('<div class=\"card temperature\">'+'\r\n')

        uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card humidity\">'+'\r\n')

        uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card pressure\">'+'\r\n')

        uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n')

        uart0.write('</div>'+'\r\n')

        uart0.write('<div class=\"card gas\">' +'\r\n')

        uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n')

        uart0.write('</div></div></div>'+'\r\n')

Bài viết cùng chuyên mục

NHANH

NHANH

Vì Đổi mới liên tục nên Nhanh hơn

ĐÚNG

ĐÚNG

Coi trọng và ưu tiên việc làm Đúng

ĐỦ

ĐỦ

Tìm và mua Đủ Đơn hàng hơn

KỊP THỜI

KỊP THỜI

Hiệu suất tối ưu bởi Kịp Thời hơn