【Beetle ESP32-C6开发板】网页热成像仪
【Beetle ESP32-C6开发板】网页热成像仪
本文介绍了 Beetle ESP32-C6 开发板结合 MLX90640 模块和 WiFi 基站功能,实现网页热成像仪的项目设计。
项目介绍
准备工作:MLX90640 驱动程序、功能测试等;
硬件连接:使用杜邦线连接传感器模块、USB转TTL工具、RP2350开发板;
工程代码:包括板端执行代码、网页设计代码;
效果演示:运行程序和网页,实现热成像画面帧的实时显示。
MLX90640
MLX90640 是一款高性能的 32x24 像素红外热成像传感器,支持非接触式温度测量,广泛应用于工业监控、智能家居和科研实验等领域。

详见:远红外热传感器阵列(32x24 RES)I Melexis .
模块设计
为了便于设备连接,设计 PCB 模块。

原理图

实物图

这里使用 MLX90640 模块,详见:MLX90640热成像传感器 - 立创开源硬件平台 .
准备工作
包括驱动代码和功能测试。
驱动代码
下载 并上传 mlx90640 驱动代码文件至开发板根目录;
这里使用 uPyPi 开发的 mlx90640 驱动程序;
uPyPi 是类似 PyPI 的 MicroPython 软件包仓库;
uPyPi 是面向 MicroPython 生态的专属包管理中心,旨在简化 MicroPython 库和驱动的发现、共享与部署流程。
详见:FreakStudioCN/upypi: micropython index .
功能测试
运行 Thonny IDE 新建文件,添加如下代码
保存代码。
效果
运行测试代码,终端输出初始化传感器信息、温度统计信息等;

详见: https://upypi.net/en/pkgs/mlx_90640_driver .
硬件连接
包括 MLX90640 模块与 ESP32-C6 开发板的连接。
MLX90640 模块
| ESP32-C6 | MLX90640 module | Note |
|---|---|---|
| SCL (Pin 20) | SCL | Serial Clock |
| SDA (Pin 19) | SDA | Serial Data |
| GND | GND | Ground |
| 3.3V | VCC | Power |
实物图

流程图

工程代码
运行 Thonny IDE 新建文件,添加如下代码
**********代码见底部文件***********
保存代码。
效果演示
运行程序,根据终端提示,获得网页对应地址;
在浏览器地址栏输入 192.168.31.115 打开网页;

网页显示实时热成像帧画面;

==================

改变手势动作,呈现相应效果;

=======

=========

总结
本文介绍了 Beetle ESP32-C6 开发板结合 MLX90640 模块和 WiFi 通信,实现网页热成像仪的项目设计,为相关产品的快速开发和应用设计提供了参考。
from machine import I2C
import time
import network
import socket
from mlx90640 import MLX90640, RefreshRate
# ==================== 配置 ====================
WIFI_SSID = "xxx"
WIFI_PASSWORD = "xxx"
I2C_SCL = 20
I2C_SDA = 19
# ==============================================
temperature_frame = [0.0] * 768
min_temp = 25.0
max_temp = 35.0
# WiFi连接
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print("Connecting WiFi...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
for _ in range(20):
if wlan.isconnected(): break
time.sleep(0.5)
print(".", end="")
if wlan.isconnected():
ip = wlan.ifconfig()[0]
print("\nIP:", ip)
return ip
print("\nWiFi 失败")
return None
# 传感器初始化
def init_sensor():
i2c = I2C(0, scl=I2C_SCL, sda=I2C_SDA, freq=100000)
addr = None
for d in i2c.scan():
if 0x31 <= d <= 0x35:
addr = d
break
if not addr:
print("未找到传感器")
raise SystemExit()
cam = MLX90640(i2c, addr)
cam.refresh_rate = RefreshRate.REFRESH_2_HZ
cam.emissivity = 0.92
print("传感器就绪")
return cam
# 读取一次温度
def read_temp(cam):
global min_temp, max_temp
try:
cam.get_frame(temperature_frame)
min_temp = min(temperature_frame)
max_temp = max(temperature_frame)
except:
pass
# 平滑渐变色
def get_color(temp):
r = (temp - min_temp) / ((max_temp - min_temp) or 1)
if r < 0.2:
return "#0000FF"
elif r < 0.4:
return "#00AFFF"
elif r < 0.6:
return "#00FF80"
elif r < 0.8:
return "#FFDD00"
else:
return "#FF4000"
# 发送顺滑居中的热成像网页
def send_page(conn):
try:
conn.send(b"HTTP/1.1 200 OK\r\n")
conn.send(b"Content-Type: text/html\r\n")
conn.send(b"Cache-Control: no-cache, no-store, must-revalidate\r\n")
conn.send(b"Pragma: no-cache\r\n")
conn.send(b"Expires: 0\r\n")
conn.send(b"Connection: close\r\n\r\n")
# 整体居中、大像素、更平滑的样式
conn.send(b"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>热成像仪</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{
background:#111;
color:#fff;
font-family:Arial;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
min-height:100vh;
padding:10px;
}
.thermal{
display:grid;
grid-template-columns: repeat(32, 8px);
gap:2px;
background:#222;
padding:10px;
border-radius:6px;
margin:12px 0;
}
.pixel{
width:8px;
height:8px;
border-radius:2px;
}
.info{
text-align:center;
margin:8px 0;
font-size:16px;
color:#0ff;
}
a{
color:#ff0;
text-decoration:none;
font-size:16px;
padding:6px 12px;
border:1px solid #ff0;
border-radius:4px;
margin-top:8px;
}
</style>
</head>
<body>
<h3>ESP32-C6 热成像仪</h3>
<div class="info">
""")
conn.send(b"MIN: ")
conn.send(str(round(min_temp, 1)).encode())
conn.send(b"°C MAX: ")
conn.send(str(round(max_temp, 1)).encode())
conn.send(b"°C")
conn.send(b"""
</div>
<a href="/">刷新画面</a>
<div class="thermal">
""")
# 逐点输出大像素色块
for t in temperature_frame:
c = get_color(t)
conn.send(f'<div class="pixel" style="background:{c};"></div>'.encode())
conn.send(b"""
</div>
</body>
</html>
""")
except:
pass
# 主程序
def main():
print("启动...")
time.sleep(1)
cam = init_sensor()
ip = connect_wifi()
if not ip:
return
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("0.0.0.0", 80))
s.listen(1)
s.settimeout(0.1)
while True:
try:
conn, addr = s.accept()
read_temp(cam)
send_page(conn)
conn.close()
print("已刷新")
except OSError:
pass
if __name__ == "__main__":
main()



