使用M5Stack Dial-ESP32-S3 作为主控与继电器模块,DS18S20温度传感器实现,其中包含硬件选择、功能实现、安全性以及用户交互等,特别是在其工作的时候,还包括超温,风循环等功能。
下面是基于M5Stack Dial-ESP32-S3的宠物烘烤控制器的设计方案概述:
一、硬件功能介绍
1. M5Stack Dial-ESP32-S3模块
M5Stack Dial是一款多功能嵌入式开发板,集成了各种智能家居控制应用所需的功能和传感器,它基于ESP32-S3芯片设计,具有高性能和低功耗的特点。
主要组件和功能:
主控制器:M5StampS3,基于ESP32-S3芯片,支持Wi-Fi和各种外设接口SPI、I2C、UART、ADC等。
显示屏:1.28英寸圆形TFT触摸屏,提供直观的用户界面。
旋转编码器:可准确记录旋钮的位置和方向,提供更好的交互体验。
RTC电路:实时时钟电路,用于时间管理。
蜂鸣器和屏下按钮:提供声音反馈和额外的用户输入方式。
显示屏与编码器、按键:圆形TFT触摸屏与按键,用于显示状态和设置温度参数调整。
2. 传感器
DS18S20传感器是一款由美国DALLAS(Maxim Integrated Products)公司生产的数字温度传感器。
产品特点
单线接口:DS18S20在与微处理器连接时,仅需一条口线即可实现微处理器与DS18S20的双向通讯,极大地节省了I/O引脚资源。
测温范围广:其测温范围为-55℃~+125℃,适用于各种环境下的温度测量。
高精度:DS18S20提供了9位高精度的摄氏温度测量,固有测温分辨率为0.5℃。
主要部件与功能
DS18S20内部包含三个主要部件:64位激光刻制的唯一ROM序列号、温度传感器以及非易失性温度报警触发器TH和TL,ROM序列号用于区分不同的DS18S20传感器,温度传感器用于测量温度,而非易失性温度报警触发器TH和TL则用于设置温度报警的上下限。
供电方式
DS18S20可以采用两种供电方式:外部供电方式和寄生电源供电方式。
外部供电方式:DS18S20可以外接3.3V或5V的电源,GND引脚接地。
3、加热模块
使用继电器控制加热元件的工作原理
加热元件通常是通过继电器工作的原理将电能直接转换为热能。当电流流过加热元件产生热量。这种热量随后被传递给烘烤室内的空气,从而实现烘烤效果。
IO控制继电器的作用
IO控制继电器是一种用于控制电路的开关设备,它可以通过输入信号数字信号来控制输出电路加热元件的通断。在烘烤设备中,IO控制继电器可以接收来自微处理器或其他控制器的指令,根据指令来控制加热元件的加热功率和时间,从而实现精确的温度控制。
通过IO控制继电器,可以根据预设的温度曲线来精确控制加热元件的加热功率和时间,从而实现烘烤过程中的温度控制。
控制方式:
电路原理图:
4、风扇:用于循环空气或排出烘烤过程中产生的湿气,和内部温度的循环,使热量均匀。
主控与继电器,温度传感器连接示意图:
B口连接位置示意图:
二、软件设计具体功能
使用Visual Studio Code开发平台进行开发,利用PlatformIO进行软件开发,使用的是C编程语言实现控制逻辑。
设计直观易用的用户界面,提高用户体验。
风扇:
当设备接收到5V供电时,风扇立即启动。
风扇持续运行,为烘箱内部提供持续的吹风,这是为了防止烘箱内部温度过高,同时也是为了保护PTC发热片免受高温损害。
超温保护机制:
设备内置超温保护开关,最高温度限制可设定为50度或70度(根据具体需求选择)。
一旦温度超过设定的最高温度限制,设备将自动停止加热并启动报警机制(如蜂鸣器或LED指示灯),以防止温度过高对设备造成损害。
M5Stack Dial主控功能:
当M5Stack Dial主控供电并开机后,将显示开机界面,并展示www.eetree.cn等相关信息。
用户可以通过扭动编码器来选择不同的功能选项,并点击M5按键进入温度设定界面。
在温度设定界面中,用户可以通过转动编码器来增加或减少设定的温度值。
温度检测与加热控制:
在设备运行过程中,温度检测模块实时工作,不断监测烘箱内部的温度。
加热模块和继电器处于待机状态,等待IO指令进行加热操作。
当实际温度低于设定温度时(例如设定温度为30度,实际温度为25度),M5Stack Dial将发出指令,驱动继电器模块启动加热功能。
当实际温度达到设定温度时,加热功能将自动停止,以避免温度过高。
硬件外设框架:
代码:
// 定义TemperatureSensor类
class TemperatureSensor {
public:
// 构造函数,初始化传感器连接引脚等
TemperatureSensor(uint8_t pin)
: ds(pin), initialized(false), conversionInProgress(false), lastRequestTime(0) {}
// 初始化传感器
void begin() {
if (initializeSensor()) {
initialized = true;
requestTemperature(); // 开始第一次温度转换
}
}
// 更新温度数据
void update() {
if (!initialized) return;
if (conversionInProgress && millis() - lastRequestTime >= 750) {
// 检查转换时间是否已过
readTemperature();
requestTemperature(); // 开始下一次转换
}
}
// 获取摄氏度温度
float getCelsius() const {
return celsius;
}
// 获取华氏度温度
float getFahrenheit() const {
return fahrenheit;
}
// 请求温度转换
void requestTemperature() {
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // 开始温度转换
conversionInProgress = true;
lastRequestTime = millis();
}
// 读取温度数据
void readTemperature() {
byte data[9];
ds.reset();
ds.select(addr);
ds.write(0xBE); // 读取暂存器
for (byte i = 0; i < 9; i++) {
data[i] = ds.read();
}
// 根据传感器类型和配置计算原始温度值
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3;
if (data[7] == 0x10) {
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw & ~7;
else if (cfg == 0x20) raw = raw & ~3;
else if (cfg == 0x40) raw = raw & ~1;
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
conversionInProgress = false;
}
// 初始化传感器,包括搜索地址、校验CRC和识别芯片类型
bool initializeSensor() {
if (!ds.search(addr)) {
Serial.println("No more addresses.");
ds.reset_search();
delay(250);
return false;
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return false;
}
type_s = identifyChip(addr[0]);
if (type_s == 255) {
Serial.println("Device is not a DS18x20 family device.");
return false;
}
return true;
}
// 根据传感器的第一个字节识别芯片类型
byte identifyChip(byte firstByte) {
switch (firstByte) {
case 0x10:
Serial.println("Chip = DS18S20");
return 1;
case 0x28:
Serial.println("Chip = DS18B20");
return 0;
case 0x22:
Serial.println("Chip = DS1822");
return 0;
default:
return 255;
}
}
};
// 创建TemperatureSensor对象,并连接到数字引脚1
TemperatureSensor sensor(1);
// setup函数,在Arduino板上电或重置时运行一次
void setup() {
// 配置M5Dial(此处代码略,具体配置依赖于M5Dial库)
auto cfg = M5.config();
M5Dial.begin(cfg, true, false);
Serial.begin(115200); // 初始化串口通信
sensor.begin(); // 初始化温度传感器
drawInit(); // 初始化显示(此处代码略,具体实现依赖于图形库)
pinMode(2, OUTPUT); // 将数字引脚2设置为输出(此行代码似乎与主要功能无关)
}
// loop函数,在Arduino运行时不断循环执行
void loop() {
sensor.update(); // 更新温度数据
M5Dial.update(); // 更新M5Dial状态
// 以下代码处理M5Dial的用户交互逻辑(略去具体细节)
// ...
// 显示当前温度
Serial.print("Temperature = ");
Serial.print(sensor.getCelsius());
Serial.println(" Fahrenheit");
delay(100); // 延时100毫秒
}
// 绘制初始化界面的函数(略去具体实现)
void drawInit() {
// ...
}
// 绘制选择界面的函数(略去具体实现)
void drawChose() {
// ...
}
// 显示对应的 温度时间信息
info.setTextColor(TFT_WHITE, TFT_BLUE);
if (chose_mode == 1)
{
info.drawString("www.eetree.cn", 30, 10, &FreeMono9pt7b);
info.drawString("2024 DigiKey third", -1, 30, &FreeMono9pt7b);
info.drawString("temperature", 30, 50, &FreeMono9pt7b);
info.pushSprite(20, 120);
}
// 系统运行时的界面
void drawRunning()
{
float currentTemp = sensor.getCelsius();
float adc=0;
runInfo msg;
background.fillSprite(TFT_BLUE);
chose.fillSprite(TFT_BLUE);
info.fillSprite(TFT_BLUE);
chose.setTextColor(TFT_BLACK, TFT_DARKGREEN);
float TEMPAD=M5Dial.Encoder.read();
//printf("TEMPAD %.1f\r\n");
Serial.print("TEMPAD: ");
Serial.println(TEMPAD);
Serial.print("\r\n");
if (chose_mode == 1)
{
if ( TEMPAD ) //编码器正转
{
settempture += 5;
// 将设定值打印到屏幕
sprintf(buf, "SETTEMP: %.1f ", settempture); // 使用当前温度值
info.drawString(buf, 0, 0, &FreeMono12pt7b); // 在屏幕上显示温度
}
else
{
settempture -= 5;
// 将设定值打印到屏幕
sprintf(buf, "SETTEMP: %.1f ", settempture); // 使用当前温度值
info.drawString(buf, 0, 0, &FreeMono12pt7b); // 在屏幕上显示温度
}
chose.drawCenterString("temperature", 90, 18, &FreeSansBold12pt7b);
sprintf(buf, "TEMP: %.1f ", currentTemp); // 使用当前温度值
info.drawString(buf, 0, 30, &FreeMono12pt7b); // 在屏幕上显示温度
sprintf(buf, "TIME: %02d:%02d", msg.timelong / 60, msg.timelong % 60);
info.drawString(buf, 0, 60, &FreeMono12pt7b);
if ( TEMPAD <= currentTemp )
{
digitalWrite(2, LOW);
} else
{
digitalWrite(2, HIGH);
TEMPAD = 0;
}
}
info.pushSprite(30, 130);
chose.pushSprite(30, 20);
background.pushSprite(0, 0);
}
软件工作流程:
工作流程的详细解释:
初始化 (setup() 函数):
配置M5Dial,包括显示屏、编码器和按钮。
初始化串口通信,以便在串行监视器上打印信息。
初始化温度传感器DS18B20。
调用drawInit()函数来初始化显示屏的背景、选择和信息图层。
选择模式 (loop() 函数中的非运行模式):
不断更新温度传感器的数据。
读取编码器的位置,以检测用户是否在旋转编码器来选择模式。
如果编码器位置发生变化,根据旋转方向更新chose_mode变量。
当按钮A被按下时,切换到运行模式,并播放一个短促的提示音。
如果按钮A被长按3秒,则重置系统到选择模式,并播放一个长提示音。
运行模式 (loop() 函数中的运行模式):
不断更新温度传感器的数据。
读取编码器的值(这里似乎有误用,因为编码器的值通常用于表示旋转的位置或步数,而不是直接作为温度值)。
使用编码器的值来增减设定温度(settempture),这在实际应用中可能不合适,因为编码器的值通常不是线性的温度增量。
根据选择的模式,在屏幕上显示当前温度、设定温度以及可能的时间信息(尽管时间信息在提供的代码中未完全实现或更新)。
如果设定温度与实际温度的关系满足特定条件(设定温度应高于实际温度),则通过引脚2输出高电平信号(可能用于控制加热器)。
否则,输出低电平。
用户界面更新 (drawChose() 和 drawRunning() 函数):
drawChose()函数用于在选择模式下更新用户界面,显示当前选择的模式和一些静态信息。
drawRunning()函数用于在运行模式下更新用户界面,显示设定温度、当前温度以及可能的时间信息。
总结:
具体功能是当给主控供电时,5V输入,风扇就开始工作,因为需要要一直给烘箱内吹风,这是防止高温的一种防止措施之一,也是保护PTC发热片烧坏的原因,第二是超温保护开关,最高温度不能超过50或者70度,避免温度过高;
当M5Stack dial主控供电,开机进入显示界面,出现开机界面,网站www.eetree.cn等相关信息,然后可以通过扭动编码器,可以进入选择,再点M5那个按键,进入温度设定界面,再转动编码器就可以加减温度的设定,在这个操作过程和开机状态,温度检测是实时在工作,加热模块,继电器是待机状态,等待IO给过的指令进行加热;如果设定温度30度,实际温度只有25度,M5Stack dial就会发出指令,驱动继电器模块加温,当达到30度时,就会停止加温。
通过实现这个烘箱的功能实现,我从中还是学习到了不少的知识提升,原计划用IIC实现温度采集,因为经常用,没有用过这个单线的DS18S20,所以就用这个实现一下,看看有什么难度,当然还有开发平台,也是用的之前没有用过的,都是一次新的开始,从中得到了大的提升,有了新的认识,虽然非常的难受,虽然欠缺,但是我还是实现了当初设想的功能,再次感谢电子森林。