描述
<div>
<h3 style="line-height:1.8;">* 1、项目功能介绍</h3>
<hr>
<p style="line-height:1.8;"><span style="font-size:10pt;"><span style="color:#95a5a6;">想必耗材受潮导致的拉丝一定困扰着每一位3D打印爱好者,热床上的炒面和盘丝洞总能引发人们的沉思。</span></span></p>
<p style="line-height:1.8;"><span style="font-size:10pt;"><span style="color:#95a5a6;">干燥箱和温湿度计已经成为每一位3D打印爱好者必备的道具。</span></span></p>
<p style="line-height:1.8;text-align:center;"><img src="//image.lceda.cn/oshwhub/939f9fe60a384332bbc8e79f9828c78c.jpg" alt="" width="1200" height="901"></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图1 再也不会笑了.jpg(一堆温湿度计)</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">传统的干燥剂+密封箱组合的干燥箱只能维持耗材的受潮程度,并不能使耗材表现变好,随着时间的推移耗材依旧会出现质量变差的情况。</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">使用具有主动干燥(加热)功能的干燥箱能够降低耗材的受潮情况,在一定程度上能够改善打印拉丝、缺陷问题。</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">某宝上有许多具有主动功能的干燥箱,但每每看到图片下的价格,总会使我沉思,我在想,3D打印爱好者的钱是不是大风刮来的?</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">虽然与打印机和高质量耗材的价格相比,这样的定价并不算昂贵,但简单的加热元件、控制器及外壳能卖到如此高昂的价格实在让我难以接受。(觉得贵是我的问题,私密马赛)</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">一番思想斗争后还是认为不能给厂商捐款,决定自己动手。</span></p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">也有部分DIY方案采用果蔬烘干器进行改造,但是220V的供电以及不能原生匹配耗材让我望而却步。</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">本干燥组件在常用的5L米桶干燥箱基础上进行附加,做小幅度改造以获得温湿度监测+主动干燥的功能。</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">以下是验证后实物展示:</span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/c3d6727d93d944fb8fb03b52c4a99e05.jpg" alt="" width="1200" height="900"></span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图2 实物展示图1</span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/faa7779395d0471b9a9700d34479e222.jpg" alt="" width="1200" height="900"></span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图3 实物展示图2</span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/833c8ef2f01a4cc39f7e2885dcae025f.jpg" alt="" width="1200" height="900"></span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图4 控制模块PCB展示</span></p>
<h3 style="line-height:1.8;">*2、项目属性</h3>
<hr>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">项目首次公开;项目为原创;项目未曾在其他比赛中获奖;项目未在学校参加过答辩。</span></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">* 3、开源协议</h3>
<hr>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:10pt;">CC BY-NC-SA 4.0</span></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*4、硬件部分</h3>
<hr>
<ul>
<li style="line-height:1.8;"><span style="color:#95a5a6;font-size:14pt;">4.1 基本特性</span></li>
</ul>
<p style="line-height:1.8;text-align:left;padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">有效输入电压:10-20V(10V为软件设定欠压保护下限,可更改;20V为PTC元件电气性能限制)</span></p>
<p style="line-height:1.8;text-align:left;padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">干燥温度范围:0-255℃(由软件设置;回答我,你不会真的加热到255℃,对吧?)</span></p>
<p style="line-height:1.8;text-align:left;padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">设计最大功率:Type-C输入 - 60W;DC输入 - 80W(可以通过软件设置限制输出功率)</span></p>
<p style="line-height:1.8;text-align:left;padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">人机交互:0.96 OLED显示、EC11编码器交互</span></p>
<p style="line-height:1.8;text-align:left;padding-left:40px;"> </p>
<ul>
<li style="line-height:1.8;text-align:left;"><span style="color:#95a5a6;font-size:14pt;">4.2 系统结构</span></li>
</ul>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">本组件主要由MCU、电源部分、主动干燥部分、温湿度监测以及人机交互部分构成。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">系统结构图如下所示:</span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:14pt;"><img src="//image.lceda.cn/oshwhub/fa54b74e288e448d9fddc31536a92433.png" alt="" width="1200" height="560"></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图5 系统结构图</span></p>
<p> </p>
<ul>
<li style="text-align:left;"><span style="color:#95a5a6;font-size:14pt;">4.3 硬件设计</span></li>
</ul>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">· MCU采用ESP32-C3-MINI-1-N4模组,自带USB支持JTAG,用过都说好!不是第一次在项目中使用改模组,但每一次在项目中使用总能学习到新的内容。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">片上有12位ADC,用于PT1000和输入电压的采样(飘也是真的飘,不校准完全不能用)。</span></span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">改模组具备WIFI功能,后续可以考虑接入物联网等。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">其余功能随后续内容描述。</span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/90281392bb6946cbb5ac6a20f7d2aa68.png" alt="" width="1200" height="589"></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图6 MCU部分原理图</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">· 电源部分,输入采用DC插口+Type-C的方案;主供电VBUS直接供给PTC加热器、风扇;主供电经过DC-DC降压获得3.3V电压用于ESP32-C3、OLED等的供电。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">DC插口与VBUS间接入肖特基二极管SS54,做防反接、防倒灌;接入TVS,防止输入电压大于20V损坏PTC。Type-C后接CH224K,用于PD诱骗,Rset设置为NC,诱骗20V电压。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">DC-DC采用Buck拓扑、使用MP2359芯片控制(<span style="text-decoration:line-through;">杰盛微可白嫖</span>&Pin2Pin芯片很多)。其中,FB电压为0.8V,通过电阻分压得到。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">分压电阻使用Matlab编写遗传算法程序,带入电压条件迭代求得,理论误差为0V。</span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/cdd1917cf80649a3b4d0da95edbed8b1.png" alt="" width="1200" height="586"></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图7 FB电阻计算</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">但注意输出电压可能不完全等于3.3V,并且后续ADC校准需要视情况更改校准参数。(本项目测试中实际电压为3.345V,由LCSC530+万用表测量得到)</span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/dd7040e30f7e4860bc2759c901df6bae.png" alt="" width="1200" height="585"></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图8 电源部分原理图</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">· 主动干燥部分由PTC加热控制、风扇控制和PT1000测量组成。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">PTC加热控制、风扇控制采用NMOS开关电路实现。风扇电流较小,使用AO3400 NMOS;PTC所需电流较大,但也仅有数A,一般DFN-8(5x6)封装的NMOS都能满足条件。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">PT1000测量则是与1k电阻构成分压电路,测量PT1000与1k电阻中间点的电压。(懒了,不想加运放做量程变换,直接软件算吧)</span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/d142c443e7b04813996a8642969feba6.png" alt="" width="1200" height="585"></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图9 主动干燥部分原理图</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">· 温湿度监测部分采用盛思锐SHT30温湿度传感器,以I2C总线进行数据交互。</span></span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">· 人机交互部分由0.96" OLED及其驱动电路、EC11编码器组成。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">本项目OLED选型为SH1106 128x64 0.96" 30Pin I2C协议OLED。一般30Pin 0.96" OLED均兼容;EC11编码器柄高随意。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">SHT30与OLED使用同一个硬件I2C。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">在之前的设计当中,分别使用了两对引脚,计划使用两组I2C总线。但在程序编写过程当中,调用库函数难以实现Wire1的使用(对不起,我的代码水平雀食不行),因此改为同一对引脚、同一个硬件I2C总线。</span></p>
<p style="padding-left:40px;text-align:left;"><span style="color:#95a5a6;font-size:10pt;">使用软件I2C进行屏幕的调用延迟较大,会在后续的软件部分说明。</span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:10pt;"><img src="//image.lceda.cn/oshwhub/bee9232b85234f6984d38a38cd015e08.png" alt="" width="1200" height="533"></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图10 温湿度监测部分&人机交互部分原理图</span></p>
<p style="padding-left:40px;text-align:left;"> </p>
<p style="padding-left:40px;text-align:left;"> </p>
<h3 style="line-height:1.8;">*5、软件部分</h3>
<hr>
<ul>
<li style="line-height:1.8;"><span style="color:#95a5a6;font-size:12pt;">5.1 软件设计思路</span></li>
</ul>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">本项目基于Arduino框架开发,开发环境为VSCode PlatformIO。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">项目中,将程序设计整体分为以下几个部分:显示(U8g2)、交互输入(Encoder、OneButton)、温湿度传感器(Adafruit_SHT31)、电压采样(analogRead)、风扇及PTC输出控制(analogWrite、PID)。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">交互输入通过在主循环中调用库函数实现;显示、数据采样、输出控制则是每隔一定间隔执行一次。</span></p>
<p style="padding-left:40px;"> </p>
<ul>
<li><span style="color:#95a5a6;font-size:12pt;">5.2 软件设计</span></li>
</ul>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">· 交互输入实现相对简单,分别通过调用Encoder.h、OneButton.h库函数实现。参照以上库提供的例程实现相应的按键和编码器功能。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">· 数据采样及输出控制中包含两个部分,分别为 需要严格保持时间间隔恒定执行 和 时间间隔要求宽松两种。</span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;"><span style="color:#95a5a6;">其中,PT1000的温度采样、PTC输出控制是需要严格保持时间间隔恒定执行的部分。这是因为该部分涉及PID控制,详细PID原理在此处不过多解释。</span><span style="color:#95a5a6;">而其他的数据采样和风扇控制不需要严格进行控制。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">因此,将上述两种类型分别采用不同方法实现。设置一个定时器(项目中时间为200ms),需要严格时间控制的部分放置于定时器内;同时定义一个中断标志,当发生定时器中断时标志变为true,在主循环中由if判断标志并执行时间要求宽松的部分。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">· 显示也属于较为宽松的部分,并且其刷新需要占用较长时间,因此同上将其放置在if判断标志后执行。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">起初想将所有函数置于定时器中断服务函数中执行,但是这样导致了报错并循环重启(推测定时器再次发生中断时服务函数还未执行完,但在ESP32-S3的开发中没有遇到这样的情况)。因此,将函数分为时间严格、时间宽松两部分分别执行。</span></p>
<p style="padding-left:40px;"> </p>
<ul>
<li><span style="color:#95a5a6;font-size:12pt;">5.3 交互逻辑</span></li>
</ul>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">交互部分包含OLED的显示和EC11编码器的输入。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">· 菜单逻辑</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">本项目中菜单分为两级,第一级菜单用于显示当前系统的情况(温湿度、输入电压、系统状态);第二级菜单用于设置主动干燥时的参数(加热温度、加热时间、风扇及PTC的功率限制)。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">程序设计中,使用一个bool型变量判断菜单的层级;分别进入两级菜单,print对应的项目并请求对应的数值,使用String()转化为字符串后以“+”连接一次性进行绘制输出。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">二级菜单需要对具体的项目进行编辑,多了一个选中状态的选项,因此增加一个unsigned char型变量用于存储选中目标序号,范围为0-3。当目标序号=项目序号时,在该行末端输出一个“*”以作为选中标记。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">在二级菜单的程序编写中,使用了结构体,大大简化了编写程序的复杂程度(一级菜单部分凑合用,就懒得改了),在结构体中存储项目名称、单位、数值和调整刻度。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">使用for循环配合结构体print即可大大压缩显示使用的程序内容。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">程序如下所示:</span></p>
<p style="padding-left:40px;"><code>struct element{<br> char* name;<br> char* unit;<br> unsigned char value;<br> unsigned char scale;<br>};<br>element Setting_Element[] = {<br> {"加热温度: ","℃",60,1},<br> {"加热时间: ","min",0,1},<br> {"功率限制: ","",32,8},<br> {"风扇转速: ","",64,8},<br>};</code></p>
<div> </div>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">菜单显示逻辑如下所示:</span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;"><img src="//image.lceda.cn/oshwhub/61c62bef8f114dc8afa916f14eae9e30.png" alt="" width="1200" height="608"></span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图11 菜单显示逻辑</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">菜单显示效果如下所示:</span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;"><img src="//image.lceda.cn/oshwhub/b5ccd1f16f724f6bb507fed4feb284cc.png" alt="" width="1200" height="356"></span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="font-size:8pt;"><span style="color:#95a5a6;">图12 菜单显示效果</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">· 输入逻辑</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">输入主要分为编码器输入和按键输入。编码器通过旋转可以增大或减小数值;按键则通过功能复用分别实现选中、切换效果。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">OneButton库提供了多种按键状态,本项目中仅使用按键单击和按键长按两种(由于主循环中显示占用时间较长,导致双击识别较不准确,故舍弃)。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">Encoder库可以记录当前编码器的位置,通过将当前位置与上一时刻位置进行比较可以判断数值增减(实际使用中还存在一定抖动)。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">输入交互逻辑如下图所示:</span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;"><img src="//image.lceda.cn/oshwhub/97a3d63d22e04eaa9b65e3fbf55e4649.png" alt="" width="1200" height="593"></span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="font-size:8pt;"><span style="color:#95a5a6;">图13 输入交互逻辑</span></span></p>
<p style="padding-left:40px;"> </p>
<ul>
<li><span style="font-size:12pt;"><span style="color:#95a5a6;">5.4 输出控制</span></span></li>
</ul>
<p style="padding-left:40px;"><span style="font-size:10pt;"><span style="color:#95a5a6;">输出控制分为PTC输出和风扇输出两部分。其中,风扇输出简单调用analogWrite即可;PTC输出为了控制输出温度恒定需要采用PID控制。</span></span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;"><span style="color:#95a5a6;">PID控制采用增量式PID,即在前一时刻控制量基础上调整控制量数值,这样的控制方法代码量比较小(个人感觉)。</span></span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;"><span style="color:#95a5a6;">PID部分代码如下所示:</span></span></p>
<p style="padding-left:40px;"><code>// PID</code><br><code>float Kp=0.1, Ti=125, Td=5;</code><br><code>uint16_t P_Term=0, I_Term=0, D_Term=0;</code></p>
<p style="padding-left:40px;"><code>void PidCtrl(){</code><br><code> // PID项计算</code><br><code> P_Term = Error_Temperature[0] - Error_Temperature[1];</code><br><code> I_Term = Error_Temperature[0];</code><br><code> D_Term = Error_Temperature[0] - 2*Error_Temperature[1] + Error_Temperature[2];</code></p>
<p style="padding-left:40px;"><code> OUT_Status = OUT_Status + Kp*( P_Term + Ts/Ti*I_Term + Td/Ts*D_Term );</code><br><code> // 功率限制</code><br><code> if(OUT_Status > Setting_Element[2].value){</code><br><code> OUT_Status = Setting_Element[2].value;</code><br><code> }</code><br><code> analogWrite(OUT,OUT_Status);</code><br><code> </code><br><code> // Serial.println(String(OUT_Status)+"*"+String(Error_Temperature[0]));</code></p>
<p style="padding-left:40px;"><code> // 温度误差更新</code><br><code> Error_Temperature[2] = Error_Temperature[1];</code><br><code> Error_Temperature[1] = Error_Temperature[0];</code><br><code> Error_Temperature[0] = Setting_Element[0].value - temperature_PT1000;</code><br><code>}</code></p>
<ul>
<li><span style="font-size:12pt;"><span style="color:#95a5a6;">5.5 PT1000测量</span></span></li>
</ul>
<p style="padding-left:40px;"><span style="font-size:10pt;"><span style="color:#95a5a6;">PT1000用于测量PTC加热器的温度。与SHT30测温不同,箱内温度在加热后需要一定时间才能上升,具有迟滞性且具有局部温度差异的情况。</span></span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;"><span style="color:#95a5a6;">若依靠SHT30测量值作为PID控制依据,很可能导致PTC过度加热,使得PTC出口附近温度过高、耗材融化。因此需要额外增加一个温度传感器用于测量PTC温度,使温度控制在合理范围。</span></span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;"><span style="color:#95a5a6;">PT1000在0℃时阻值为1kΩ,随温度上升增大阻值。但其关系并非线性,因此需要对其进行一定处理。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">考虑到加热温度多处于40~80℃,因此本项目抛弃40℃以下、80℃以上的测量准确性,采用局部拟合的方式得到温度与采样值之间的关系。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">根据PT1000温度计算公式,建立温度与电压的实际曲线,然后截取40-80℃部分使用Matlab cftool进行一阶线性拟合。拟合效果如下图所示:</span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;"><img src="//image.lceda.cn/oshwhub/f4928efb6a5a4d8394c4246199e527b9.png" alt="" width="1200" height="531"></span></span></p>
<p style="padding-left:40px;text-align:center;"><span style="font-size:8pt;"><span style="color:#95a5a6;">图14 PT1000拟合效果</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">其中绿线(局部一阶拟合)是黑线(一阶拟合函数)的部分,在图中重合。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">但由于没有能够进行温度校<span style="color:#95a5a6;">准的工具</span>,因此无法判断拟合的效果。并且由于ESP32-C3的ADC存在偏移,测量结果必然存在一定误差。</span></span></p>
<p style="padding-left:40px;"> </p>
<h3 style="line-height:1.8;">*6、BOM清单</h3>
<hr>
<ul>
<li style="line-height:1.8;text-align:left;"><span style="color:#95a5a6;"><span style="font-size:12pt;">6.1 装配明细</span></span></li>
</ul>
<p style="text-align:center;"><span style="color:#95a5a6;font-size:8pt;">表1 装配明细</span></p>
<table style="border-collapse:collapse;width:80%;height:320px;margin-left:auto;margin-right:auto;">
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">序号</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">项目</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">数量</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">备注</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">6CM风扇</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">厚度不限</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">2</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">6x3磁铁</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">8</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">安装时注意对吸</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">3</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M4x4x5.5土八螺母</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">4</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">4</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M4x14内六角螺栓</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">4</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">5</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M3x3x4.5土八螺母</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">4</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">6</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M3x12铜柱</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">7</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M3x8铜柱</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">8</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M3x4平头螺丝</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">2</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">9</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">PT1000</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">10</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">XH2.54-2P端子线</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">11</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">四氟管</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">一小段,外径4mm(玩3D打印的大家都有吧?)</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">12</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M3x10螺丝</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">2</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">圆头或平头</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">13</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">M3x8螺丝</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">4</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">沉头最佳</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">14</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">铜鼻子</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">2</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">孔内径>3mm</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">15</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">PTC加热器</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">12V 50W</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">16</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">控制器模块</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"> </td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">17</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">风嘴</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">打印件,见附件</span></td>
</tr>
<tr style="height:20.7656px;">
<td style="width:11.8724%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">18</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">控制器座</span></td>
<td style="width:20.2929%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.7656px;line-height:1;"><span style="font-size:10pt;">打印件,见附件</span></td>
</tr>
<tr style="height:20.8281px;">
<td style="width:11.8724%;text-align:center;height:20.8281px;line-height:1;"><span style="font-size:10pt;">19</span></td>
<td style="width:20.2929%;text-align:center;height:20.8281px;line-height:1;"><span style="font-size:10pt;">控制器盖</span></td>
<td style="width:20.2929%;text-align:center;height:20.8281px;line-height:1;"><span style="font-size:10pt;">1</span></td>
<td style="width:47.4895%;text-align:center;height:20.8281px;line-height:1;"><span style="font-size:10pt;">打印件,见附件</span></td>
</tr>
</table>
<p style="padding-left:40px;"> </p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:14px;"><img src="//image.lceda.cn/oshwhub/f5c87498b11c4c1b9ca21a7c0f67be3d.jpg" alt="" width="1200" height="900"></span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图15 模块组成展示</span></p>
<ul>
<li><span style="color:#95a5a6;font-size:12pt;">6.2 模块装配</span></li>
</ul>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;"><img src="//image.lceda.cn/oshwhub/d0016c0a38bd48daba3352f4387647bd.png" alt="" width="1200" height="675"></span></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图16 装配爆炸图(部分)</span></p>
<p style="line-height:1.8;text-align:left;padding-left:40px;"><span style="color:#95a5a6;font-size:10pt;">安装时,5L米桶需要进行打孔处理,两个为PTC加热器接线柱、一个为四氟管伸出孔、方孔用于伸出XH座子和端子线。如下图所示:</span></p>
<p style="line-height:1.8;padding-left:40px;text-align:center;"> <img src="//image.lceda.cn/oshwhub/46add3291d8a4f8f98a27bd7143b5754.jpg" alt="" width="1200" height="900"></p>
<p style="line-height:1.8;padding-left:40px;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图17 打孔标记</span></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*7、大赛LOGO验证</h3>
<hr>
<p style="line-height:1.8;text-align:center;"> </p>
<p style="line-height:1.8;text-align:center;"><img src="//image.lceda.cn/oshwhub/0d6c6273f421438885cd73f4d827f8dd.jpg" alt="" width="1200" height="899"></p>
<p style="line-height:1.8;text-align:center;"><span style="color:#95a5a6;font-size:8pt;">图18 大赛Logo验证</span></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">* 8、演示您的项目并录制成视频上传</h3>
<hr>
<p style="line-height:1.8;"><span style="font-size:10pt;color:#95a5a6;">视频见附件。</span></p>
<p style="line-height:1.8;"> </p>
<ul>
<li style="line-height:1.8;"><span style="font-size:12pt;color:#95a5a6;">8.1 项目附加说明</span></li>
</ul>
<p style="padding-left:40px;"><span style="font-size:10pt;color:#95a5a6;">在实物验证过程中,发现了部分不合理之处,不推荐直接对该项目进行复刻,建议做一定修改再行复刻。以下是待改进的点:</span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;color:#95a5a6;">1.风扇噪声。风扇控制使用analoagWrite,PWM频率较低,在运行时存在较大的噪声,后续尝试改为ESP32的ledc控制。</span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;color:#95a5a6;">2.风扇与PT1000连接。当前使用的XH插接位置较差,装配需要镊子辅助,应该将插座留在侧面方便连接;或者增加副板、更换PogoPin实现免插接并降低漏气可能。</span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;color:#95a5a6;">3.屏幕刷新率较低。当前使用的是硬件I2C方案,虽然相较于原有的软件I2C有极大的改善,但是刷新时间仍较长,还有很大的改进空间。(在代码是也可以优化,个人软件水平一般,能力有限)</span></p>
<p style="padding-left:40px;"><span style="font-size:10pt;color:#95a5a6;">4.温湿度与主动干燥没有联动。当前还没有加入联动,例如设置湿度阈值进行主动干燥。</span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">5.干燥剂放置。原先计划将干燥剂以磁吸方式吸附在风扇另一侧,但实际安装中空间过小,无法放入。</span></span></p>
<p style="padding-left:40px;"><span style="color:#95a5a6;"><span style="font-size:13.3333px;">本项目仅抛砖引玉,提供一些设计思路供各位大佬参考。</span></span></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">附录</h3>
<ul>
<li><span style="font-size:12pt;">附录1 项目程序</span></li>
</ul>
<p style="padding-left:40px;"><code>#include <Arduino.h></code><br><code>#include <Wire.h></code><br><code>#include <SPI.h></code><br><code>#include <U8g2lib.h></code><br><code>#include "Adafruit_SHT31.h"</code><br><code>#define ENCODER_OPTIMIZE_INTERRUPTS </code><br><code>#include <Encoder.h></code><br><code>#include "OneButton.h"</code></p>
<p style="padding-left:40px;"><code>// IO Setting</code><br><code>#define OUT 4</code><br><code>#define FAN 5</code><br><code>#define UIN_IN 0</code><br><code>#define PT1000_IN 1</code></p>
<p style="padding-left:40px;"><code>// Variable Definition</code><br><code>float temperature = 0; // 箱内温度</code><br><code>float humidity = 0; // 箱内湿度</code><br><code>uint16_t UIN = 0; // UIN读数</code><br><code>uint16_t PT1000 = 0; // PT1000读数</code><br><code>float voltage_UIN = 0; // UIN电压</code><br><code>float temperature_PT1000 = 0; // PT1000温度</code><br><code>unsigned char OUT_Status = 0; // PTC输出状态</code><br><code>float Error_Temperature[3] = {0}; // 温度误差队列</code><br><code>const uint16_t Ts = 200; // 采样、上传、控制周期设置</code><br><code>bool FLAG_timIT0 = 0; // timer0中断标志</code><br><code>bool System_Status = 0; // 系统状态 0 - 待机;1 - 加热</code><br><code>bool List_Level = 0; // 菜单层级 0 - 主页;1 - 设置</code><br><code>bool Choose_Status = 0; // 选中状态</code><br><code>bool UIN_Error = 0; // 输入电压过低标志</code><br><code>unsigned char UIN_threshold = 10; // 电压阈值</code><br><code>unsigned char Choose_Targrt = 0; // 选中目标</code><br><code>uint16_t heating_times = 0; // 加热时间计数器</code><br><code>uint16_t heating_sum_time = 0; // 加热计数器最大值</code></p>
<p style="padding-left:40px;"><code>struct element{</code><br><code> char* name;</code><br><code> char* unit;</code><br><code> unsigned char value;</code><br><code> unsigned char scale;</code><br><code>};</code><br><code>element Setting_Element[] = {</code><br><code> {"加热温度: ","℃",60,1},</code><br><code> {"加热时间: ","min",0,1},</code><br><code> {"功率限制: ","",32,8},</code><br><code> {"风扇转速: ","",64,8},</code><br><code>};</code></p>
<p style="padding-left:40px;"><code>// U8G2</code><br><code>#define SDA 7</code><br><code>#define SCL 6</code><br><code>// U8G2_SH1106_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);</code><br><code>U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);</code></p>
<p style="padding-left:40px;"><code>// SHT30</code><br><code>Adafruit_SHT31 sht31 = Adafruit_SHT31();</code><br><code>#define SHT30_SDA 2</code><br><code>#define SHT30_SCL 3</code></p>
<p style="padding-left:40px;"><code>// Encoder</code><br><code>#define KeyA 20</code><br><code>#define KeyB 21</code><br><code>Encoder Enc(KeyB, KeyA);</code><br><code>long oldPosition=-999;</code><br><code>long newPosition=0;</code></p>
<p style="padding-left:40px;"><code>void EncoderRead(){</code><br><code> if(Enc.read() != oldPosition) {</code><br><code> newPosition = Enc.read();</code><br><code> Serial.println(newPosition);</code><br><code> if(List_Level){</code><br><code> if(Choose_Status){</code><br><code> if(newPosition>oldPosition){</code><br><code> Setting_Element[Choose_Targrt].value+=Setting_Element[Choose_Targrt].scale;</code><br><code> }</code><br><code> else{</code><br><code> Setting_Element[Choose_Targrt].value-=Setting_Element[Choose_Targrt].scale;</code><br><code> }</code><br><code> }</code><br><code> else{</code><br><code> if(newPosition>oldPosition){</code><br><code> Choose_Targrt+=1;</code><br><code> }</code><br><code> else{</code><br><code> Choose_Targrt-=1;</code><br><code> }</code><br><code> if(Choose_Targrt>3){</code><br><code> Choose_Targrt=0;</code><br><code> }</code><br><code> }</code><br><code> }</code><br><code> oldPosition=newPosition;</code><br><code> }</code><br><code>}</code></p>
<p style="padding-left:40px;"><code>// OneButton</code><br><code>#define Key1 10</code><br><code>OneButton button(Key1, true);</code></p>
<p style="padding-left:40px;"><code> // 按键单击</code><br><code>void Click1() {</code><br><code> Serial.println("click");</code><br><code> List_Level = !List_Level;</code><br><code> Choose_Status = 0;</code><br><code> Serial.println(List_Level);</code><br><code>}</code><br><code> // 按键长按</code><br><code>void longPressStart() {</code><br><code> Serial.println("longPressStart");</code><br><code> if(!List_Level){</code><br><code> if(1){//voltage_UIN > UIN_threshold){</code><br><code> System_Status = !System_Status;</code><br><code> heating_times = 0;</code><br><code> heating_sum_time = Setting_Element[1].value *300;</code><br><code> }</code><br><code> else{</code><br><code> UIN_Error = 1;</code><br><code> }</code><br><code> }</code><br><code> else{</code><br><code> Choose_Status = !Choose_Status;</code><br><code> }</code><br><code>}</code></p>
<p style="padding-left:40px;"><code>// 数据读取</code><br><code>void dataRead() {</code><br><code> temperature = sht31.readTemperature();</code><br><code> humidity = sht31.readHumidity();</code><br><code> UIN = analogRead(UIN_IN);</code><br><code> voltage_UIN = UIN*0.006046; // 1/4096*3.3*8.5 取决于ESP32-C3系数需要自行校准</code><br><code> // PT1000 = analogRead(PT1000_IN);</code><br><code>}</code></p>
<p style="padding-left:40px;"><code>// PID</code><br><code>float Kp=0.1, Ti=125, Td=5;</code><br><code>uint16_t P_Term=0, I_Term=0, D_Term=0;</code></p>
<p style="padding-left:40px;"><code>void PidCtrl(){</code><br><code> // PID项计算</code><br><code> P_Term = Error_Temperature[0] - Error_Temperature[1];</code><br><code> I_Term = Error_Temperature[0];</code><br><code> D_Term = Error_Temperature[0] - 2*Error_Temperature[1] + Error_Temperature[2];</code></p>
<p style="padding-left:40px;"><code> OUT_Status = OUT_Status + Kp*( P_Term + Ts/Ti*I_Term + Td/Ts*D_Term );</code><br><code> // 功率限制</code><br><code> if(OUT_Status > Setting_Element[2].value){</code><br><code> OUT_Status = Setting_Element[2].value;</code><br><code> }</code><br><code> analogWrite(OUT,OUT_Status);</code><br><code> </code><br><code> // Serial.println(String(OUT_Status)+"*"+String(Error_Temperature[0]));</code></p>
<p style="padding-left:40px;"><code> // 温度误差更新</code><br><code> Error_Temperature[2] = Error_Temperature[1];</code><br><code> Error_Temperature[1] = Error_Temperature[0];</code><br><code> Error_Temperature[0] = Setting_Element[0].value - temperature_PT1000;</code><br><code>}</code></p>
<p style="padding-left:40px;"><code>// 定时器设置</code><br><code>hw_timer_t *timer0 = NULL; // 定时器0 采样、上传、控制刷新</code><br><code> // 状态更新</code><br><code>void onTimer0() {</code><br><code> FLAG_timIT0 = 1;</code></p>
<p style="padding-left:40px;"><code> PT1000 = analogRead(PT1000_IN) *0.85+52;</code><br><code> temperature_PT1000 = (PT1000-2070)/3.11;</code><br><code> // Serial.println(temperature_PT1000);</code></p>
<p style="padding-left:40px;"><code> heating_times++;</code><br><code> if(System_Status){</code><br><code> PidCtrl();</code></p>
<p style="padding-left:40px;"><code> if(heating_times >= heating_sum_time){</code><br><code> System_Status = 0;</code><br><code> heating_times = 0;</code><br><code> Setting_Element[2].value = 0;</code><br><code> }</code><br><code> }</code><br><code> // Serial.println(PT1000);</code><br><code> // Serial.println(temperature_PT1000);</code><br><code> </code><br><code>}</code></p>
<p style="padding-left:40px;"><code>unsigned char ITtimes=0; // 用于屏幕刷新的计数器</code></p>
<p style="padding-left:40px;"><code>void setup() {</code><br><code> // put your setup code here, to run once:</code><br><code> // IO Setting</code><br><code> pinMode(OUT,OUTPUT);</code><br><code> pinMode(FAN,OUTPUT);</code><br><code> pinMode(PT1000_IN,INPUT);</code><br><code> pinMode(UIN_IN,INPUT);</code></p>
<p style="padding-left:40px;"><code> // Serial</code><br><code> Serial.begin(115200);</code></p>
<p style="padding-left:40px;"><code> // SHT30</code><br><code> Wire.begin(SHT30_SDA,SHT30_SCL);</code><br><code> if (!sht31.begin(0x44)) {</code><br><code> while (1) {</code><br><code> Serial.println("SHT31 sensor not found!");</code><br><code> }</code><br><code> }</code></p>
<p style="padding-left:40px;"><code> // U8G2</code><br><code> u8g2.begin();</code><br><code> u8g2.enableUTF8Print();</code><br><code> u8g2.setFont(u8g2_font_wqy14_t_gb2312a);</code></p>
<p style="padding-left:40px;"><code> button.reset();//清除一下按钮状态机的状态</code><br><code> button.attachClick(Click1);</code><br><code> button.attachLongPressStart(longPressStart);</code></p>
<p style="padding-left:40px;"><code> // 定时器初始化</code><br><code> // 定时器0</code><br><code> timer0 = timerBegin(0,80,true); // 初始化定时器-使用定时器1</code><br><code> timerAttachInterrupt(timer0,onTimer0,true); // 绑定定时器中断服务函数</code><br><code> timerAlarmWrite(timer0,Ts*1000,true); // 设置中断 间隔为采样周期</code><br><code> timerAlarmEnable(timer0); // 启动定时器</code><br><code>}</code></p>
<p style="padding-left:40px;"><code>void loop() {</code><br><code> // put your main code here, to run repeatedly:</code><br><code> EncoderRead();</code><br><code> button.tick();</code></p>
<p style="padding-left:40px;"><code> if(FLAG_timIT0){</code><br><code> FLAG_timIT0 = 0;</code></p>
<p style="padding-left:40px;"><code> dataRead();</code><br><code> if(System_Status){</code><br><code> analogWrite(FAN,Setting_Element[3].value);</code><br><code> }</code><br><code> else{</code><br><code> analogWrite(FAN,0);</code><br><code> analogWrite(OUT,0);</code><br><code> }</code><br><code> </code><br><code> ITtimes++;</code><br><code> if(!List_Level){</code><br><code> if(ITtimes >= 4){</code><br><code> ITtimes = 0;</code></p>
<p style="padding-left:40px;"><code> u8g2.clearBuffer();</code><br><code> u8g2.setCursor(0, 15);</code><br><code> u8g2.print("箱内温度: "+String(temperature)+"℃");</code><br><code> u8g2.setCursor(0, 31);</code><br><code> u8g2.print("箱内湿度: "+String(humidity)+"%");</code><br><code> u8g2.setCursor(0, 47);</code><br><code> u8g2.print("输入电压: "+String(voltage_UIN)+"V");</code><br><code> u8g2.setCursor(0, 63);</code><br><code> if(UIN_Error){</code><br><code> u8g2.print("系统状态: 电压过低");</code><br><code> u8g2.drawHLine(0, 63, 128);</code><br><code> }</code><br><code> else{</code><br><code> if(System_Status){</code><br><code> u8g2.print("系统状态: 加热中");</code><br><code> }</code><br><code> else{</code><br><code> u8g2.print("系统状态: 待机");</code><br><code> }</code><br><code> }</code><br><code> u8g2.sendBuffer();</code><br><code> }</code><br><code> }</code><br><code> else{</code><br><code> if(ITtimes >= 1){</code><br><code> ITtimes = 0;</code></p>
<p style="padding-left:40px;"><code> u8g2.clearBuffer();</code><br><code> for(unsigned char i=0; i<=3; i++){</code><br><code> u8g2.setCursor(0, (i+1)*16-1);</code><br><code> u8g2.print(Setting_Element[i].name+String(Setting_Element[i].value)+Setting_Element[i].unit);</code><br><code> if(Choose_Targrt == i){</code><br><code> if(Choose_Status){</code><br><code> u8g2.setCursor(112, (i+1)*16-1);</code><br><code> u8g2.print("*");</code><br><code> }</code><br><code> u8g2.drawHLine(0, (i+1)*16-1, 128);</code><br><code> }</code><br><code> }</code><br><code> u8g2.sendBuffer();</code><br><code> }</code><br><code> }</code><br><code> }</code><br><code>}</code></p>
</div>
评论(42)