ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ESP32-S3墨水屏骑行码表DIY:GPS速度里程离线显示

ESP32-S3墨水屏骑行码表DIY:GPS速度里程离线显示 1. 为什么我要把一块墨水屏开发板改成骑行码表骑行码表这个东西说贵不贵说便宜也不便宜。市面上带GPS、能记录轨迹、续航过得去的码表动辄大几百上千。但如果你跟我一样骑车的时候其实只需要看几个核心数据——当前速度、骑行时长、总里程、时间——那花大价钱买一堆用不上的功能多少有点浪费。更关键的是我手上正好有一块LILYGO的墨水屏开发板型号是T5 4.7英寸那款主控是ESP32-S3屏幕是E042A13这个型号的电子墨水屏。这块板子买回来本来是想做电子价签或者桌面信息屏的结果吃灰了小半年。某天骑车出门手机架在车把上又怕颠坏、又怕太阳晒突然就想为什么不把这块墨水屏改成一台离线骑行码表墨水屏做骑行码表有几个天然优势是普通LCD比不了的。第一阳光下可读性极强LCD在强光下基本看不清墨水屏反而越晒越清楚。第二断电之后画面还能保留停车休息的时候数据不会消失。第三功耗极低刷新一次才耗一点电配合ESP32-S3的深度睡眠续航可以做到非常夸张。第四ESP32-S3自带WiFi和蓝牙虽然我们做的是离线码表但调试和后续扩展都很方便。这个项目的核心思路很简单用ESP32-S3读取GPS模块的数据解析出速度、里程、时间这些信息然后驱动墨水屏刷新显示。整个系统完全离线运行不需要联网不需要手机开机就能用。适合有一定嵌入式基础、玩过ESP32、想找个实用项目练手的开发者。如果你连Arduino都没碰过建议先补一下基础但也不用怕我会把关键步骤和踩坑点都讲清楚。2. 硬件选型与接线别小看那几根杜邦线2.1 LILYGO T5 4.7英寸开发板到底是个什么板子LILYGO T5这块板子核心是ESP32-S3这是一颗双核Xtensa LX7处理器主频最高240MHz自带512KB SRAM和8MB PSRAM具体版本有差异我手上这块是8MB PSRAM的版本。屏幕是4.7英寸的电子墨水屏分辨率960x540型号E042A13。这个分辨率对于骑行码表来说绰绰有余显示速度、时间、里程、电量这些信息完全够用。板子上自带的接口比较丰富有USB Type-C用于供电和烧录有电池接口可以直接接锂电池还有一组扩展IO口。墨水屏通过SPI接口和ESP32-S3通信板子已经做好了电平转换和驱动电路我们不需要自己搞升压电路这点省了很多事。需要注意的是这块板子的墨水屏驱动芯片是ED047TC1和常见的Waveshare或者微雪那套驱动不太一样。LILYGO官方提供了Arduino库和PlatformIO的支持但文档写得比较散很多细节要自己翻源码。我建议直接用PlatformIO来开发因为Arduino IDE对ESP32-S3的支持虽然也能用但库管理和编译速度都不如PlatformIO舒服。2.2 GPS模块的选择为什么我最终用了ATGM336HGPS模块的选择上我试过三种方案。第一种是常见的NEO-6M便宜、资料多但定位速度慢冷启动要一分多钟而且天线是陶瓷的在骑行震动环境下容易接触不良。第二种是NEO-M8N性能好很多但价格也上去了而且模块体积偏大。第三种是ATGM336H中科微的芯片支持GPS北斗双模冷启动30秒左右热启动1秒价格只要二十多块体积也小。最终我选了ATGM336H原因有三个。第一双模定位在骑行场景下更可靠城市里高楼多单GPS容易丢星北斗补充上来之后定位稳定性明显提升。第二它输出的是标准NMEA协议解析起来和NEO系列一样代码不用大改。第三它支持3.3V和5V供电和ESP32-S3的3.3V电平直接匹配不需要额外的电平转换。接线方面ATGM336H和ESP32-S3之间只需要四根线VCC接3.3VGND接GNDTX接ESP32-S3的RX我用的GPIO18RX接ESP32-S3的TX我用的GPIO17。这里有个坑要注意ESP32-S3的默认硬件串口是GPIO43和GPIO44但这两个脚在T5板子上被墨水屏占用了。所以我们必须用SoftwareSerial或者ESP32的第二个硬件串口。我建议用硬件串口因为SoftwareSerial在高速波特率下容易丢数据。ESP32-S3有两个硬件串口Serial0给USB调试用Serial1可以映射到任意GPIO我映射到了17和18。2.3 供电方案一块18650能撑多久供电我用了一块18650锂电池标称3.7V容量2600mAh。T5板子自带锂电池充电电路直接插上就能充。墨水屏的功耗在刷新时大约20mA静态显示时几乎为零。ESP32-S3在正常运行时大约40mA深度睡眠时只有10uA左右。GPS模块ATGM336H的工作电流大约25mA。如果一直开着GPS和屏幕刷新总电流大约85mA2600mAh的电池大概能撑30小时。但实际骑行中我们不需要一直刷新屏幕可以设置成每5秒刷新一次GPS也可以设置成1Hz的输出频率。这样平均电流能降到50mA左右续航能到50小时以上。如果进一步优化比如在停车时让ESP32进入深度睡眠GPS也断电那续航可以做到一周以上。这里有个细节墨水屏刷新需要升压电路T5板子上的升压芯片在刷新瞬间会有电流尖峰如果电池电量低或者电池内阻大可能会导致刷新失败或者屏幕花屏。我建议用质量好一点的18650比如松下或者三星的内阻小的电池更稳。3. 开发环境搭建从VSCode到PlatformIO的完整链路3.1 为什么我不推荐用Arduino IDEArduino IDE对ESP32-S3的支持是通过ESP32 Arduino Core实现的安装起来不算复杂但有几个问题让我最终放弃了它。第一库管理混乱LILYGO的墨水屏库和其他的库经常冲突版本依赖很难搞。第二编译速度慢ESP32-S3的代码量稍微大一点编译一次要一两分钟。第三串口监视器功能太弱调试GPS数据的时候很不方便。PlatformIO就不一样了它是VSCode的插件底层用的是Python的platformio-core库管理用的是platformio.ini配置文件版本锁定很清晰。编译速度也比Arduino IDE快不少而且串口监视器支持时间戳、日志过滤这些功能调试起来舒服很多。3.2 在VSCode里搭建ESP32-S3开发环境的详细步骤首先你需要安装VSCode。去官网下载对应系统的安装包一路下一步就行。安装完成后打开VSCode点击左侧的扩展图标搜索PlatformIO IDE点击安装。安装过程会下载一些依赖可能需要几分钟耐心等。安装完成后VSCode左侧会出现一个蚂蚁头图标那就是PlatformIO。点击它选择PIO Home然后点击New Project。项目名称随便起比如bike-computer。Board选Espressif ESP32-S3-DevKitC-1Framework选Arduino。注意LILYGO T5的板子虽然用的是ESP32-S3但它的Flash和PSRAM配置和官方DevKitC-1不完全一样所以创建完项目后需要手动改platformio.ini。打开项目根目录下的platformio.ini改成下面这样[env:lilygo-t5-47] platform espressif32 board esp32-s3-devkitc-1 framework arduino monitor_speed 115200 upload_speed 921600 board_build.flash_mode qio board_build.psram_type opi board_build.partitions default_16MB.csv build_flags -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE1 -DARDUINO_USB_CDC_ON_BOOT1 lib_deps https://github.com/Xinyuan-LilyGO/LilyGo-EPD47.git mikalhart/TinyGPSPlus^1.0.3这里有几个关键点。board_build.psram_type opi是因为T5板子的PSRAM是OPI接口的不设置的话PSRAM用不了。ARDUINO_USB_CDC_ON_BOOT1是为了让串口输出走USB CDC这样你只需要一根Type-C线就能同时烧录和看日志。lib_deps里引用了LILYGO官方的EPD47库这个库是驱动E042A13屏幕的关键。3.3 烧录第一个测试程序让屏幕亮起来环境搭好之后先别急着写码表逻辑第一步是让屏幕能显示东西。LILYGO的EPD47库自带了一些示例在.pio/libdeps/lilygo-t5-47/LilyGo-EPD47/examples目录下。你可以把HelloWorld示例的代码复制到你的src/main.cpp里然后点击PlatformIO的Upload按钮烧录。烧录的时候有个坑ESP32-S3进入下载模式需要手动操作。按住板子上的BOOT键然后按一下RST键松开RST再松开BOOT这时候板子就进入下载模式了。如果你用的是PlatformIO的Upload它会自动尝试进入下载模式但有时候会失败手动操作更稳。烧录成功后屏幕会刷新显示一段文字。如果屏幕没反应先检查串口日志有没有报错。常见的错误是PSRAM初始化失败那就要检查board_build.psram_type设置对不对。还有一个可能是墨水屏的排线没插紧T5板子的排线是FPC插座要确保卡扣扣好。4. GPS数据解析与速度里程计算的核心逻辑4.1 NMEA协议到底在说什么ATGM336H输出的NMEA语句有很多种我们只需要关心其中三条GPRMC、GPGGA、GPGSV。GPRMC是推荐最小定位信息包含时间、日期、经纬度、速度、航向。GPGGA是GPS定位信息包含定位质量、卫星数、海拔。GPGSV是可见卫星信息用来判断信号强度。GPRMC的格式是这样的$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A字段依次是UTC时间、状态A有效V无效、纬度、北纬/南纬、经度、东经/西经、地面速度节、航向、日期、磁偏角。我们需要的速度就是第7个字段单位是节1节等于1.852公里每小时。TinyGPSPlus这个库已经把NMEA解析封装好了我们不需要自己写字符串分割。用起来很简单#include TinyGPSPlus.h TinyGPSPlus gps; void loop() { while (Serial1.available() 0) { gps.encode(Serial1.read()); } if (gps.location.isUpdated()) { double speed_kmh gps.speed.kmph(); double lat gps.location.lat(); double lng gps.location.lng(); // 后续处理 } }这里要注意gps.speed.kmph()返回的是浮点数但墨水屏刷新慢我们不需要那么高的精度取整就行。4.2 里程计算的两种方案GPS积分 vs 轮速传感器里程计算有两种思路。第一种是GPS积分每次定位更新时计算当前点和上一个点的距离累加起来。第二种是轮速传感器在车轮上装霍尔传感器每转一圈记一次数乘以轮周长就是里程。我最终选了GPS积分原因很简单不用额外装传感器不用校准轮周长而且GPS积分在开阔路面上精度足够。但GPS积分有个问题如果信号丢失或者漂移里程会跳变。解决办法是设置一个速度阈值只有速度大于1km/h时才累加里程同时如果两次定位之间的距离超过100米明显是漂移就丢弃这次数据。距离计算用Haversine公式double haversine(double lat1, double lon1, double lat2, double lon2) { double dLat radians(lat2 - lat1); double dLon radians(lon2 - lon1); double a sin(dLat/2) * sin(dLat/2) cos(radians(lat1)) * cos(radians(lat2)) * sin(dLon/2) * sin(dLon/2); double c 2 * atan2(sqrt(a), sqrt(1-a)); return 6371000 * c; // 地球半径单位米 }这个公式在短距离计算上精度很高骑行场景完全够用。4.3 速度平滑为什么原始GPS速度不能直接显示GPS输出的速度是瞬时速度波动很大。你匀速骑20km/hGPS可能一会儿显示18一会儿显示23。直接显示的话数字跳来跳去看着很难受。解决办法是做滑动平均。我用的是一阶低通滤波公式是平滑速度 0.8 * 上次平滑速度 0.2 * 当前速度。这个系数可以根据实际体验调整0.8意味着新数据权重20%响应不会太慢也不会太跳。如果你想要更平滑可以把0.8改成0.9但那样加速减速的时候显示会滞后。还有一个细节GPS在低速时比如等红灯速度会归零但定位还在漂移这时候如果累加里程会凭空多出几百米。所以我在速度小于1km/h时暂停里程累加同时把显示速度直接置零。5. 墨水屏刷新策略如何做到既省电又不闪瞎眼5.1 墨水屏的刷新模式全刷和局刷的区别E042A13这块墨水屏支持全刷和局刷两种模式。全刷是整个屏幕重新绘制会有一次明显的黑白闪烁大概需要2秒。局刷是只更新变化的部分闪烁不明显速度快很多大概0.5秒。骑行码表上速度数字一直在变如果每次都用全刷屏幕会一直闪体验极差。所以必须用局刷。但局刷有个问题刷新次数多了之后屏幕会有残影就是之前显示的内容会淡淡地留在背景上。解决办法是每隔一定次数比如50次局刷做一次全刷清除残影。LILYGO的EPD47库提供了epd_poweron()、epd_clear()、epd_poweroff()这些函数但局刷的API在示例里不太明显。我翻源码找到了epd_draw_grayscale_image和epd_push_pixels这些底层函数但用起来比较复杂。后来我发现库里有epd_update()和epd_update_partial()前者是全刷后者是局刷。局刷需要传入一个矩形区域指定要更新的范围。5.2 我的刷新策略分区刷新加定时全刷我的策略是这样的屏幕分成几个区域速度区域每2秒局刷一次时间区域每60秒局刷一次里程区域每10秒局刷一次。每50次局刷后做一次全刷清残影。具体实现上我用了一个计数器partial_count每次局刷加一到50就触发全刷并清零。局刷的区域用矩形坐标定义比如速度区域是(100, 200, 400, 300)表示从x100,y200开始宽400高300的矩形。这里有个坑局刷的矩形坐标必须是8的倍数因为墨水屏的驱动是按字节操作的。如果坐标不是8的倍数刷新区域会错位显示会花。我一开始没注意速度数字总是显示不全后来把坐标都对齐到8的倍数就好了。5.3 省电优化深度睡眠和GPS断电骑行码表大部分时间其实是在骑行中但如果你中途停下来休息屏幕和GPS还在工作就浪费电了。我加了一个自动休眠逻辑如果速度连续5分钟为0ESP32-S3进入深度睡眠GPS模块通过一个MOS管断电。唤醒方式是按板子上的BOOT键或者晃动板子如果你装了加速度传感器。深度睡眠的代码很简单esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0); // BOOT键唤醒 esp_deep_sleep_start();但要注意深度睡眠后所有变量都会丢失里程数据要存在RTC内存或者Flash里。我用了RTC内存因为写入速度快不伤Flash。RTC内存的用法是RTC_DATA_ATTR double total_distance;这样变量在深度睡眠后还能保留。6. 外壳与安装怎么把开发板固定在车把上6.1 3D打印外壳的设计要点开发板裸奔在车把上肯定不行颠簸几下就掉了而且不防水。我设计了一个简单的3D打印外壳用PETG材料耐候性好一点。外壳分两部分底座和盖板。底座固定在车把上用扎带或者螺丝卡箍。盖板用M3螺丝拧在底座上中间夹一层防水胶条。设计的时候有几个要点。第一屏幕开窗要精确E042A13的显示区域是103.5mm x 58.2mm开窗要比这个略大一点留0.5mm余量。第二USB接口要留孔方便充电和烧录。第三GPS天线要朝上所以外壳顶部要留一个凹槽让陶瓷天线露出来。第四按键要留孔BOOT键和RST键要能按到。如果你没有3D打印机也可以用现成的防水盒改造比如淘宝上那种接线盒用美工刀挖孔也行就是丑一点。6.2 车把固定的几种方案对比固定方案我试过三种。第一种是扎带最简单但扎带时间长了会老化断裂而且不防震。第二种是硅胶绑带比如那种手机支架用的弹性好防震但绑不紧的话屏幕会晃。第三种是螺丝卡箍最稳但需要车把直径匹配而且拆装麻烦。我最终用了硅胶绑带加防滑垫的组合。绑带绕车把两圈防滑垫垫在开发板和车把之间这样既稳又防震。实测骑了200多公里没有松动。6.3 防水处理骑行遇到下雨怎么办墨水屏本身不防水ESP32-S3也不防水。我的做法是外壳用防水胶条密封USB口用硅胶塞堵住。但如果你遇到大雨还是建议把码表拆下来放口袋里。另外屏幕表面可以贴一层透明防水膜不影响显示但能防泼溅。7. 实测数据与踩坑记录7.1 速度精度对比GPS码表 vs 手机码表我同时用手机上的骑行APP和自制的码表骑了10公里对比数据。手机APP显示平均速度22.3km/h自制码表显示22.1km/h差距在1%以内。最大速度手机显示38.5自制显示37.9差距1.5%。这个精度对于骑行来说完全够用毕竟我们不是做专业计时。7.2 续航实测从满电到关机2600mAh的18650满电4.2V。我设置的是速度区域每2秒局刷GPS 1Hz输出没有开深度睡眠。连续骑行4小时电量从4.2V降到3.6V估计还能再撑2小时。如果开启深度睡眠停车时自动休眠续航可以轻松超过20小时。7.3 踩过的坑那些让我熬夜调试的问题第一个坑是PSRAM初始化失败。我一开始没在platformio.ini里设置board_build.psram_type opi结果屏幕能显示但一刷新就崩溃。后来看串口日志发现PSRAM malloc失败才意识到是PSRAM没启用。第二个坑是GPS数据乱码。我用SoftwareSerial接GPS波特率9600但数据总是丢。后来换成硬件串口Serial1问题解决。ESP32-S3的SoftwareSerial在9600下还算稳但如果你同时有WiFi或者蓝牙任务就会丢数据。第三个坑是墨水屏局刷残影。我一开始没做定时全刷骑了半小时后屏幕上一片 ghosting速度数字叠在一起看不清。后来加了每50次局刷全刷一次问题解决。第四个坑是电池低压时屏幕花屏。18650电量低于3.4V时墨水屏刷新会失败屏幕出现横向条纹。解决办法是加一个低压检测电量低于3.5V时在屏幕上显示低电量警告并停止刷新。8. 后续可以扩展的方向这个码表目前只显示了速度、时间、里程、电量。其实ESP32-S3还有很大的发挥空间。比如可以加一个SD卡模块记录轨迹GPX文件回来导到电脑上看。可以加一个BME280传感器显示温度和气压气压还能用来算海拔。可以加一个蓝牙模块把数据传到手机上的APP。甚至可以加一个太阳能板边骑边充电。但我觉得最实用的扩展是加一个自动背光或者前灯控制。ESP32-S3的GPIO可以驱动一个MOS管控制车灯开关。光线传感器检测到环境变暗自动开灯。这样夜骑的时候不用手动操作安全很多。我个人在实际使用中的体会是墨水屏做骑行码表最大的优势不是省电而是那种“看一眼就清楚”的体验。LCD在太阳底下要用手遮着看墨水屏是越亮越清楚。而且它不发光晚上骑车不会晃眼睛。如果你手头正好有一块吃灰的墨水屏开发板真的建议试试这个项目成本不到一百块但实用性远超预期。
返回列表