描述
<p><h3 style="line-height: 1.8;">1、项目功能介绍</h3>
<hr />
<p style="line-height: 1.8;">本次大赛是做一个温湿度(SHT40传感器)检测仪,官方版本显示屏是数码管。我想着那可以加上墨水屏做一个低功耗的检测仪,既然上了墨水屏那MCU就换成ESP32吧,然后再加一个空气质量传感器SGP30,这就是本项目主要的想法。</p>
<h3 style="line-height: 1.8;"> </h3>
<h3 style="line-height: 1.8;">2、硬件部分</h3>
<hr />
<p style="line-height: 1.8;">ESP32有好多版本,最开始看上了ESP32-PICO-V3。看上它的主要原因是它是一颗SIP,就是系统级集成的芯片,基本不需要啥外围电路;相比ESP32或者ESP32-S系列芯片,ESP32-PICO-V3集成了晶振、电源等基本的外围电路。虽然ESP32-PICO-V3的官方参考电路还是有电源滤波电容,但是我觉得这颗芯片主要上电再加个天线就可以用了。最终成品没有选它,原因无他,就是贵。</p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">墨水屏在闲鱼上收了一个2.66寸的黑白两色屏幕。卖家说兼容佳显的GDEW026T0D,那驱动应该不要愁了。</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/pullimage/nyMs9NVzg5zwWrSSFyPcjDgUe7GlaI6TmyIrTP6I.jpeg" alt="" width="696" height="654" /></p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">第一版产品用了ESP32-C3,虽然他的外围电路多,但是芯片够便宜。下面的第一版的电路图和PCB。</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/pullimage/JqTGBSS9j4pYf4gEDbc5u4t72w6qVyde55BgilaV.png" alt="" width="1190" height="845" /><img src="//image.lceda.cn/pullimage/NM87FR70muun3TXHNxD4DhSUV9Ngt7RiFT6RYi4j.png" alt="" width="829" height="465" /></p>
<p style="line-height: 1.8;">这板打出来焊接完成后识别不到芯片,认真检查已排除芯片虚焊和USB信号线没通芯片的情况;由于缺少工具没法检查晶振和芯片是否正常工作,只好放弃这个方案。</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/pullimage/ZbbNB0yftT8dPY9n2DgNGuBp5jQNWrJ1uYoEYDQ1.jpeg" alt="" width="828" height="478" /></p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">第二版方案就是最终的成品,这版直接把ESP32-C3芯片换成ESP32-S3模块以便提高成功率。拿到板子焊接后轻松识别到芯片,传感器也能读到。OK,接下来就是写程序了。</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/pullimage/iLgr4WGsBiO4ICYanCK0UzydTmmxxy1J9mPEgyrb.jpeg" alt="" width="830" height="415" /></p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">关于焊接需要特别说的是:</p>
<p style="line-height: 1.8;">由于盛世瑞到传感器非常小,特别是SHT40是一个1.5mmX1.5mm的DFN。第一次焊接时把焊油弄到传感器的小孔里了,虽然用酒精清理干净了,但是后面读取温湿度时发展这两个值基本都是40左右,显然不对。换个新SHT40,焊接时用风枪吹上去,焊油只放一点点,基本不会弄到孔里去;但是发现温度还是偏高4、5度不知道为什么。另外空气传感器SGP30有个白色的保护膜(上图没有撕掉),基本可以随便焊随便洗;最后记得撕掉就好,否则TVOC就一直是400,相当于没有感应到环境的有机挥发物。</p>
<h3 style="line-height: 1.8;"> </h3>
<h3 style="line-height: 1.8;">3、软件部分</h3>
<hr />
<p style="line-height: 1.8;">ESP32的开发有好几种方式,第一种方式是直接用官方的ESP-IDF进行开发,这种方式相当于装一个SDK然后就用一个自己喜欢的编辑器写代码就行,也可以配合PlatformIO在VS Code中写代码。第二种方式就是Arduino了,在Arduino中安装好espressif官方的包在选择一个Flash与你用的模块一样的ESP32-S3板子就行。其他的方式还有MircoPython、ESPHome等。我这里用ESPHome来开发软件,选它的原因是写代码就是写配置文件,把传感器、屏幕、按键等外设配置好就可以工作,非常简单。</p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">ESPHome的安装非常简单,在mac下一个命令就搞定:</p>
<p style="line-height: 1.8;"><code>pip install esphome python-magic-bin</code></p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">当然了,作为极致懒的人,连ESPHome的配置文件都不想从头开始写,那就让LLM帮忙写一版。下面是GPT-4o写的第一版程序(完整程序见附件“temp-detector-gpt4o.yaml”):</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/pullimage/yS0NpEckcc57k3eQfZc342LeQYDKklNkf7M78DsO.png" /></p>
<p style="line-height: 1.8;">GPT-4o的程序基本实现了我描述的功能,除了墨水屏驱动它没法提供,这也好理解毕竟我没有告诉它墨水屏更详细的信息。除了没墨水屏需求,其他大问题是没有的,但是小问题不少,例如board这样写就是错的编译不过。</p>
<p style="line-height: 1.8;">小问题好说,我就基于GPT-4o的版本进行修改了, 最终程序见附件“temp-detector.yaml”,“temp-detector.bin”是编译好的固件。注意要修改wifi配置为对应的wifi名字和密码。</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/eec21b53b2be4c19bb314465f1f27e5e.png" /></p>
<p style="line-height: 1.8;"> </p>
<h4 style="line-height: 1.8;">3.1 屏幕驱动</h4>
<p style="line-height: 1.8;">最开始想用ESPHome里自带的微雪驱动,但是不论用里面自带的那个尺寸的屏幕驱动都无法驱动我这块墨水屏。折腾了一天最后还是用佳显官方GDEW026T0D的驱动才搞定。</p>
<p style="line-height: 1.8;">当然佳显官方的驱动不能直接放到ESPHome里,它没有对ESPHome最适配。所以还得移植一下,具体有两种做法,一是直接在ESPHome中微雪的驱动上改,这种方法侵入性很大不推荐;二是把佳显的驱动做成一个ESPHome的component。</p>
<p style="line-height: 1.8;">为了快速实现功能,我先在微雪驱动上改,后续再做成一个component。具体修复方法如下:</p>
<p style="line-height: 1.8;">用pip show esphome命令找到esphome的安装路径。我这边安装路径是/opt/miniconda3/lib/python3.12/site-packages</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/8238b2dd3ed4479983334dd834e7905a.png" /></p>
<p style="line-height: 1.8;">然后打开这个路径下的文件/opt/miniconda3/lib/python3.12/site-packages/esphome/components/waveshare_epaper/waveshare_epaper.cpp进行修改。我在2.70inv2这个驱动的基础上进行修改,2.70inv2对应的类是WaveshareEPaper2P7InV2。需要改的函数有4个,首先修改get_width_internal和get_height_internal为屏幕的分辨率;接着修改初始化initialize函数,最后修改display函数即可。改完后如下:</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/fc1bc1f041fb4156983e224c40cdfc2a.png" /></p>
<p>修改好的waveshare_epaper.cpp文件见附件。</p>
<p> </p>
<h4 style="line-height: 1.8;">3.2 界面设计</h4>
<p style="line-height: 1.8;">对于墨水屏的界面设计,首先是要找到一个合适墨水屏的字体。以下代码用GothamRnd-Book.ttf字体在坐标(0,0)上显示文字“20:33 31.7°C”。可以看出显示效果不理想,文字边缘不光滑,颗粒感比较强;主要原因是灰阶数少,另外与墨水屏的DPI不高也有关。</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/9e393e529b1e49a8b81a0df0d19a49cb.png" /></p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/06ef19b2c06548eab78b886ce15092cd.jpg" alt="" width="838" height="415" /></p>
<p style="line-height: 1.8;">那什么样的字体适合在墨水屏上显示呢?很显然,没有斜边,直来直去的字体显示效果应该会很好。于是花了一个早上的时间看了1000来个像素风格的字体,测试了十来个字体后选择了Acme-9-Regular这个字体,显示效果如下:</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/e14abdd3c523413ab664c63fd287f71b.png" /></p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/8f5e2aa148d34bdf8440be9b5d195dfd.jpg" alt="" width="819" height="431" /></p>
<p style="line-height: 1.8;">这个文字的显示效果就光滑干净多了。</p>
<p style="line-height: 1.8;"><strong>注意:我对原版Acme-9-Regular字体做了一项调整,具体请看附录。</strong></p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">选定字体后,界面就设计就容易了。我把屏幕分成3个区域,左上角放天气信息(这部分暂时hardcode,后续再对接天气接口),右上角是时间,下面就是温湿度、TVOC和CO2的数值了。代码和效果如下:</p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/9b1ccc27d65140478fb31ff585636de9.png" /></p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/24cf5d2319d041e4973b05d71127359a.png" /></p>
<p style="line-height: 1.8;"><img src="//image.lceda.cn/oshwhub/cb0360923aff452ca54ba3b64ca677b8.jpg" alt="" width="814" height="420" /></p>
<p style="line-height: 1.8;">字体配置中glyphs指定了需要用到的字符,这样可以减少固件体积。所用到的字体文件见附件。</p>
<h3 style="line-height: 1.8;"> </h3>
<h3 style="line-height: 1.8;">4、低功耗</h3>
<hr />
<p style="line-height: 1.8;">ESP32-S3具有deep sleep模式10uA左右的电流;而温湿度传感器SHT40休眠电流20nA完全可以忽略不计,空气质量传感器SGP30休眠电流2uA。此外3.3V LDO选用超低静态电流的HE9073,静态电流可达0.3uA;由于SGP30的电压是1.8V,所以还需要一个1.8V的LDO,也是用HE9073。最后电压采集采用两个2.2MΩ分压电阻,消耗电流不大与3.3V / (2<em>2.2</em>10^6)=0.75uA。墨水屏休眠电流5uA。所以整个系统休眠电流理论上能控制在16.55uA以内。</p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">不开WiFi的情况下(每小时开一次WiFi获取天气信息),ESP32+传感器电流大约80mA,开WiFi电流去到150mA。为了更新墨水屏上的时间和传感器的值,需要每分钟采集传感器数据并更新墨水屏;此更新操作能在1秒内完成。因此ESP32每分钟运行1秒,deep sleep 59秒,每小时还开一次WiFi(为了加快WIFI连接,可以配置固定IP地址,整个过程大约2秒)。</p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">整个系统一小时的平均电流是(((80 <em> 1 + 0.01655 </em> 59) / 60) <em> 58 + 150 </em> 2) / 60=6.305mA;那么使用一个400mAh的锂电池,那么理论上续航时间是400/(6.305 <em> 24)=2.64天。如果墨水屏不显示时间,那么刷新间隔可以放长到1小时,此时每小时平均电流是(150 </em> 2 + 0.01655 <em> 3598) / 3600=0.100mA,续航可达400/(0.100 </em> 24)=166.7天(5个半月)。</p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;">对于功耗,还可以进一步优化,主要思路是降低CPU运行时间,首先CPU主频可以降低到40MHz。经实测墨水屏刷新操作大概400ms,之后的刷新操作都是屏幕驱动芯片在运行,ESP32进入休眠不影响墨水屏的刷新。传感器数据读取都可以在50ms内完成。所以我们可以在每次deep sleep唤醒CPU后,发送传感器读数据指令,在50ms后获取到最新数据,然后开始刷新屏幕,400ms后即可进入Deep Sleep模式。其次墨水屏使用局部刷新也许还能降低刷新时间。</p>
<p style="line-height: 1.8;"> </p>
<p style="line-height: 1.8;"><strong>注意:目前的代码中没有实现ESP32的deep sleep,这部分待补充。</strong></p>
<p style="line-height: 1.8;"> </p>
<h3 style="line-height: 1.8;">5、外壳设计</h3>
<hr />
<p>外壳未完成,待补充。</p>
<p style="line-height: 1.8;"> </p>
<h3 style="line-height: 1.8;">6、大赛LOGO验证</h3>
<hr />
<p style="line-height: 1.8;"><img src="//image.lceda.cn/pullimage/iLgr4WGsBiO4ICYanCK0UzydTmmxxy1J9mPEgyrb.jpeg" alt="" width="396" height="198" /></p>
<h3 style="line-height: 1.8;"> </h3>
<h3 style="line-height: 1.8;">7、项目属性</h3>
<hr />
<p style="line-height: 1.8;">此项目为原创,首次公开,无其他比赛获奖。</p>
<h3 style="line-height: 1.8;"> </h3>
<h3 style="line-height: 1.8;">8、开源协议</h3>
<hr />
<p>本项目遵循MIT开源协议。</p>
<h3 style="line-height: 1.8;"> </h3>
<h3 style="line-height: 1.8;">9、附录</h3>
<hr />
<h4>9.1 字体修改</h4>
<p>Acme-9-Regular字体中带有两个版本,一个是不带“Xtnd”的小间距字体“Acme 9 Regular.ttf”和“Acme 9 Regular Bold.ttf”,一个是带“Xtnd”的大间距字体“Acme 9 Regular Xtnd.ttf”和“Acme 9 Regular Bold Xtnd.ttf”。</p>
<p> </p>
<p>我小间距字体“Acme 9 Regular.ttf”作为时间专用字体,可以减少时间区域空间占用,“Acme 9 Regular Xtnd.ttf”作为其他信息的字体。</p>
<p> </p>
<p><strong>1)Acme 9 Regular.ttf的修改</strong></p>
<p>这个字体其实只改了一个地方,就是把数字1改成等宽的<strong>。</strong>下图左边是修改前的数据1,它比其他数字宽度要小,这样带来的问题是显示的时间包含了数字1的时候整个时间信息就往左边缩,因为数字1比其他数字宽度小。如果数字1宽度与其他数字的一样,那就不存在这个问题。下图右边是修改后的数字1。</p>
<p><img src="//image.lceda.cn/oshwhub/cb5e0eb39c8c444ba41b45d20081015e.png" /> <img src="//image.lceda.cn/oshwhub/8cdaf5b678d94f9bbe561c580e1c9483.png" /></p>
<p>修改方法是右击数字1,选“设置宽度”:</p>
<p><img src="//image.lceda.cn/oshwhub/32b0716bb9b74011adb21c3dd73bca67.png" /></p>
<p>在弹出来的窗口中输入1000,然后点确定:</p>
<p><img src="//image.lceda.cn/oshwhub/4dacc3331ac5427d9fe819b7e2957ac6.png" /></p>
<p>设置好宽度后数字1比较靠左边,还需要设置一下左边距。</p>
<p><img src="//image.lceda.cn/oshwhub/5dc9ae19779443b7b925e311b6a1aceb.png" /></p>
<p>点选数字1,然后选菜单“度量”再点“宽度三分之一”:</p>
<p><img src="//image.lceda.cn/oshwhub/9c3564bedbf4423983336379404520f3.png" /></p>
<p>设置好数字1如下:</p>
<p><img src="//image.lceda.cn/oshwhub/e1fcc496c40b474e8f80e8710c89acee.png" /></p>
<p>导出设置好的字体,点“文件”菜单,选“生成字体”:</p>
<p><img src="//image.lceda.cn/oshwhub/7af300d5010f447d8bab1671bd3d52c3.png" /></p>
<p>输入文件名,点“Generate”,后面弹出点警告窗口不管,按下面截图点即可成功导出字体文件。</p>
<p><img src="//image.lceda.cn/oshwhub/8edc0f2470cf40a49648d6ea8f2bf6b2.png" /> <img src="//image.lceda.cn/oshwhub/c6e6edf981e34bfeaa4071176ae88056.png" /><img src="//image.lceda.cn/oshwhub/e10ddaf29e4a495c867707fcf90bd6a3.png" /></p>
<p> </p>
<p><strong>2)Acme 9 Regular Xtnd.ttf的修改</strong></p>
<p>这个字体主要改了百分号“%”和摄氏度的“°”,因为我觉得原版的不是很好看。这个修改就是自己画字符,没有太多技巧,下面是修改前后效果。</p>
<table style="border-collapse: collapse; width: 24.2991%; height: 260.188px;" border="0">
<tbody>
<tr style="height: 122.594px;">
<td style="width: 49.4461%; height: 122.594px;"><img src="//image.lceda.cn/oshwhub/c864a2b029434bdd866ef830479a4369.png" /></td>
<td style="width: 50.5539%; height: 122.594px;"><img src="//image.lceda.cn/oshwhub/c57ce66c38584e078f7333932efb1b08.png" /></td>
</tr>
<tr style="height: 137.594px;">
<td style="width: 49.4461%; height: 137.594px;"><img src="//image.lceda.cn/oshwhub/76a2ac3e4f72460c999f394330aa2dbe.png" /></td>
<td style="width: 50.5539%; height: 137.594px;"><img src="//image.lceda.cn/oshwhub/3bfc2aeacf4f44b6a64b4282e7b0c3ee.png" /></td>
</tr>
</tbody>
</table>
<p>字体导出方法跟上面的一样。</p></p>
评论(4)