Repository: Eddddddddy/Songguo-PTS200
Branch: main
Commit: 4d7a19397737
Files: 12
Total size: 89.8 KB
Directory structure:
gitextract_rrchcozt/
├── .gitignore
├── Power Calculator.numbers
├── Power Calculator.xlsx
├── README.md
├── SolderingPen_ESP32S2/
│ ├── Languages.h
│ ├── PTS200_16.h
│ ├── SolderingPen_ESP32S2.ino
│ ├── UtilsEEPROM.h
│ └── config.h
├── boards/
│ └── PTS200.json
├── docs/
│ └── update_guide.md
└── platformio.ini
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
.pio
.vscode
.DS_Store
.idea
SolderingPen_ESP32S2/build
SolderingPen_ESP32S2/.idea
================================================
FILE: README.md
================================================
# Songguo PTS200
## Introduction
1. PD3.0 and QC3 fast charge protocol
2. 20V 5A 100W maximum power
<!-- 内置IMU,用于休眠检测 -->
3. Built-in IMU for sleep detection
<!-- PD协议芯片使用CH224K -->
4. PD protocol chip uses CH224K
<!-- MOSFET支持30V 12A -->
5. MOSFET supports 30V 12A
<!-- MCU使用ESP32 S2 FH4 -->
6. MCU uses ESP32 S2 FH4
<!-- 电源输入使用功率加强的USB-C接口 -->
7. The power input uses a power-enhanced USB-C interface
<!-- 定制的4欧姆内阻的烙铁头 -->
8. Customized soldering tip with 4 ohm internal resistance. It can be powered by 20V with 100W.
<!-- 128x64 OLED screen -->
9. 128x64 OLED screen
<!-- 3个按键,中间的按键与GPIO0相连 -->
10. 3 buttons, the middle button is connected to GPIO0
<!-- MSC 模式的固件升级,闪存盘模式 -->
11. MSC firmware upgrade, flash disk mode
<!-- 带有便携式的尖端保护盖 -->
12. With a portable tip cap
<!-- 构建方法 -->
## Build method
<!-- Arduino with ESP32 环境 -->
1. Arduino with ESP32 environment
<!-- 安装依赖库 -->
2. Install dependent libraries: Button2, U8g2, QC3Control, ESP32AnalogRead, PID_v1, SparkFun_LIS2DH12
<!-- 从U8G2库中替换u8g2_fonts.c文件 -->
3. Replace the u8g2_fonts.c file from the U8G2 library
<!-- 在Arduino 中选择Tools- USB CDC On Boot- Enable -->
4. In Arduino, select Tools-USB CDC On Boot-Enable
<!-- 在Arduino 中选择Tools-Upload Mode- Internal USB -->
5. In Arduino, select Tools-Upload Mode-Internal USB
<!-- 点击上传 -->
6. Click Upload
================================================
FILE: SolderingPen_ESP32S2/Languages.h
================================================
// 菜单项
const uint8_t language_types = 3;
// "温控类型", "溫控類型", "Control Type",
const char *SetupItems[][language_types] = { "菜单设置", "菜單設置", "Setup Menu",
"烙铁头设置", "烙鐵頭設置", "Tip Settings",
"温度设置", "溫度設置", "Temp Settings",
"时间设置", "時間設置", "Timer Settings",
"主屏幕", "主屏幕", "Main Screen",
"信息", "信息", "Information",
"电压设置", "電壓設置", "Voltage",
"QC", "QC", "QC",
"蜂鸣器", "蜂鳴器", "Buzzer",
"恢复默认设置", "恢復默認設置", "Restore Config",
"更新版本", "更新版本", "Update Firmware",
"Languages", "Languages", "Languages",
"切换左右手", "切换左右手", "L/R Hand",
"返回", "返回", "Return" };
const char *LanguagesItems[][language_types] = { "Languages", "Languages", "Languages",
"简体中文", "简体中文", "zh-CN",
"繁体中文", "繁体中文", "zh-TW",
"English", "English", "English" };
const char *TipItems[][language_types] = { "烙铁头:", "烙鐵頭:", "Tip:",
"更换烙铁头", "更換烙鐵頭", "Change Tip",
"校准烙铁头", "校準烙鐵頭", "Calibrate Tip",
"重命名烙铁头", "重命名烙鐵頭", "Rename Tip",
"删除烙铁头", "刪除烙鐵頭", "Delete Tip",
"新建烙铁头", "新建烙鐵頭", "New Tip",
"返回", "返回", "Return" };
const char *TempItems[][language_types] = { "温度设置", "溫度設置", "Temp Settings",
"默认温度", "默認溫度", "Default Temp",
"休眠温度", "休眠溫度", "Sleep Temp",
"提高温度", "提高溫度", "Boost Temp",
"返回", "返回", "Return" };
const char *TimerItems[][language_types] = { "时间设置", "時間設置", "Timer Settings",
"休眠时间", "休眠時間", "Sleep Timer",
"关闭时间", "關閉時間", "Shutdown Timer",
"提温时间", "提溫時間", "Boost Timer",
"唤醒阈值", "唤醒閾值", "Wake Threshold",
"返回", "返回", "Return" };
const char *ControlTypeItems[][language_types] = { "温控类型", "溫控類型", "Control Type",
"非PID", "非PID", "Non-PID",
"PID", "PID", "PID" };
const char *MainScreenItems[][language_types] = {
"主屏幕",
"主屏幕",
"Main Screen",
"大数字",
"大數字",
"Big Number",
"更多信息",
"更多信息",
"More Info",
};
const char *StoreItems[][language_types] = { "存储设置?", "存儲設置?", "Save?",
"否", "否", "No",
"是", "是", "Yes" };
const char *DefaultItems[][language_types] = { "恢复设置?", "恢復設置?", "Restore?",
"否", "否", "No",
"是", "是", "Yes" };
const char *SureItems[][language_types] = { "确定?", "確定?", "Sure?",
"否", "否", "No",
"是", "是", "Yes" };
const char *VoltageItems[][language_types] = { "电压设置", "電壓設置", "Voltage Settings",
"9V", "9V", "9V",
"12V", "12V", "12V",
"15V", "15V", "15V",
"20V(50%)", "20V(50%)", "20V(50%)",
"20V(100%)", "20V(100%)", "20V(100%)"};
const char *QCItems[][language_types] = { "QC", "QC", "QC",
"禁用", "禁用", "Disable",
"启用", "啟用", "Enable" };
const char *BuzzerItems[][language_types] = { "蜂鸣器", "蜂鳴器", "Buzzer",
"禁用", "禁用", "Disable",
"启用", "啟用", "Enable" };
const char *DefaultTempItems[][language_types] = { "默认温度", "默認溫度", "Default Temp",
"deg C", "deg C", "deg C" };
const char *SleepTempItems[][language_types] = { "休眠温度", "休眠溫度", "Sleep Temp",
"deg C", "deg C", "deg C" };
const char *BoostTempItems[][language_types] = { "提高温度", "提高溫度", "Boost Temp",
"deg C", "deg C", "deg C" };
const char *SleepTimerItems[][language_types] = { "休眠时间", "休眠時間", "Sleep Timer",
"秒", "秒", "sec" };
const char *WAKEUPthresholdItems[][language_types] = { "唤醒阈值", "唤醒閾值", "Wake Threshold",
"mg", "mg", "mg" };
const char *OffTimerItems[][language_types] = { "关闭时间", "關閉時間", "Shutdown Timer",
"分钟", "分鐘", "min" };
const char *BoostTimerItems[][language_types] = { "提温时间", "提溫時間", "Boost Timer",
"秒", "秒", "sec" };
const char *DeleteMessage[][language_types] = { "警告", "警告", "Warning",
"你不能", "你不能", "You can't",
"删除你的", "刪除你的", "delete your",
"最后的烙铁头!", "最後的烙鐵頭!", "last tip!" };
const char *MaxTipMessage[][language_types] = { "警告", "警告", "Warning",
"你已达", "你已達", "You reached",
"最大数量", "最大數量", "maximum number",
"的烙铁头!", "的烙鐵頭!", "of tips!" };
const char *txt_set_temp[] = { "设温:", "設溫:", "SET:" };
const char *txt_error[] = { "错误", "錯誤", "ERROR" };
const char *txt_off[] = { "关闭", "關閉", "OFF" };
const char *txt_sleep[] = { "休眠", "休眠", "SLEEP" };
const char *txt_boost[] = { "提温", "提溫", "BOOST" };
const char *txt_worky[] = { "工作", "工作", "WORK" };
const char *txt_on[] = { "加热", "加熱", "HEAT" };
const char *txt_hold[] = { "保持", "保持", "HOLD" };
const char *txt_Deactivated[] = { "禁用", "禁用", "Deactivated" };
const char *txt_temp[] = { "温度:", "溫度:", "TEMP:" };
const char *txt_voltage[] = { "电压:", "電壓:", "VOLT:" };
const char *txt_Version[] = { "版本:", "版本:", "VER:" };
const char *txt_select_tip[] = { "选择烙铁头", "選擇烙鐵頭", "Select Tip" };
const char *txt_calibrate[] = { "校准", "校準", "Calibrate" };
const char *txt_step[] = { "步进", "步進", "Step" };
const char *txt_set_measured[] = { "设为测量", "設為測量", "Set Measure" };
const char *txt_s_temp[] = { "的温度:", "的溫度:", "Temp:" };
const char *txt_temp_2[] = { "温度: ", "溫度: ", "Temp: " };
const char *txt_wait_pls[] = { "请稍等...", "請稍等...", "Please wait ..." };
const char *txt_enter_tip_name[] = { "输入烙铁头名称", "輸入烙鐵頭名稱", "Enter Tip Name" };
================================================
FILE: SolderingPen_ESP32S2/PTS200_16.h
================================================
/*
Fontname: -FreeType-Alibaba PuHuiTi Medium-Medium-R-Normal--16-120-96-96-P-142-ISO10646-1
Copyright: Copyright � 2019 Alibaba (China) Co., Ltd. All rights reserved.
Glyphs: 244/28936
BBX Build Mode: 0
*/
// #include "U8g2lib.h"
const uint8_t PTS200_16[7917] U8G2_FONT_SECTION("PTS200_16") =
"\365\0\3\2\4\5\4\5\6\20\21\377\375\13\375\15\377\1\324\4\1\5\234 \6\0\20\242\0!\10\341"
"\366\241x\210\4\42\12\65R\243P\224HJ\0#\30\310\20\242\213\302(\214\242a\210\212Q\30\205Q"
"\64\14Q\61\12\243\14$\24\327\360\241K\267\244)\222\302$]\223\60\222*mk\6%\27\327\360\241"
"\321\244\244\224\224\64%\215\323\70\221\222()I\221\246\0&\25\307\20\242\22\243,\312\222\64\216*M"
"I-\312\242J\244\5'\10\62V\243P\24\0(\14\344\362\241\213jQ\326c\26\26)\15\344\364\241"
"\10ka\326S\26\325\0*\17\227P\242\213\263\250\322\266%M\265\70\3+\24\251.\242\314\221\34\311"
"\221p\70\346H\216\344H\216\204\0,\10B\324\241\30\22\5-\7\27\320\242\70\4.\7\42\364\241\30"
"\2/\17\306\22\242-\246a\32\246a\32\246)\0\60\15\267\22\252\332*\251_\223,\233\0\61\11\265"
"\26\252\30\373\247A\62\15\267\22\252\332*i\134\355u\30\2\63\23\267\22\252\31\242\60\7\342\64\333\201"
"\34\210\305h\210\0\64\25\270\22\252\215\325$\214\262R\30\205\321\60\250\71\220\3\21\0\65\20\267\22\252"
"\270\304-\223\226\3q,FC\4\66\20\267\22\252\332*qe\322\222\324\232d\331\4\67\15\267\22\252"
"\70\304i\134\215\253q\15\70\21\267\22\252\332JY\224e[%\265&Y\66\1\71\20\267\22\252\332*"
"\251\65\311\244%\256d\331\4:\11\202V\242\30rd\10;\13\262\366\241\30rlH\24\0<\21\327"
"\360\241N\373\16\344@\16\344@\16\344@\0=\12G\220\242\70\344\204C\0>\21\327\360\241\310\201\34"
"\310\201\34\310\201\34H\373\14\77\16\306\22\242\322\242$\24[\353\264\64\2@\24\230\60\242\32\262\60\211"
"\214\211\264(Q\42-\305l\210\0A\27\271\20\252\314\221\34H\342$\315\302\254\32\15C\224&\71\240"
"\3\1B\22\267\22\252\30\244\60I\215\311 \205IjL\6\11C\26\270\22\252\33\262\60\211s \7"
"r \7r$G\302lH\0D\30\271\22\262\70Dq\222\3:\240\3:\240\3:\240\3r\62\14"
"\21\0E\16\267\22\246\70\310\315\303 \67\17C\0F\14\267\22\246\70\310\315\303\22w\6G\27\271\22"
"\262\32\246XGr$G\302A\7t@\7\222\70\32\206\0H\26\271\22\256\310\1\35\320\1\35\320\201"
"\7\35\320\1\35\320\1\35\10I\7\261\24\222x\20J\12\344\256\221\353\377\224H\0K\23\270\22\252\210"
"\325$\214\262R\270FaV\214\322$\16L\12\267\22\242\210\373\347a\10M\34\273\22\266\320\201!\7"
"\226\64Q\322D\312\42)\213\264$\323\222L\14uH\207\2N\24\270\22\256PW%TB)\223\62"
"-\322\42\61\21\23UO\27\272\22\262\33\322\60\213\223\34\321\21\35\321\21\35)ga:d\0P\15"
"\267\22\246\270\244^\207!\211\233\1Q\32\332\322\261\33\322\60\213\223\34\321\21\35\321\21\35)ga:"
"\344X\216%\0R\25\270\22\252\70\245I\232\244I\30\15Z\30\205Q\232\244I\34S\22\267\22\252\332"
"*q\16\344\300\16\344@,FC\4T\25\271\20\246x\314\221\34\311\221\34\311\221\34\311\221\34\311\221"
"\20U\14\270\22\256\210\375s\22fC\4V\27\271\20\252\310\1\35\320\201$\215\322\254\230\245I\234\344"
"@\216\204\0W\37\275\22\276HS\65U+Y\222EY\222EY\222U\262$L\262$L\262$-"
"\247\31\0X\27\271\22\252\310\1\35H\322\254\232\344@\16$iVMr@\7\2Y\20\267\22\246H"
"\325$\213\262J\230\244q\67\0Z\16\270\22\252\70\350@\334\357@\16\34\4[\12\344\364\241\30\264\376"
"\267!\134\24\347\360\241\210s \316\201\70\7\342\34\210s \316\201\70]\12\344\364\241\30\262\376\267A"
"^\12GP\243K\223\254\222\6_\7\27\320\241\70\4`\7D\24\243\10\33a\21\207\22\246\31\242\60"
"\216\6%L\302$\214\206$b\17\267\22\252\210[&-I]\267$\231\0c\14\206\22\242\32\222\60"
"m\216\207\0d\16\267\22\252nZj\253k\222IK\0e\16\207\22\246\332*\351p\316\201,\233\0"
"f\14\265\20\226\223\302h\220\302>\1g\20\267\262\251Zj\253k\222IK\234FC\4h\14\267\22"
"\252\210[&-I}\15i\10\261\24\222P\206Aj\12\343\260\221\252F\375i\1k\20\266\22\246H"
"\333\222\250\222\211I\26\325\222\60l\7\261\24\222x\20m\22\213\24\276H\246E\63\206b(\206b("
"\206b\1n\13\207\22\252H\206DT}\15o\15\207\22\246\332*\251k\222e\23\0p\20\267\262\251"
"H&-I]\267$\231\342\62\0q\16\267\262\251Zj\253k\222IK\334\0r\12\205\22\232H\6"
"-\354\21s\14\206\22\242\31\222PvL\206\4t\13\245\20\232\12\243A\12{\25u\12\206\24\252\10"
"\375\246,\1v\17\207\22\246H\255I\26e\225\60I\63\0w\30\213\22\262\10C\61\324\222,\211\222"
"\250\222%Q\222%Y\32\246\21\0x\17\207\22\246H\223\254\222\306i\222U\322\0y\22\267\262\245H"
"\325$\213\262J\230\244q\32\207*\0z\12\206\22\242\270\206\275\16\3{\14\343\364\241J\242.Q\26"
"u\13|\7\1\327\241\370!}\15\343\364\241\310\242nQ\22u\211\0~\11\67\260\242\21\243\242\2\200"
"\22\307\20\242\333*q:h\351\240\305u \313\26\0\0\0\0\4\377\377N\15&\17\321\301\207\223\341"
";\222\23r\70'\344\260\222cI\224#Q\246f\241\26\246Q\232\23rBN\310\11\71\0N- "
"\16\323\301\316\341\34N\223\341k%\255\244\225\264\62<$i\35\310\341\34\316\341\34\316\341\34N:,"
"\17\321\301Gr(\314\61)\7\243\234\20&\303w \315\221\64\7\342\34H\302\70\223\342\60Js$"
"\314\241,\7\222,\207\62\0N;\42\377\360\301\316)\71!\314\206\207\34\311\11\71!'d\351p\320"
"\241\234\220\23rBNH\223\341\3O\21+\17\321\301\254Ca\16\205\71\222fa\62\34\42\65N\302"
"\61\12w K\312YR\216Z\223,\63fa\232#i\216\244)\0OS,\17\321\301\13s(\314"
"\241\60G\322\34I\206C\244%\305$K\312Qk\324\232d\305$\31\224I\254\245\71\222\346H\232#"
"i\14O\134-\17\321\301\214r\60\312\301(\15\263a\320\242$G\244$\7\222R-\322\6\65\314\241"
"\60\207\302,\15\207\261\16\205\71\24\346P\30\3O`%\16\321\301\253CY\16e\71\222\15\203\224\305"
"\211\24'\215qcR\254DY)\222j\245\270c\22\247)\0O\335,\377\360\301\313\11\321\60\244Q"
"\32fi\230\245\231\66\14Q\22\347@\62\34\244t\16\223j\230T\263\250\30eQ\230\204\231\24\247\0"
"O\341+\17\321\301\314r,\314\322\341\240\345\204\34\11\225\341\224\344`\224#i\62\34sB\64\14i"
"\224\226\322RZ\32\206\64J#\0P<+\17\321\301\254Ca\24\17\207\60\315\221\64\12\245a\220\222"
"(\215J\303\220Fii\30\322(-\15C\32\245\245\64\35\336r\20P\250\63\17\321\301Ks$\315"
"\21\61\12\243d\30\262(KBYJ\222!\31\6\251-\214\222a\310\42%\13\243Z\30%\303\30)"
"Y\30\325\302t\20\323,\2Q\62\66\377\360\301\213s \11s \312JY\64$Q\62(Q\244\3"
"I\224$\303A\312\221\64\31\242A\212\265(\31\224,J\242h\220\222\250\26%C\64HIT\13Q"
"e'\17\321\301\315)\71%'\344\204\34Nr\64\311\321$\7\263\34\253Ci\216\244\71\220\3i\216"
"\204\71\66\344h\2Qs)\17\321\301\313\201\34\210u \314\241,\312\206\207\34\311\11\71!M\206\357"
"@\16'\71\232\344`\226C\251\35\31t\60\1Q\306,\17\321\301\7\222\70\215b-*F\303\71\313"
"\201DKRe\30\304(\213\263J\264\15\203\326\234\225\263R\226\15\247,'\344\10\0R\6.\17\321"
"\301Gr\60\312\301,\207\302\34Js \7\322\34\312\242aH\206\64\213r \313\261:\24\346P\230"
"#i\16dI\16\244\61\0R\7+\17\321\301\313\11\71\24f\303\240\245Y\230d\305!\312\222!\315"
"\302\64\13\323,\214ja\222\25\265\260;\222\346@\226\304j\6R =\16\321\301\207\262dH\6)"
"\211\222(K\242$J\232\222(iJ\242\244)\211\222dxHJI\224\64%Q\322\224DIS\22"
"%MI\224%Q\22eI\224DI\42%\221\224\0R*(\376\362\301I+\303 &\235*\235*"
"\235*\235*\235\242\341\220DI\247J\247J\247J\327\244S\245\226-\241\230\0R\240(\377\360\301\313"
"\11\71!\207\302(\32\36\224,\214jaT\13\243Z\30\325\232\262\246\254)k\312\242J\64(aV"
"\1SU\42\17\321\301\313\201\34Hs(\213\302\341-\354q\70\210}\34\16b\235\220&\303w '"
"\344\204\34S\213'\377\360\301G\303\341-\315\221\64G\322\34Is$\315\302d\70di\216\244I\234"
"Fb\232\225s \16\223hxS\363)\17\321\301\316\11\71!N\206\257\71!\207sB\16\244\303A"
"Kr \213r \312r \316\201\70\7\342\341\234\3\21\0T\15'\16\321\301\316\341\34\35\206\270\250"
"\204\71T\7uL\307t \71\34\302\34Hs \315\201\64\7\322\341\232\3\11\0T\16*\17\321\301"
"\7st\10\207!GrB\216e\303C\224\23r(\214\206[\24\207Q\34FqV\316\312Q\70\14"
":\20G\0T&*\17\321\301\207\223\341;\222\303\71\254\243I\242#Q&j\351\220fQ\66\34\322"
"\34\210s \316\201\70\7\342\341\234\3\31\0T/+\17\321\301\7rJ\30\16o\71\24\346P\230C"
"\341p\20sB\16\205\303\233\216dI\216dI\216Du\244\66\34\322\34I\0TJ'\17\321\301\7"
"r\254\216\65\17\207\64\313\241\60'\244\311\360\35\214\207C\232\3q\16\304\71\20\347@<\234s \3"
"T}+\17\321\301\7rB\16'\71\230\345P\252\16\337\261pP\206\255\222\205Y\222\205Y\222\205Y"
"\42\205\203\322\230%Q\16\346\204\30U$(\16\323\301Gr$L\7i\220\332JI\26%Q\64\234"
"\272D]\242.Q\227h\370\32Fa\222cu$\25\345\4U_-\376\362\301Js$\314\242$J"
"\206e\30\264(\214\32\243$\33\66-\214\42%\34\223:\20E\303!\314\201\64\7\322\341\232\3\21\0"
"U\256%\377\360\301\32\224A\314\222,\314\222,\34\224A'\17\347\254<\234\263\362p\316\352X\232\14"
"\337\201\234\220\3Vh\63\17\321\301\32\224A\314\222,\314\222,\314\222,\34\224A\207\352`\226$\303"
"\347$\307\314: \15C\62\14Q\226da\226da\226d\341\240\14\22\0V\336%\356\362\301G\223"
"\341;\230\344@\226d\303\224d-YK\326\222\265d\203\226d-\71\230\14\17I\16&\0W\213-"
"\377\360\301\7\322h\30\304R\26\205Q\26\205Q\26%\303%\12\243,\12\243,\12\243\70\313\264$J"
"\303lx\310\221\234\220&\303\7X\323\61\377\360\301\312\261lx\210\222(K\223!\23\223(K\262d"
"\70HI\26\245\311 \245I\26\211\311\240DR\222\211Q\32\205\321p\213\303$\32\36Y\15,\17\321"
"\301\313\221t\70h\71!\31\6\61\212\263l\30t \316\201\203\216\344\360\60\350\200\230\3Q\35\10u"
" \214r,Tw`Y\32$\15\323\301\315\321\34\34\206\264*\246Q\242cI\216H\351\66\14iQ"
"\15\243,\14w,\207v`\307\0Y'$\377\360\301\7rBN\310\11\71!M\206\357@\16'\71"
"\232\344h\224cu,\314\221\270\216,:\226\0Y\64(\17\321\301GrB\216\325A%G\262$\207"
"\264\34\253\23\302d\370\216\344pNHt,\314\221\70\325\1I\307\22\0[W#\16\321\301\316\11\71"
"\360!\311A\35\14\207AGs\64Gs\340C\16\344p\16\347p\16&\71\232\3[X(\17\321\301"
"\316\11q\62|\315\341\234\220\14C\232\3qY\315\242dx\210\322\34Is$\315\221\64G\262$G"
"\302\30[\232(\17\321\301\316)\71\62<(\71\252\243\71\232\16\7\35\312\11\71V\312\201l\220\263\34"
"\253CI\224#\331\16\304\303 \134O(\17\321\301G\303\341-\207\302\34\12\207\203\230\225\303$\12\223"
"\341\220\65g\245lx\210\262rV\15\263\260\35IC\0]\345\35\337\20\302G\263\341!GrBN"
"\310\11\71!'\344\204\234\220\23rB\232\14\37]\346\42\377\360\301\316\11\71!\215\206\7\71'\344\204"
"\34\256\3\257a\16\205\71\222\346@\134\7\302hx\20]\362#\375\362\301\307\242\341\35\314\321,G\262"
"\34\311\206C\226#Y\216\346h\216\346X\222cI\216E\303A^U)\17\321\301\315\242lx\210\263"
"$\36\16i\16\304\303\71\7\342\341\216\344@\62|k\35\276d\225\60K\312Y\224\203\71\0^\246*"
"\17\321\301\7rJ\230\15\17QV\316*\341\360\326\234\15rNH\206A\315\312a\222\3i\16\204\212"
"\230\251C\244C\11\0^\372-\17\321\301\207rB:(\303\20\207Q\232\14\207,\215\302e\30\342\60"
"\315\222a\210\252q\222\306I\62\334\342\34\210+b\32\16\207\0_\214-\17\321\301\254Ca\216\204Y"
"X\13\243d\320\221\60G\302,T\206S\222\345@\224\15k\224Vjq\230\344@\232#\231\42'\352"
"\0_\251,\377\360\301\223\322\60\33\6)\313\241,\31\206$\222\322\60\33\206,L#q\30\222j\216"
"\204\303\220eb\251\65\226CI\214d\1`b\61\17\321\301\13s(\314\241\260e\70$\211\226\3I"
"S\232dQ\30eQ\61J*b\24\315Q\226\3I\230\3I\226\304b\22\207\331\26\251\11\0`o"
"+\17\321\301\316\341\64\36\16i\16\304\71\20\17\347\34\210\207s\16\304\71\20\17w(\207\222L\214\222"
"\60\212\244\34\210\302a\320\0bK&\17\321\301\7sp\320\206!'\344\204,\35\16:\224\23rB"
"\232\14\337\201\234\220\23rB\216&\71\234#\0b\351/\17\321\301\313\11\321\60\244Y\71L\302a\313"
"\221\60\311\201\244\26+Q\64)\311\240$J\232#i\224&\303\61\315\221\64N\322\34\210S\0c\1"
".\17\321\301Ks$\315\221\64\211\243a\210\206-G\322(M\206\243\234\352@\222(\311p\310\242\60"
"\316\312Y\71\7\302$M\322\34\10\1cb-\17\321\301\13s(\314\241l\220\243,\34\266(\215\206"
"A\214Z\207\250(\65)Q\353\360\226\346H\230\344@VL\242tJt \1c\247-\17\321\301K"
"s$\316\201h\270E\71p\310\222b-M\252\241\216\352H\244D\303 \306\71\20\347@\234\3qT"
"I\206C\224\243\0c\320\60\17\321\301\313\221\64\33\206\60\13\323,\214\206eX\263\60M\212\251\64\214"
":\250$\303!\213s \213\222\64\213\206\60\213\322$J\312Q\66\14c\333-\377\360\301\13\243\70\34"
"\324\254\66\14Y\16D\303\220FIk\242\264*\225i\210\224(K\242\326d\70di)L\304-\234"
"\42\71\1d\307,\377\360\301\213\206[T\211\262\250\22\15\37\262\70\7\262a\10\223\60\7\224\341!\13"
"\263$\214\342h\270\305a\24\15\227\271\16\204\0ep/\17\321\301,G\225\34HJ\71\224\205\311\360"
"M\12+RVJji\230E\303\20%i\26%\241V\7\222,\311\201\254\250\24\7\61N\0ex"
"-\377\360\301,\17C\22G\225t\70dQ\313\260\14\247\70\214\262aH\242,\252D\331\60$Q\32"
"'\321pJ\263\212\270e\303\264\6e\207(\17\321\301\316)\71!M\206o\71\220\3q\16\244\71\24"
"\346P\226\203I\16\347p\222\203\231\216\304\251\216\14:\230\0e\260.\17\321\301\313)\71\360\240\254Y"
"\224#Q\35\251\15\17J\24\207Q\34F\321\60(Q\230hQ\230\264\225\222Z\224Ea\245ZG\42"
"\0e\366(\16\323\301\7\343\322\260FY\34e\303A\213\243,\216\6)\213\262R\255T\213\243,\216"
"\6\71\312J\71\230\344h\6f/-\17\321\301\34\206\34Is$\315\221a\310\221\64G\322\34\31\206"
"\234\226\14\337\201\34\214\352H\64\350@\224cI\35\312t$\36\206\0fB+\376\362\301\207r \15"
"\7e\30\222(\15\243\64\214\222\341!\307\242\34\210*\303!\312\201\250\222FC\24F-Q\16\356h"
"\6f\364#\17\321\301\207\223\341;\20\206\303[\330\343p\20\373\70\34\304$\12s \311\341\34Nt"
"H\334vhg\0*\17\321\301\33\316\71\20\17\347\34\210\207;)\31>e\71\66\274U\302lP\262"
"\60\213\222t\320\302-Jt\244\66\253\11\0g,(\17\321\301\7rBN\310\11a\66<\304I\35"
"K\352XR\207\332\221\250\16d\325d\30\222A\255#\71!'\344\0h!+\17\321\301Ks$\316"
"\201\34\12\243\341;\32f\241\226JK-\351\224U\322$\213\322$\256\3i\22\207Y\32\211\333\16$"
"\0ke*\17\321\301\7r\60\312\301(\313\201h\230\243\34\214\322d\370\16\344`\224\345\200\222\251Y"
"\24\207Q\216\352\240\16\352\330\16\2mK,\376\320\301\311\201,\212\206\251-I\304\244\213\224t\252t"
"T\272%=UZ\206(\351\24\246Q\226\204Q\255\224\204I)\207\22\0n)/\17\321\301G\263p"
"\30\64)-\245Q:\14\231\226\206Y\32'\303\220\346p\64\134\246J\224E\225(\213*Q\26U\242"
",\31\16R\216\2n,\62\377\360\301\311\212Q\64lQ-L\263$\322\206%J\332\222(iK\242"
"\322\240DmI\264U\242$\33\224(\311*\321\230\244[eH\242\60K\0n\226(\376\362\301\11\223"
"\34\310\242J\224\14\227\266\70\31nJ\26j\303 e\325l\270d\71%L\206\7\35\310\341\34\216\1"
"n\253\63\377\360\301\11\323\60\33\6\255\32'i\224%\303\220%Q\232%\321\60\204Y\32F\71\220h"
"\303!\311\242$\252EI\224hQ\22%Z\224D\245\341 p\272)\376\362\301\312t\250\216%Y\70"
"\34t$\313\241,G\206A\256\346@\230\14\207$\7\62))\325\222(\211:\346\330\2p\331\60\17"
"\321\301\13s(\314\241p\30\223j\224HZ%\252\204I\34Fi\22g\332\226\310a\66\14a\226f"
"I\224fQ\222F\351\60$q\232\0p\355*\17\321\301\254Ca\16\205Q\66<\244a\24'Qu"
"\222\62%\214\342,)g\225(\211\302$\213\342\234\26e\275\215Y\30q\261)\376\362\301Ks M"
"\7-I\263a\31\206(\11\223\60\211\224\304\222V\262AJ\224\254\70\234sJ\224\225\262\232\230\25r"
"H\61\17\321\301\314\201,\212\247\322\220Fu$\252#\203\62\14QZJ\223(\33\242$\312\242J\61"
"*\211Q\222\245Q\22%a$eC\26\245u\14u(%\16\321\301G\263\341)\254\205\265\260\66\34"
"\264\260\26\326\302\332p\320\302ZX\13Ki\30\245QR\307\42\0u\65!\375\362\301\315\321\34\15\243"
"\341%,\205\245\341 \205\245\260\64\34\244\260\16\344h\234\306\361\60\4v\204\60\16\323\301Js \215"
"\263(K\206!\31\206\60\11\223PM\302\70\11\223\60\31&)\11\263(\11\343$\214\223\60N\206\71"
"\11\263$G\63\0w \64\16\323\301\7\243!\31\6%J\322\250\222F\225\64\32\222a\210*Q\32"
"%Q\226D\311\360\220Di\224da\224da\224\204\331\220\224\42)\21\223\64\26xn\62\17\321\301"
"\207r\254:\14\321\220\206Q\234E\265l\70U\242\322\240D\225R\62\14Y\224D\265(\211jQ\62"
"\14Y\224D\265!\211jMq\254\0x\272\60\377\360\301\307r(\211\262\341CV\311\302\64I\323a"
"\210\206$\13\245\255\22%\303 U\262\64J\262\64J\206A\32\222,\215\222,\307\206Ay\201,\17"
"\321\301Ls$M\262a\31FqM\244\244\26%R%K\263\234\66\34t\332\360\35\310\301\250\16d"
"\231\30%a\216\344\10\0y\322\60\17\321\301\15sdK\207\64G\322\34\311\222\322\60$%\61K\262"
"l\211r@\311\242,I\243,I\223,\212\263j\216\204\71\224\345X\242\3y\360,\17\321\301\315r"
"h\212\207,\307\352X\64|N+\351\230\3J\307$K\242,\211JJ\324\246%Y\216\244\71\222%"
"\71\22\246\0z\15\62\17\321\301Ls`\211*C\230Da\245\32G\311\260\14\203V\315\246\64S\222"
"a\210\222,\215\222,M\242l\30\302,\15\263\64\314*a\26F\0z\61\60\377\360\301M\17C\70"
"dI\246\205I\24&QR\32\206,\7\262a\10\245\66%\31\206(\311\242J\224E\305d\70d\325"
"\60\313\306,\214\0{I(\17\321\301Ks\244\26\205\203\62L\335\241$\313\261\34\32\16:\224\3\277"
"C\71!I\207\203\34\346X\35Mr\70\6{\200\65\17\321\301\213j\341\240\14S\222%i\226d\245"
"\34\11\223d\30\264\34\12\243A\12\243,\12\243,\12\243A\12\243,\12\243,\12\243A\12s \11"
"s$\3|{(\17\321\301\7r\254\35\210\352`mx\310\221\34M\352PI\316\352X\232\14\237\223"
"\34\314r(\315\201\34\230t(\2~A-\17\321\301\312\312\303\324\16\34\222A\321*\265$\32Ni"
"RK\246A\321r \313\201C\216\352\240\230\16\7\71\252\3R&fi\4\177n'\377\360\301\32\16"
"b\224E\341p\320\241\34\31\36r$\307\206s\16\304\303\71\7\342\341\234\3\361p\316\201$\31>\200"
"\375\60\17\321\301\13s(\314\302\250\244\225\222p\30\22\35L\302h\220\302(\313\6i\320\261R\326\24"
"i\203\224\244Y$gQ\232\64\245I\24\16\3\203\334'\17\321\301\315r\254e\370\232\345\224q\30t"
"$\12s \252\203i\62|\336\301\244\16\225\344,\134\304\64Gr\0\207\2\61\17\321\301\13s(\314"
"\241p\30\223D\313\206)\11\223b\232\224\224!\251L-\245A\33\304\64\311\206!L\302\34X\206!"
"\231\302\64GrB\10\212-*\377\360\301J\243\70\34\324\60\312\206!\211r\60\312\261p\31v\312\60"
"D\203\224\345Xm\220\262.a\26\246\203\244h\331*\212\215/\377\360\301\312\261\60\32nq\224\14C"
"R\312\241$\312\221\250\64h\311\16e\331\240D\71%\34\264\244\224%\305$KJI\62L\265\342\4"
"\212\244-\377\360\301\212\7\61\315\302,\311\222a\251\345H\62\350H-\32\242\234p\210\206\64\312\301("
"\32\222\341\22\245\245\60\11\207\254)Q\5\212\313/\377\360\301\311\221\70\33N\71\20\16\313\60\344`\216"
"\15\337I\303\220\14K\232#\303\220\14K\232\204\311\60$a\222&\303\222-a\22F\0\213f&\17"
"\321\301K\262x\30\222A\14\245p\230\222,i\213\227D\231\325d\370N\34\356\14\357\14\317\71\20\17"
"\67\0\213\244+\17\321\301\207\342\34\310\1\65G\322\234\220\23\322!Lr Lr Lr +g"
"\345\244\26+i)\315\201\34\20s$\1\213\276,\17\321\301\7\6\65\314\342\254\234\325\261:\224\16C"
"\222\243\321\60\244Y\230f\345\60\212\303$\7\222,G\264D\216\304Q\7\22\0\213\357*\17\321\301G"
"\263p\30\64)-\245\71\62\14\71m\32nq\16\304Ye\70Hq\16\244I\234dI\254U\263t"
"\315\201\4\213\367/\17\321\301\207\342\34\310\201h\270\305\71\70\14\321\234\3\311p\220rB\66\14a\226"
"\206\331\60\204Y\32&\311\60\204R\32f\225\34\11\63\0\217\70/\377\360\301\213s M\262aH\262"
"\64K\225a\31\224\356\330\240\14Y\322)\251\14\312\220\364)\251\225\222dx\251\225\262\246d\253H\11"
"\0\217\223\66\17\321\301\212s M\342$K\302a\311\322,]\262dP\242$\7\243h\310\222A\211"
"\222b\64$\265%J*J\64$\305\250R\214jaT\13\243DR\0\217\276*\377\360\301Gr "
"\316\221\64G\322\234\220\305\303!Ys$\314\241\60\311\201\254\234\205i\224\212I\16dI\16m\303!"
"\1\217\324,\17\321\301G\263\34\332\244A\7\242\234\220\23\222A\32\242\264\224DqT\211\243,\7\242"
"J\234D\231\230T\263$\7\263\234\62\34\217\333%\377\360\301\316\322\60\213\263r\62\34r \313\261\342"
"V\316\312\311p\310\232\263rV\216\302\64\211\303l\70\10\220\11/\17\321\301\207\342\60\312\1\251\65\32"
"\6\35\210r\254eH\206C\26&\71\20&\71\20&\71\220EYSV\12\207(\321\261: \17\203"
"\2\220\62.\377\360\301\7\222\70\215b)\213\302h\270j\71R\313\201h\30\224A\311r \32\6\61"
"\312r \312r \32NR\16\325\261p\70\4\220T+\377\360\301\207\342\34\310\1i\30\304\64\307\206"
"C\16dq\230D\311\360-\315\221h\30\304\64G\222\341\20\251\251\24\246\341p\10\220x/\377\360\301"
"\35\222!\312\242$\312\224!\31\302$\314\322L\213\207d\310\302(\33\224a\20Kq\62\34\262\234\220"
"I\242\42\17Q\216\205\303!\221\222\64\17\321\301\315\201d\30\222a\210\222,\314\222lX\206!\11\223"
".\303\322-L\222\245(&\303\222Ja\232\205\303\220\14K\232\205i\26%\303\207\64G\0\221\315#"
"\377\360\301\307\306a\320\321\312\360\35\310\342\341\220f\345\341\234\225\207;\226C\303A\207rB\232\14\37"
"\221\317%\17\321\301\7\343\341\220\346@<\234s I\206\357\304\341\234\225\207sV\36\356X\216\15w"
",G\206\207\4\223/\61\377\360\301K\243T\214\322$\213\302l\270\344@\24\15[\224f\303\240\345\340"
"\60$\303\22%Q\30%Z\30%\341\60\16I\230\14\341\60\305a\2\224\30-\377\360\301\312\201X\32"
"NI\326K\226\16\227AG\263a\10\263\250\62,\303\220DY\324R\31\206(Qs \33\206d\30"
"\323p\70\224\65\61\377\360\301\13\243\70\214TeHjQc\70|\215\243!\211\243J\64\34\224HJ"
"\322$J\224!)%a\244d\303\20%\203\30%J\70h\1\224\237/\17\321\301\213s \316\201\70"
"\7\306(\13\207A\12\243\322\240D\225(\213\212YT\31\226a\10\263\250\30\347@\22\346\200\232\3q"
"N\10\1\224\301/\17\321\301Ks$Kr$K\312\313\60Vr \213\342A\213\232\206AL\343A"
"\313\221\60\311\201\60\311\201\244\26KY\34\245k\16$\0\225\31\60\17\321\301\13\263\64\314\302!\312\302"
"p\30\242\70\313\6)\213J\303-'d\303\220\14K\32fi\230\15C\230\245aR\15\245a\10\263"
"\64\1\225\211+\16\323\301\70\15C\30\205\303\20\15C\30\205\303\20\15C\30\205r*\247\312pH\344"
"\324MI\25-\25\223T\15\23\35L\0\225\223+\376\362\301\70\15C\30\205\303\20\15C\30\205\303\20"
"\15C\30\205:\252\15\233\26f\332\260ia\246\15\233\26J:\66\344`\2\225\276/\376\362\301\70\15"
"C\30\205\303\20\15C\30\205\303\20\15C\234dr\24)\303!\221Si\220\42\251\242ICR\222\23"
"I\31\304!\7\23\0\225\334\62\376\362\301\70\15C\30\205\303\20\15C\30\205\303\20\15C\24\206J\224"
"D\221\62mR\22%\221\62$\203\42F\241\224DI$\235\304(\32\222\255\2\225\355.\16\323\301\311"
"\261L\31n\71R\16\223\70\211\222d\270\224\303$\25\223\60\11\223,\12\223(\13\223b%\16\223\60"
"\11\223\64K\352X\4\225\364\63\15\323\301\311\241L\31\6-\7\222\34K\242aJ\242\60J\242\60J"
"\242\60J\242aJ\242\60J\242\60J\242\60J\242aJ\242\60Jr\244\35\212\0\226\10\63\16\323\301"
"\311\261\312p\220\223(\211\243$\31\36\222\70L\222!\11\223R\22%M\225N\221\224$C\224%\71"
"\220T\206%Q\252YR\214\223\34S\0\226d/\16\323\301G\322!L\243,\11\223\60\11\223\254\246"
"\245CR\31\224R\230Fa\222E\303!Q\302\64\311\222Z\30EJ\326\222&i\34\3\226\373(\377"
"\360\301\33\16Y\32'\303\347\64\33\222d\310\241\34\32\222d\310\251\303Al\34\16b\343pPr "
"\316\221a\10\227^&\17\321\301\315r\254\216\265\14\333\260f\71V\307J\331\240\15r\226cu\254\216"
"\265\14\333\260f\71V\307\252\0\230-.\377\360\301\315\201d\370\216\245Y\64L\303\22FY\24FY"
"\64L\203\24FY\64\314Q\30\325\302,\311\206-Y\302dH\23-\25\5\230^\60\376\362\301\210\252"
"QR\31\206\244\61\16\7e\30\222,\333JIiP\242J\26&\321 FI\226\14C\222\205\341\240"
"%Y)\253Da\242\11\230y*\17\321\301\207\323d\370\230\3i\26f\303\240U\303,*fQ\61"
"\213\212YT\134\242\312\220E\255Q\35Kt,\314\1\71\232\330(\17\321\301\316)\71\360;u\30r"
"$\315\221a\310\311\303C\224\203Q\64\14Qk\324\32\225\206!\252\203Q\16-\0\234\364/\376\362\301"
"G\304(\211J\303C\22%iT\31\206\250\222F\225a\210*\71\22%\303C\222#Q\62\34r\64"
"L\232\302(i\253$\12\0\236#*\16\323\301Gr$+\15\312\60$Q\61j\211:F]\242\266"
"R\65\211\242\341\35)\245Q:\14I\16\347`\222\243\21\0\236\330.\17\321\301\7\242t\30\24\61j"
"\311\224DJ\223%*\15\17b\232\16C\224#i\216\14Q:\244\71\224\64&=&\245,\252\205s"
"\5\377\32\12\202^\302\30rd\10\0";
================================================
FILE: SolderingPen_ESP32S2/SolderingPen_ESP32S2.ino
================================================
//
#include "config.h"
//
#include <Button2.h>
#include <QC3Control.h>
//
#include "FirmwareMSC.h"
#include "Languages.h"
#include "USB.h"
#include "UtilsEEPROM.h"
QC3Control QC(14, 13);
// QC.set12V();
#include <U8g2lib.h> // https://github.com/olikraus/u8g2
// font
#include "PTS200_16.h"
// #include<analogWrite.h>
#include <ESP32AnalogRead.h> //Click here to get the library: http://librarymanager/All#ESP32AnalogRead
#include "esp_adc_cal.h"
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
#include <PID_v1.h> // https://github.com/wagiminator/ATmega-Soldering-Station/blob/master/software/libraries/Arduino-PID-Library.zip
// (old cpp version of
// https://github.com/mblythe86/C-PID-Library/tree/master/PID_v1)
#include <EEPROM.h> // 用于将用户设置存储到EEPROM
// 选择加速度计芯片
// #define MPU
#define LIS
/*#if defined(MPU)
#include <MPU6050_tockn.h> //https://github.com/tockn/MPU6050_tockn
MPU6050 mpu6050(Wire);*/
// #if defined(LIS)
#include "SparkFun_LIS2DH12.h" //Click here to get the library: http://librarymanager/All#SparkFun_LIS2DH12
SPARKFUN_LIS2DH12 accel; // Create instance
/*#else
#error Wrong SENSOR type!
#endif*/
int16_t gx = 0, gy = 0, gz = 0;
uint16_t accels[32][3];
uint8_t accelIndex = 0;
#define ACCEL_SAMPLES 32
// 定义积极和保守的PID调整参数
double aggKp = 11, aggKi = 0.5, aggKd = 1;
double consKp = 11, consKi = 3, consKd = 5;
// 用户可以更改并存储在EEPROM中的默认值
uint16_t DefaultTemp = TEMP_DEFAULT;
uint16_t SleepTemp = TEMP_SLEEP;
uint8_t BoostTemp = TEMP_BOOST;
uint16_t time2sleep = TIME2SLEEP;
uint8_t time2off = TIME2OFF;
uint8_t timeOfBoost = TIMEOFBOOST;
uint8_t MainScrType = MAINSCREEN;
bool PIDenable = PID_ENABLE;
bool beepEnable = BEEP_ENABLE;
volatile uint8_t VoltageValue = VOLTAGE_VALUE;
bool QCEnable = QC_ENABLE;
uint8_t WAKEUPthreshold = WAKEUP_THRESHOLD;
bool restore_default_config = false;
// T12的默认值
uint16_t CalTemp[TIPMAX][4] = {TEMP200, TEMP280, TEMP360, TEMPCHP};
char TipName[TIPMAX][TIPNAMELENGTH] = {TIPNAME};
uint8_t CurrentTip = 0;
uint8_t NumberOfTips = 1;
// Variables for pin change interrupt 引脚更改中断的变量
volatile uint8_t a0, b0, c0, d0;
volatile bool ab0;
volatile int count, countMin, countMax, countStep;
volatile bool handleMoved;
// Variables for temperature control 温度控制变量
uint16_t SetTemp, ShowTemp, gap, Step;
double Input, Output, Setpoint, RawTemp, CurrentTemp, ChipTemp;
// Variables for voltage readings 电压读数变量
uint16_t Vcc, Vin;
// State variables 状态变量
bool inLockMode = true;
bool inSleepMode = false;
bool inOffMode = false;
bool inBoostMode = false;
bool inCalibMode = false;
bool isWorky = true;
bool beepIfWorky = true;
bool TipIsPresent = true;
bool OledClear;
// Timing variables 时间变量
uint32_t sleepmillis;
uint32_t boostmillis;
uint32_t buttonmillis;
uint32_t goneMinutes;
uint32_t goneSeconds;
uint8_t SensorCounter = 0;
// Specify variable pointers and initial PID tuning parameters
// 指定变量指针和初始PID调优参数
PID ctrl(&Input, &Output, &Setpoint, aggKp, aggKi, aggKd, REVERSE);
// Setup u8g object depending on OLED controller
// 根据OLED控制器设置u8g对象
#if defined(SSD1306)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE,
/* clock=*/22, /* data=*/21);
#elif defined(SH1107)
U8G2_SH1107_64X128_F_HW_I2C u8g2(U8G2_R1, 7);
#else
#error Wrong OLED controller type!
#endif
// Buffer for drawUTF8
char F_Buffer[20];
float lastSENSORTmp = 0;
float newSENSORTmp = 0;
uint8_t SENSORTmpTime = 0;
// ADC Calibrate
uint16_t vref_adc0, vref_adc1;
ESP32AnalogRead adc_sensor;
ESP32AnalogRead adc_vin;
// Language
uint8_t language = 0;
// Hand Side
uint8_t hand_side = 0;
// MSC Firmware
FirmwareMSC MSC_Update;
bool MSC_Updating_Flag = false;
// Button2 Obj
Button2 btn;
float limit = 0.0;
void setup() {
digitalWrite(PD_CFG_0, LOW);
digitalWrite(PD_CFG_1, HIGH);
digitalWrite(PD_CFG_2, LOW);
// pinMode(14, INPUT);
// pinMode(13, INPUT);
// QC.set12V();
Serial.begin(115200);
Serial.setTxTimeoutMs(0);
// delay(5000);
// analogSetAttenuation(ADC_11db);
// vref_adc0 = calibrate_adc(ADC_UNIT_1, (adc_atten_t)ADC1_CHANNEL_5);
// vref_adc1 = calibrate_adc(ADC_UNIT_2, (adc_atten_t)ADC2_CHANNEL_9);
adc_sensor.attach(SENSOR_PIN);
adc_vin.attach(VIN_PIN);
/*#if defined(MPU)
mpu6050.begin();
mpu6050.calcGyroOffsets(true);*/
// #endif
// set the pin modes 设置引脚模式
pinMode(SENSOR_PIN, INPUT_PULLUP);
// pinMode(VIN_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
// pinMode(CONTROL_PIN, OUTPUT);
pinMode(BUTTON_P_PIN, INPUT_PULLUP);
pinMode(BUTTON_N_PIN, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT_PULLUP);
// digitalWrite(BUZZER_PIN, LOW); // must be LOW when buzzer not in
// use当蜂鸣器不使用时,必须是低电平
// get default values from EEPROM 从EEPROM获取默认值
// if (!EEPROM.begin(EEPROM_SIZE))
// {
// Serial.println("failed to initialise EEPROM");
// delay(100);
// }
init_EEPROM();
if (digitalRead(BUTTON_P_PIN) == LOW && digitalRead(BUTTON_N_PIN) == LOW &&
digitalRead(BUTTON_PIN) == HIGH) {
write_default_EEPROM();
}
getEEPROM();
pinMode(PD_CFG_0, OUTPUT);
pinMode(PD_CFG_1, OUTPUT);
pinMode(PD_CFG_2, OUTPUT);
if (QCEnable) {
QC.begin();
delay(100);
switch (VoltageValue) {
case 0: {
QC.set9V();
} break;
case 1: {
QC.set12V();
} break;
case 2: {
QC.set12V();
} break;
case 3: {
QC.set20V();
} break;
case 4: {
QC.set20V();
} break;
default:
break;
}
}
PD_Update();
// read supply voltages in mV 以mV为单位读取电源电压
delay(100);
Vin = getVIN();
// read and set current iron temperature 读取和设置当前的烙铁头温度
SetTemp = DefaultTemp;
RawTemp = denoiseAnalog(SENSOR_PIN);
calculateTemp();
// turn on heater if iron temperature is well below setpoint
// 如果烙铁头温度远低于设定值,则打开加热器
limit = POWER_LIMIT_20;
if (VoltageValue < 3) {
limit = POWER_LIMIT_15;
}
if (((CurrentTemp + 20) < DefaultTemp) && !inLockMode)
ledcWrite(CONTROL_CHANNEL, constrain(HEATER_ON, 0, limit));
// set PID output range and start the PID
// 设置PID输出范围,启动PID
ctrl.SetOutputLimits(0, 255);
ctrl.SetMode(AUTOMATIC);
// set initial rotary encoder values 设置旋转编码器的初始值
// a0 = PINB & 1; b0 = PIND >> 7 & 1; ab0 = (a0 == b0);
a0 = 0;
b0 = 0;
setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP, DefaultTemp);
// reset sleep timer 睡眠定时器重置
sleepmillis = millis();
// long beep for setup completion 安装完成时长哔哔声
beep();
beep();
// delay(2000);
Serial.println("Soldering Pen");
// #elif defined(LIS)
// u8g2.setBusClock(100000);
Wire.begin();
Wire.setClock(100000); // 400000
if (accel.begin() == false) {
delay(500);
Serial.println("Accelerometer not detected.");
}
// lis2dh12_block_data_update_set(&(accel.dev_ctx), PROPERTY_DISABLE);
// accel.setScale(LIS2DH12_2g);
// accel.setMode(LIS2DH12_HR_12bit);
// accel.setDataRate(LIS2DH12_ODR_400Hz);
// lis2dh12_fifo_mode_set(&(accel.dev_ctx), LIS2DH12_BYPASS_MODE);
ChipTemp = getChipTemp();
lastSENSORTmp = getMPUTemp();
u8g2.initDisplay();
u8g2.begin();
u8g2.sendF("ca", 0xa8, 0x3f);
u8g2.enableUTF8Print();
if(hand_side){
u8g2.setDisplayRotation(U8G2_R3);
}else{
u8g2.setDisplayRotation(U8G2_R1);
}
// btn.begin(BUTTON_PIN);
// btn.setDoubleClickHandler(turnOffHeater);
// btn.setDebounceTime(25);
}
int SENSORCheckTimes = 0;
long lastMillis = 0;
void loop() {
long timems = millis();
ROTARYCheck(); // check rotary encoder (temp/boost setting, enter setup menu)
// 检查旋转编码器(温度/升压设置,进入设置菜单)
SLEEPCheck(); // check and activate/deactivate sleep modes
// 检查和激活/关闭睡眠模式
if (SENSORCheckTimes > 1) {
// long timems = millis();
SENSORCheck(); // reads temperature and vibration switch of the iron
// 读取烙铁头的温度和振动开关
// lastMillis = millis() - timems;
// Serial.println(lastMillis);
SENSORCheckTimes = 0;
}
SENSORCheckTimes++;
Thermostat(); // heater control 加热器控制
MainScreen(); // updates the main page on the OLED 刷新OLED主界面
lastMillis = millis() - timems;
Serial.println(lastMillis);
}
// check rotary encoder; set temperature, toggle boost mode, enter setup menu
// accordingly 检查旋转编码器;设置温度,切换升压模式,进入设置菜单相应
void ROTARYCheck() {
// set working temperature according to rotary encoder value
// 根据旋转编码器值设定工作温度
SetTemp = getRotary();
uint8_t c = digitalRead(BUTTON_PIN);
if (!c && c0) {
delay(10);
if (digitalRead(BUTTON_PIN) == c) {
beep();
buttonmillis = millis();
delay(10);
while ((!digitalRead(BUTTON_PIN)) && ((millis() - buttonmillis) < 500))
;
delay(10);
if ((millis() - buttonmillis) >= 500) {
SetupScreen();
} else {
if (inLockMode) {
inLockMode = false;
} else {
buttonmillis = millis();
while ((digitalRead(BUTTON_PIN)) && ((millis() - buttonmillis) < 200))
delay(10);
if ((millis() - buttonmillis) >= 200) { // single click
if (inOffMode) {
inOffMode = false;
} else {
inBoostMode = !inBoostMode;
if (inBoostMode) {
boostmillis = millis();
}
handleMoved = true;
}
} else { // double click
inOffMode = true;
}
}
}
}
}
c0 = c;
// check timer when in boost mode 在升温模式时检查计时器
if (inBoostMode && timeOfBoost) {
goneSeconds = (millis() - boostmillis) / 1000;
if (goneSeconds >= timeOfBoost) {
inBoostMode = false; // stop boost mode 停止升温模式
beep(); // beep if boost mode is over 如果升温模式结束,会发出蜂鸣声
beepIfWorky = true; // beep again when working temperature is reached
// 当达到工作温度,会发出蜂鸣声
}
}
}
// check and activate/deactivate sleep modes 检查和激活/关闭睡眠模式
void SLEEPCheck() {
if (inLockMode) {
;
} else {
if (handleMoved) { // if handle was moved 如果手柄被移动
u8g2.setPowerSave(0);
if (inSleepMode) { // in sleep or off mode? 在睡眠模式还是关机模式?
limit = POWER_LIMIT_20;
if (VoltageValue < 3) {
limit = POWER_LIMIT_15;
}
if ((CurrentTemp + 20) <
SetTemp) // if temp is well below setpoint 如果温度远低于设定值
ledcWrite(
CONTROL_CHANNEL,
constrain(HEATER_ON, 0, limit)); // then start the heater right
// now 那现在就启动加热器
beep(); // beep on wake-up
beepIfWorky = true; // beep again when working temperature is reached
// 当达到工作温度,会发出蜂鸣声
}
handleMoved = false; // reset handleMoved flag
inSleepMode = false; // reset sleep flag
// inOffMode = false; // reset off flag
sleepmillis = millis(); // reset sleep timer
}
// check time passed since the handle was moved 检查把手被移动后经过的时间
goneSeconds = (millis() - sleepmillis) / 1000;
if ((!inSleepMode) && (time2sleep > 0) && (goneSeconds >= time2sleep)) {
inSleepMode = true;
beep();
} else if ((!inOffMode) && (time2off > 0) &&
((goneSeconds / 60) >= time2off)) {
inOffMode = true;
u8g2.setPowerSave(1);
beep();
}
}
}
// reads temperature, vibration switch and supply voltages
// 读取温度,振动开关和电源电压
void SENSORCheck() {
/*#if defined(MPU)
mpu6050.update();
if (abs(mpu6050.getGyroX() - gx) > WAKEUP_THRESHOLD ||
abs(mpu6050.getGyroY() - gy) > WAKEUP_THRESHOLD || abs(mpu6050.getGyroZ() -
gz) > WAKEUP_THRESHOLD)
{
gx = mpu6050.getGyroX();
gy = mpu6050.getGyroY();
gz = mpu6050.getGyroZ();
handleMoved = true;
Serial.println("进入工作状态!");
}*/
// #if defined(LIS)
// if (abs(accel.getX() - gx) > WAKEUPthreshold ||
// abs(accel.getY() - gy) > WAKEUPthreshold ||
// abs(accel.getZ() - gz) > WAKEUPthreshold) {
// gx = accel.getX();
// gy = accel.getY();
// gz = accel.getZ();
// handleMoved = true;
// // Serial.println("进入工作状态!");
// }
// accel.getRawX() return int16_t
if (accel.available()) {
accels[accelIndex][0] = accel.getRawX() + 32768;
accels[accelIndex][1] = accel.getRawY() + 32768;
accels[accelIndex][2] = accel.getRawZ() + 32768;
accelIndex++;
// debug output
// Serial.print("X: ");
// Serial.print(accels[accelIndex][0]);
// Serial.print(" Y: ");
// Serial.print(accels[accelIndex][1]);
// Serial.print(" Z: ");
// Serial.println(accels[accelIndex][2]);
if (accelIndex >= ACCEL_SAMPLES) {
accelIndex = 0;
// cal variance
uint64_t avg[3] = {0, 0, 0};
for (int i = 0; i < ACCEL_SAMPLES; i++) {
avg[0] += accels[i][0];
avg[1] += accels[i][1];
avg[2] += accels[i][2];
}
avg[0] /= ACCEL_SAMPLES;
avg[1] /= ACCEL_SAMPLES;
avg[2] /= ACCEL_SAMPLES;
uint64_t var[3] = {0, 0, 0};
for (int i = 0; i < ACCEL_SAMPLES; i++) {
var[0] += (accels[i][0] - avg[0]) * (accels[i][0] - avg[0]);
var[1] += (accels[i][1] - avg[1]) * (accels[i][1] - avg[1]);
var[2] += (accels[i][2] - avg[2]) * (accels[i][2] - avg[2]);
}
var[0] /= ACCEL_SAMPLES;
var[1] /= ACCEL_SAMPLES;
var[2] /= ACCEL_SAMPLES;
// debug output
// Serial.print("variance: ");
// Serial.print(var[0]);
// Serial.print(" ");
// Serial.print(var[1]);
// Serial.print(" ");
// Serial.println(var[2]);
int varThreshold = WAKEUPthreshold * 10000;
if (var[0] > varThreshold || var[1] > varThreshold ||
var[2] > varThreshold) {
handleMoved = true;
// Serial.println("进入工作状态!");
}
}
}
// #endif
ledcWrite(CONTROL_CHANNEL,
HEATER_OFF); // shut off heater in order to measure
// temperature 关闭加热器以测量温度
if (VoltageValue == 3) {
delayMicroseconds(TIME2SETTLE_20V);
} else {
delayMicroseconds(TIME2SETTLE); // wait for voltage to settle 等待电压稳定
}
long timems = millis();
double temp = denoiseAnalog(SENSOR_PIN); // 读取ADC值的温度
lastMillis = millis() - timems;
// Serial.println(lastMillis);
if (SensorCounter++ > 10) {
Vin = getVIN(); // get Vin every now and then 时不时去获取VIN电压
SensorCounter = 0;
}
if (!inLockMode) {
limit = POWER_LIMIT_20;
if (VoltageValue < 3) {
limit = POWER_LIMIT_15;
}
ledcWrite(CONTROL_CHANNEL,
constrain(HEATER_PWM, 0,
limit)); // turn on again heater 再次打开加热器
}
RawTemp += (temp - RawTemp) *
SMOOTHIE; // stabilize ADC temperature reading 稳定ADC温度读数
calculateTemp(); // calculate real temperature value 计算实际温度值
// stabilize displayed temperature when around setpoint
// 稳定显示温度时,周围的设定值
if ((ShowTemp != Setpoint) || (abs(ShowTemp - CurrentTemp) > 5))
ShowTemp = CurrentTemp;
if (abs(ShowTemp - Setpoint) <= 1) ShowTemp = Setpoint;
if (inLockMode) {
ShowTemp = 0;
}
// set state variable if temperature is in working range; beep if working
// temperature was just reached
// 温度在工作范围内可设置状态变量;当工作温度刚刚达到时,会发出蜂鸣声
gap = abs(SetTemp - CurrentTemp);
if (gap < 5) {
if (!isWorky && beepIfWorky) beep();
isWorky = true;
beepIfWorky = false;
} else
isWorky = false;
// checks if tip is present or currently inserted
// 检查烙铁头是否存在或当前已插入
if (ShowTemp > 500) TipIsPresent = false; // tip removed ? 烙铁头移除?
if (!TipIsPresent &&
(ShowTemp < 500)) { // new tip inserted ? 新的烙铁头插入?
ledcWrite(CONTROL_CHANNEL, HEATER_OFF); // shut off heater 关闭加热器
beep(); // beep for info
TipIsPresent = true; // tip is present now 烙铁头已经存在
ChangeTipScreen(); // show tip selection screen 显示烙铁头选择屏幕
updateEEPROM(); // update setting in EEPROM EEPROM的更新设置
handleMoved = true; // reset all timers 重置所有计时器
RawTemp = denoiseAnalog(
SENSOR_PIN); // restart temp smooth algorithm 重启临时平滑算法
c0 = LOW; // switch must be released 必须松开开关
setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP,
SetTemp); // reset rotary encoder 重置旋转编码器
}
}
// calculates real temperature value according to ADC reading and calibration
// values 根据ADC读数和校准值,计算出真实的温度值
void calculateTemp() {
if (RawTemp < 200)
CurrentTemp = map(RawTemp, 0, 200, 15, CalTemp[CurrentTip][0]);
else if (RawTemp < 280)
CurrentTemp =
map(RawTemp, 200, 280, CalTemp[CurrentTip][0], CalTemp[CurrentTip][1]);
else
CurrentTemp =
map(RawTemp, 280, 360, CalTemp[CurrentTip][1], CalTemp[CurrentTip][2]);
}
// controls the heater 控制加热器
void Thermostat() {
// define Setpoint acoording to current working mode
// 根据当前工作模式定义设定值
if (inOffMode || inLockMode)
Setpoint = 0;
else if (inSleepMode)
Setpoint = SleepTemp;
else if (inBoostMode) {
Setpoint = constrain(SetTemp + BoostTemp, 0, 450);
} else
Setpoint = SetTemp;
if (SetTemp != DefaultTemp) {
DefaultTemp = SetTemp; // 把设置里面的默认温度也修改了
update_default_temp_EEPROM();
}
// control the heater (PID or direct) 控制加热器(PID或直接)
gap = abs(Setpoint - CurrentTemp);
if (PIDenable) {
Input = CurrentTemp;
if (gap < 30)
ctrl.SetTunings(consKp, consKi, consKd);
else
ctrl.SetTunings(aggKp, aggKi, aggKd);
ctrl.Compute();
} else {
// turn on heater if current temperature is below setpoint
// 如果当前温度低于设定值,则打开加热器
if ((CurrentTemp + 0.5) < Setpoint)
Output = 0;
else
Output = 255;
}
limit = POWER_LIMIT_20;
if (VoltageValue < 3) {
limit = POWER_LIMIT_15;
} else if(VoltageValue == 3){
limit = POWER_LIMIT_20_2;
}
ledcWrite(CONTROL_CHANNEL,
constrain((HEATER_PWM), 0, limit)); // set heater PWM 设置加热器PWM
}
// creates a short beep on the buzzer 在蜂鸣器上创建一个短的哔哔声
void beep() {
if (beepEnable) {
for (uint8_t i = 0; i < 255; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delayMicroseconds(125);
digitalWrite(BUZZER_PIN, LOW);
delayMicroseconds(125);
}
}
}
// sets start values for rotary encoder 设置旋转编码器的起始值
void setRotary(int rmin, int rmax, int rstep, int rvalue) {
countMin = rmin << ROTARY_TYPE;
countMax = rmax << ROTARY_TYPE;
countStep = rstep;
count = rvalue << ROTARY_TYPE;
}
// reads current rotary encoder value 读取当前旋转编码器值
int getRotary() {
Button_loop();
return (count >> ROTARY_TYPE);
}
// reads user settings from EEPROM; if EEPROM values are invalid, write defaults
// 从EEPROM读取用户设置;如果EEPROM值无效,则写入默认值
void getEEPROM() { read_EEPROM(); }
// writes user settings to EEPROM using updade function to minimize write cycles
// 使用升级功能将用户设置写入EEPROM,以最小化写入周期
void updateEEPROM() { update_EEPROM(); }
// draws the main screen 绘制主屏幕
void MainScreen() {
u8g2.firstPage();
do {
// u8g2.setCursor(0, 0);
// u8g2.print(F("nihao"));
// draw setpoint temperature
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
// u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, "设温:");
u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_set_temp[language]);
u8g2.setCursor(40, 0 + SCREEN_OFFSET);
u8g2.setFont(u8g2_font_unifont_t_chinese3);
u8g2.print(Setpoint, 0);
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
// draw status of heater 绘制加热器状态
u8g2.setCursor(96, 0 + SCREEN_OFFSET);
if (ShowTemp > 500)
u8g2.print(txt_error[language]);
else if (inOffMode || inLockMode)
u8g2.print(txt_off[language]);
else if (inSleepMode)
u8g2.print(txt_sleep[language]);
else if (inBoostMode)
u8g2.print(txt_boost[language]);
else if (isWorky)
u8g2.print(txt_worky[language]);
else if (Output < 180)
u8g2.print(txt_on[language]);
else
u8g2.print(txt_hold[language]);
u8g2.setFont(u8g2_font_unifont_t_chinese3);
// rest depending on main screen type 休息取决于主屏幕类型
if (MainScrType) {
// draw current tip and input voltage 绘制当前烙铁头及输入电压
float fVin = (float)Vin / 1000; // convert mv in V
newSENSORTmp = newSENSORTmp + 0.01 * getMPUTemp();
SENSORTmpTime++;
if (SENSORTmpTime >= 100) {
lastSENSORTmp = newSENSORTmp;
newSENSORTmp = 0;
SENSORTmpTime = 0;
}
u8g2.setCursor(0, 50);
u8g2.print(lastSENSORTmp, 1);
u8g2.print(F("C"));
u8g2.setCursor(83, 50);
u8g2.print(fVin, 1);
u8g2.print(F("V"));
// draw current temperature 绘制当前温度
u8g2.setFont(u8g2_font_freedoomr25_tn);
u8g2.setFontPosTop();
u8g2.setCursor(37, 18);
if (ShowTemp > 500)
u8g2.print(F("000"));
else
u8g2.printf("%03d", ShowTemp);
} else {
// draw current temperature in big figures 用大数字绘制当前温度
u8g2.setFont(u8g2_font_fub42_tn);
u8g2.setFontPosTop();
u8g2.setCursor(15, 20);
if (ShowTemp > 500)
u8g2.print(F("000"));
else
u8g2.printf("%03d", ShowTemp);
}
} while (u8g2.nextPage());
}
// setup screen 设置屏幕
void SetupScreen() {
ledcWrite(CONTROL_CHANNEL, HEATER_OFF); // shut off heater
beep();
uint16_t SaveSetTemp = SetTemp;
uint8_t selection = 0;
bool repeat = true;
while (repeat) {
selection = MenuScreen(SetupItems, sizeof(SetupItems), selection);
switch (selection) {
case 0: {
TipScreen();
repeat = false;
} break;
case 1: {
TempScreen();
} break;
case 2: {
TimerScreen();
} break;
// case 3:
// PIDenable = MenuScreen(ControlTypeItems,
// sizeof(ControlTypeItems), PIDenable); break;
case 3: {
MainScrType =
MenuScreen(MainScreenItems, sizeof(MainScreenItems), MainScrType);
} break;
case 4: {
InfoScreen();
} break;
case 5:
VoltageValue =
MenuScreen(VoltageItems, sizeof(VoltageItems), VoltageValue);
PD_Update();
break;
case 6:
QCEnable = MenuScreen(QCItems, sizeof(QCItems), QCEnable);
break;
case 7:
beepEnable = MenuScreen(BuzzerItems, sizeof(BuzzerItems), beepEnable);
break;
case 8: {
restore_default_config = MenuScreen(DefaultItems, sizeof(DefaultItems),
restore_default_config);
if (restore_default_config) {
restore_default_config = false;
write_default_EEPROM();
read_EEPROM();
}
} break;
case 9: {
bool lastbutton = (!digitalRead(BUTTON_PIN));
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(0, 10,
"MSC Update"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(1000);
do {
MSC_Update.onEvent(usbEventCallback);
MSC_Update.begin();
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
MSC_Update.end();
} break;
case 10: {
Serial.println(language);
language = MenuScreen(LanguagesItems, sizeof(LanguagesItems), language);
Serial.println(language);
repeat = false;
} break;
case 11: {
if(hand_side == 0){
u8g2.setDisplayRotation(U8G2_R3);
hand_side = 1;
}else{
u8g2.setDisplayRotation(U8G2_R1);
hand_side = 0;
}
repeat = false;
} break;
default:
repeat = false;
break;
}
}
updateEEPROM();
handleMoved = true;
SetTemp = SaveSetTemp;
setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP, SetTemp);
}
// tip settings screen 烙铁头设置屏幕
void TipScreen() {
uint8_t selection = 0;
bool repeat = true;
while (repeat) {
selection = MenuScreen(TipItems, sizeof(TipItems), selection);
switch (selection) {
case 0:
ChangeTipScreen();
break;
case 1:
CalibrationScreen();
break;
case 2:
InputNameScreen();
break;
case 3:
DeleteTipScreen();
break;
case 4:
AddTipScreen();
break;
default:
repeat = false;
break;
}
}
}
// temperature settings screen 温度设置屏幕
void TempScreen() {
uint8_t selection = 0;
bool repeat = true;
while (repeat) {
selection = MenuScreen(TempItems, sizeof(TempItems), selection);
switch (selection) {
case 0:
setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP, DefaultTemp);
DefaultTemp = InputScreen(DefaultTempItems);
break;
case 1:
setRotary(50, TEMP_MAX, TEMP_STEP, SleepTemp);
SleepTemp = InputScreen(SleepTempItems);
break;
case 2:
setRotary(10, 100, TEMP_STEP, BoostTemp);
BoostTemp = InputScreen(BoostTempItems);
break;
default:
repeat = false;
break;
}
}
}
// timer settings screen 定时器设置屏幕
void TimerScreen() {
uint8_t selection = 0;
bool repeat = true;
while (repeat) {
selection = MenuScreen(TimerItems, sizeof(TimerItems), selection);
switch (selection) {
case 0:
setRotary(0, 600, 10, time2sleep);
time2sleep = InputScreen(SleepTimerItems);
break;
case 1:
setRotary(0, 60, 1, time2off);
time2off = InputScreen(OffTimerItems);
break;
case 2:
setRotary(0, 180, 10, timeOfBoost);
timeOfBoost = InputScreen(BoostTimerItems);
break;
case 3:
setRotary(0, 50, 5, WAKEUPthreshold);
WAKEUPthreshold = InputScreen(WAKEUPthresholdItems);
break;
default:
repeat = false;
break;
}
}
}
// menu screen 菜单屏幕
uint8_t MenuScreen(const char *Items[][language_types], uint8_t numberOfItems,
uint8_t selected) {
// Serial.println(numberOfItems);
bool isTipScreen = ((strcmp(Items[0][language], "烙铁头:") == 0) ||
(strcmp(Items[0][language], "Tip:") == 0) ||
(strcmp(Items[0][language], "烙鐵頭:") == 0));
uint8_t lastselected = selected;
int8_t arrow = 0;
if (selected) arrow = 1;
numberOfItems = numberOfItems / language_types;
numberOfItems >>= 2;
// 根据OLED控制器设置选择方向
#if defined(SSD1306)
setRotary(0, numberOfItems + 3, 1, selected);
#elif defined(SH1107)
setRotary(0, numberOfItems - 2, 1, selected);
#else
#error Wrong OLED controller type!
#endif
bool lastbutton = (!digitalRead(BUTTON_PIN));
do {
selected = getRotary();
arrow = constrain(arrow + selected - lastselected, 0, 2);
lastselected = selected;
u8g2.firstPage();
do {
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, Items[0][language]);
if (isTipScreen)
u8g2.drawUTF8(54, 0 + SCREEN_OFFSET, TipName[CurrentTip]);
u8g2.drawUTF8(0, 16 * (arrow + 1) + SCREEN_OFFSET, ">");
for (uint8_t i = 0; i < 3; i++) {
uint8_t drawnumber = selected + i + 1 - arrow;
if (drawnumber < numberOfItems)
u8g2.drawUTF8(12, 16 * (i + 1) + SCREEN_OFFSET,
Items[selected + i + 1 - arrow][language]);
}
} while (u8g2.nextPage());
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
beep();
return selected;
}
void MessageScreen(const char *Items[][language_types], uint8_t numberOfItems) {
numberOfItems = numberOfItems / language_types;
bool lastbutton = (!digitalRead(BUTTON_PIN));
u8g2.firstPage();
do {
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
for (uint8_t i = 0; i < numberOfItems; i++)
u8g2.drawUTF8(0, i * 16, Items[i][language]);
} while (u8g2.nextPage());
do {
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
beep();
}
// input value screen 输入值屏幕
uint16_t InputScreen(const char *Items[][language_types]) {
uint16_t value;
bool lastbutton = (!digitalRead(BUTTON_PIN));
do {
value = getRotary();
u8g2.firstPage();
do {
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, Items[0][language]);
u8g2.setCursor(0, 32);
u8g2.print(">");
u8g2.setCursor(10, 32);
if (value == 0)
u8g2.print(txt_Deactivated[language]);
else {
u8g2.print(value);
u8g2.print(" ");
u8g2.print(Items[1][language]);
}
} while (u8g2.nextPage());
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
beep();
return value;
}
// information display screen 信息显示屏幕
void InfoScreen() {
bool lastbutton = (!digitalRead(BUTTON_PIN));
do {
Vin = getVIN(); // read supply voltage
float fVin = (float)Vin / 1000; // convert mv in V
float fTmp = getChipTemp(); // read cold junction temperature
u8g2.firstPage();
do {
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
u8g2.setCursor(0, 0 + SCREEN_OFFSET);
u8g2.print(txt_temp[language]);
u8g2.print(fTmp, 1);
u8g2.print(F(" C"));
u8g2.setCursor(0, 16 + SCREEN_OFFSET);
u8g2.print(txt_voltage[language]);
u8g2.print(fVin, 1);
u8g2.print(F(" V"));
u8g2.setCursor(0, 16 * 2 + SCREEN_OFFSET);
u8g2.print(txt_Version[language]);
u8g2.print(VERSION);
// u8g2.setCursor(0, 48); u8g2.print(F("IMU: "));
// u8g2.print(accelerometer[1], DEC); u8g2.print(F(""));
} while (u8g2.nextPage());
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
beep();
}
// change tip screen 改变烙铁头屏幕
void ChangeTipScreen() {
uint8_t selected = CurrentTip;
uint8_t lastselected = selected;
int8_t arrow = 0;
if (selected) arrow = 1;
setRotary(0, NumberOfTips - 1, 1, selected);
bool lastbutton = (!digitalRead(BUTTON_PIN));
Serial.print("selected: ");
Serial.println(selected);
Serial.print("lastselected: \n");
Serial.println(lastselected);
Serial.print("NumberOfTips: \n");
Serial.println(NumberOfTips);
do {
selected = getRotary();
arrow = constrain(arrow + selected - lastselected, 0, 2);
lastselected = selected;
u8g2.firstPage();
do {
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
// strcpy_P(F_Buffer, PSTR("选择烙铁头"));
u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_select_tip[language]);
u8g2.drawUTF8(0, 16 * (arrow + 1) + SCREEN_OFFSET, ">");
for (uint8_t i = 0; i < 3; i++) {
uint8_t drawnumber = selected + i - arrow;
if (drawnumber < NumberOfTips)
u8g2.drawUTF8(12, 16 * (i + 1) + SCREEN_OFFSET,
TipName[selected + i - arrow]);
}
} while (u8g2.nextPage());
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
beep();
CurrentTip = selected;
}
// temperature calibration screen 温度校准屏幕
void CalibrationScreen() {
uint16_t CalTempNew[4];
uint16_t tempSetTemp = SetTemp;
for (uint8_t CalStep = 0; CalStep < 3; CalStep++) {
SetTemp = CalTemp[CurrentTip][CalStep];
Serial.print("SetTemp: ");
Serial.println(SetTemp);
setRotary(100, 500, 1, SetTemp);
beepIfWorky = true;
bool lastbutton = (!digitalRead(BUTTON_PIN));
do {
SENSORCheck(); // reads temperature and vibration switch of the iron
// 读取烙铁头的温度和振动开关
Thermostat(); // heater control
u8g2.firstPage();
do {
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
// strcpy_P(F_Buffer, PSTR("校准"));
u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_calibrate[language]);
u8g2.setCursor(0, 16 + SCREEN_OFFSET);
u8g2.print(txt_step[language]);
u8g2.print(CalStep + 1);
u8g2.print(" of 3");
if (isWorky) {
u8g2.setCursor(0, 32 + SCREEN_OFFSET);
u8g2.print(txt_set_measured[language]);
u8g2.setCursor(0, 48 + SCREEN_OFFSET);
u8g2.print(txt_s_temp[language]);
u8g2.print(getRotary());
} else {
u8g2.setCursor(0, 32 + SCREEN_OFFSET);
u8g2.print(txt_temp_2[language]);
u8g2.print(uint16_t(RawTemp));
u8g2.setCursor(0, 48 + SCREEN_OFFSET);
u8g2.print(txt_wait_pls[language]);
}
} while (u8g2.nextPage());
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
CalTempNew[CalStep] = getRotary();
beep();
delay(10);
}
ledcWrite(CONTROL_CHANNEL, HEATER_OFF); // shut off heater 关闭加热器
if (VoltageValue == 3) {
delayMicroseconds(TIME2SETTLE_20V);
} else {
delayMicroseconds(TIME2SETTLE); // wait for voltage to settle 等待电压稳定
}
CalTempNew[3] = getChipTemp(); // read chip temperature 读芯片温度
if ((CalTempNew[0] + 10 < CalTempNew[1]) &&
(CalTempNew[1] + 10 < CalTempNew[2])) {
if (MenuScreen(StoreItems, sizeof(StoreItems), 0)) {
for (uint8_t i = 0; i < 4; i++) CalTemp[CurrentTip][i] = CalTempNew[i];
}
}
SetTemp = tempSetTemp;
update_EEPROM();
}
// input tip name screen 输入烙铁头名字屏幕
void InputNameScreen() {
uint8_t value;
for (uint8_t digit = 0; digit < (TIPNAMELENGTH - 1); digit++) {
bool lastbutton = (!digitalRead(BUTTON_PIN));
setRotary(31, 96, 1, 65);
do {
value = getRotary();
if (value == 31) {
value = 95;
setRotary(31, 96, 1, 95);
}
if (value == 96) {
value = 32;
setRotary(31, 96, 1, 32);
}
u8g2.firstPage();
do {
u8g2.setFont(PTS200_16);
if(language == 2){
u8g2.setFont(u8g2_font_unifont_t_chinese3);
}
u8g2.setFontPosTop();
u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_enter_tip_name[language]);
u8g2.setCursor(12 * digit, 48 + SCREEN_OFFSET);
u8g2.print(char(94));
u8g2.setCursor(0, 32 + SCREEN_OFFSET);
for (uint8_t i = 0; i < digit; i++) u8g2.print(TipName[CurrentTip][i]);
u8g2.setCursor(12 * digit, 32 + SCREEN_OFFSET);
u8g2.print(char(value));
} while (u8g2.nextPage());
if (lastbutton && digitalRead(BUTTON_PIN)) {
delay(10);
lastbutton = false;
}
} while (digitalRead(BUTTON_PIN) || lastbutton);
TipName[CurrentTip][digit] = value;
beep();
delay(10);
}
TipName[CurrentTip][TIPNAMELENGTH - 1] = 0;
return;
}
// delete tip screen 删除烙铁头屏幕
void DeleteTipScreen() {
if (NumberOfTips == 1) {
MessageScreen(DeleteMessage, sizeof(DeleteMessage));
} else if (MenuScreen(SureItems, sizeof(SureItems), 0)) {
if (CurrentTip == (NumberOfTips - 1)) {
CurrentTip--;
} else {
for (uint8_t i = CurrentTip; i < (NumberOfTips - 1); i++) {
for (uint8_t j = 0; j < TIPNAMELENGTH; j++)
TipName[i][j] = TipName[i + 1][j];
for (uint8_t j = 0; j < 4; j++) CalTemp[i][j] = CalTemp[i + 1][j];
}
}
NumberOfTips--;
}
}
// add new tip screen 添加新的烙铁头屏幕
void AddTipScreen() {
if (NumberOfTips < TIPMAX) {
CurrentTip = NumberOfTips++;
InputNameScreen();
CalTemp[CurrentTip][0] = TEMP200;
CalTemp[CurrentTip][1] = TEMP280;
CalTemp[CurrentTip][2] = TEMP360;
CalTemp[CurrentTip][3] = TEMPCHP;
} else
MessageScreen(MaxTipMessage, sizeof(MaxTipMessage));
}
// 对32个ADC读数进行平均以降噪
// VP+_Ru = 100k, Rd_GND = 1K
uint16_t denoiseAnalog(byte port) {
uint32_t result = 0;
float maxValue, minValue;
int resultArray[8];
for (uint8_t i = 0; i < 8; i++) {
// get 32 readings and sort them 获取32个读数并对其进行排序
float value, raw_adc;
raw_adc = adc_sensor.readMiliVolts();
// value = constrain(0.4432 * raw_adc + 29.665, 20, 1000);
value = constrain(0.5378 * raw_adc + 6.3959, 20, 1000); // y = 0.5378x + 6.3959
resultArray[i] = value;
}
// sort resultArray with low time complexity
// 用低时间复杂度对resultArray进行排序
for (uint8_t i = 0; i < 8; i++) {
for (uint8_t j = i + 1; j < 8; j++) {
if (resultArray[i] > resultArray[j]) {
int temp = resultArray[i];
resultArray[i] = resultArray[j];
resultArray[j] = temp;
}
}
}
// get the average of the middle 4 readings 获取中间20个读数的平均值
for (uint8_t i = 2; i < 6; i++) {
result += resultArray[i];
}
// Serial.printf("raw_val: %d", adc_sensor.readMiliVolts());
// Serial.println();
// Serial.printf("val: %d", result / 4);
// Serial.println();
return (result / 4); // devide by 32 and return value 除以32并返回值
}
// 读取SENSOR内部温度
double getChipTemp() {
#if defined(MPU)
mpu6050.update();
int16_t Temp = mpu6050.getTemp();
#elif defined(LIS)
int16_t Temp = accel.getTemperature();
#endif
return Temp;
}
// get LIS/MPU temperature 获取LIS/MPU的温度
float getMPUTemp() {
#if defined(MPU)
mpu6050.update();
int16_t Temp = mpu6050.getTemp();
#elif defined(LIS)
int16_t Temp = accel.getTemperature();
#endif
return Temp;
}
// get supply voltage in mV 得到以mV为单位的电源电压
uint16_t getVIN() {
long value;
long voltage;
long result = 0;
for (uint8_t i = 0; i < 4; i++) { // get 32 readings 得到32个读数
// long val = analogRead(VIN_PIN);
long val = adc_vin.readMiliVolts();
result += val; // add them up 把它们加起来
}
value = (result / 4);
// // VIN_Ru = 100k, Rd_GND = 3.3K
// if (value < 500)
// {
// voltage = value * 1390 * 31.3 / 4095 * 1.35;
// }
// else if (500 <= value && value < 1000)
// {
// voltage = value * 1390 * 31.3 / 4095 * 1.135;
// }
// else if (1000 <= value && value < 1500)
// {
// voltage = value * 1390 * 31.3 / 4095 * 1.071;
// }
// else if (1500 <= value && value < 2000)
// {
// voltage = value * 1390 * 31.3 / 4095;
// }
// else if (2000 <= value && value < 3000)
// {
// voltage = value * 1390 * 31.3 / 4095;
// }
// else
// voltage = value * 1390 * 31.3 / 4095;
voltage = value * 31.3;
return voltage;
// return value;
}
int32_t variance(int16_t a[]) {
// Compute mean (average of elements)计算平均值(元素的平均值)
int32_t sum = 0;
for (int i = 0; i < 32; i++) sum += a[i];
int16_t mean = (int32_t)sum / 32;
// Compute sum squared differences with mean.计算和平方差的平均值
int32_t sqDiff = 0;
for (int i = 0; i < 32; i++) sqDiff += (a[i] - mean) * (a[i] - mean);
return (int32_t)sqDiff / 32;
}
unsigned int Button_Time1 = 0, Button_Time2 = 0;
void Button_loop() {
if (!digitalRead(BUTTON_N_PIN) && a0 == 1) {
delay(BUTTON_DELAY);
if (!digitalRead(BUTTON_N_PIN)) {
int count0 = count;
count = constrain(count + countStep, countMin, countMax);
if (!(countMin == TEMP_MIN && countMax == TEMP_MAX)) {
if (count0 + countStep > countMax) {
count = countMin;
}
}
a0 = 0;
}
} else if (!digitalRead(BUTTON_N_PIN) && a0 == 0) {
delay(BUTTON_DELAY);
if (Button_Time1 > 10) // 这里的数越大,需要长按时间更长
count = constrain(count + countStep, countMin, countMax);
else
Button_Time1++;
} else if (digitalRead(BUTTON_N_PIN)) {
Button_Time1 = 0;
a0 = 1;
}
if (!digitalRead(BUTTON_P_PIN) && b0 == 1) {
delay(BUTTON_DELAY);
if (!digitalRead(BUTTON_P_PIN)) {
int count0 = count;
count = constrain(count - countStep, countMin, countMax);
if (!(countMin == TEMP_MIN && countMax == TEMP_MAX)) {
if (count0 - countStep < countMin) {
count = countMax;
}
}
b0 = 0;
}
} else if (!digitalRead(BUTTON_P_PIN) && b0 == 0) {
delay(BUTTON_DELAY);
if (Button_Time2 > 10) // 这里的数越大,需要长按时间更长
count = constrain(count - countStep, countMin, countMax);
else
Button_Time2++;
} else if (digitalRead(BUTTON_P_PIN)) {
Button_Time2 = 0;
b0 = 1;
}
}
void PD_Update() {
switch (VoltageValue) {
case 0: {
digitalWrite(PD_CFG_0, LOW);
digitalWrite(PD_CFG_1, LOW);
digitalWrite(PD_CFG_2, LOW);
} break;
case 1: {
digitalWrite(PD_CFG_0, LOW);
digitalWrite(PD_CFG_1, LOW);
digitalWrite(PD_CFG_2, HIGH);
} break;
case 2: {
digitalWrite(PD_CFG_0, LOW);
digitalWrite(PD_CFG_1, HIGH);
digitalWrite(PD_CFG_2, HIGH);
} break;
case 3: {
digitalWrite(PD_CFG_0, LOW);
digitalWrite(PD_CFG_1, HIGH);
digitalWrite(PD_CFG_2, LOW);
} break;
case 4: {
digitalWrite(PD_CFG_0, LOW);
digitalWrite(PD_CFG_1, HIGH);
digitalWrite(PD_CFG_2, LOW);
} break;
default:
break;
}
if (VoltageValue == 3) {
ledcSetup(CONTROL_CHANNEL, CONTROL_FREQ_20V, CONTROL_RES);
} else {
ledcSetup(CONTROL_CHANNEL, CONTROL_FREQ, CONTROL_RES);
}
ledcAttachPin(CONTROL_PIN, CONTROL_CHANNEL);
// analogWrite(CONTROL_PIN, HEATER_OFF); // this shuts off the
// heater这是用来关闭加热器的
ledcWrite(CONTROL_CHANNEL, HEATER_OFF);
}
static void usbEventCallback(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == ARDUINO_USB_EVENTS) {
// arduino_usb_event_data_t* data = (arduino_usb_event_data_t*)event_data;
switch (event_id) {
case ARDUINO_USB_STARTED_EVENT:
// HWSerial.println("USB PLUGGED");
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(0, 10,
"USB PLUGGED"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
case ARDUINO_USB_STOPPED_EVENT:
// HWSerial.println("USB UNPLUGGED");
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(
0, 10, "USB UNPLUGGED"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
case ARDUINO_USB_SUSPEND_EVENT:
// HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n",
// data->suspend.remote_wakeup_en);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(
0, 10, "USB SUSPENDED"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
case ARDUINO_USB_RESUME_EVENT:
// HWSerial.println("USB RESUMED");
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(0, 10,
"USB RESUMED"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
default:
break;
}
} else if (event_base == ARDUINO_FIRMWARE_MSC_EVENTS) {
// arduino_firmware_msc_event_data_t* data =
// (arduino_firmware_msc_event_data_t*)event_data;
switch (event_id) {
case ARDUINO_FIRMWARE_MSC_START_EVENT:
// HWSerial.println("MSC Update Start");
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(
0, 10,
"MSC Update Start"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
case ARDUINO_FIRMWARE_MSC_WRITE_EVENT:
// HWSerial.printf("MSC Update Write %u bytes at offset %u\n",
// data->write.size, data->write.offset);
// HWSerial.print(".");
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(0, 10,
"MSC Updating"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
case ARDUINO_FIRMWARE_MSC_END_EVENT:
// HWSerial.printf("\nMSC Update End: %u bytes\n", data->end.size);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(
0, 10, "MSC Update End"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
case ARDUINO_FIRMWARE_MSC_ERROR_EVENT:
// HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n",
// data->error.size);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(
0, 10,
"MSC Update ERROR!"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
case ARDUINO_FIRMWARE_MSC_POWER_EVENT:
// HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u",
// data->power.power_condition, data->power.start,
// data->power.load_eject);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(
0, 10,
"MSC Update Power"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
break;
default:
break;
}
}
}
void turnOffHeater(Button2 &b) { inOffMode = true; }
// uint16_t calibrate_adc(adc_unit_t adc, adc_atten_t channel) {
// uint16_t vref;
// esp_adc_cal_characteristics_t adc_chars;
// esp_adc_cal_value_t val_type = esp_adc_cal_characterize((adc_unit_t)adc,
// (adc_atten_t)channel, (adc_bits_width_t)ADC_WIDTH_BIT_12, 1100,
// &adc_chars);
// //Check type of calibration value used to characterize ADC
// if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
// Serial.printf("eFuse Vref:%u mV", adc_chars.vref);
// Serial.println();
// vref = adc_chars.vref;
// } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
// Serial.printf("Two Point --> coeff_a:%umV coeff_b:%umV\n",
// adc_chars.coeff_a, adc_chars.coeff_b); Serial.println();
// } else {
// Serial.println("Default Vref: 1100mV");
// }
// return vref;
// }
void heatWithLimit() {
// ledcSetup(channel, hertz, resolution);
// ledcAttachPin(pin, channel);
limit = 0;
if (VoltageValue < 3) {
limit = POWER_LIMIT_15;
} else if (VoltageValue == 3) {
limit = POWER_LIMIT_20;
}
ledcWrite(
CONTROL_CHANNEL,
constrain(HEATER_PWM, 0, limit)); // turn on again heater 再次打开加热器
}
================================================
FILE: SolderingPen_ESP32S2/UtilsEEPROM.h
================================================
#include <EEPROM.h>
#define ADDR_SYSTEM_INIT_FLAG 0
#define ADDR_DEFAULT_TEMP ADDR_SYSTEM_INIT_FLAG + 4
#define ADDR_SLEEP_TEMP ADDR_DEFAULT_TEMP + 2
#define ADDR_BOOST_TEMP ADDR_SLEEP_TEMP + 2
#define ADDR_TIME_2_SLEEP ADDR_BOOST_TEMP + 1
#define ADDR_TIME_2_OFF ADDR_TIME_2_SLEEP + 2
#define ADDR_TIME_OF_BOOST ADDR_TIME_2_OFF + 1
#define ADDR_MAIN_SCREEN ADDR_TIME_OF_BOOST + 1
#define ADDR_PID_ENABLE ADDR_MAIN_SCREEN + 1
#define ADDR_BEEP_ENABLE ADDR_PID_ENABLE + 1
#define ADDR_VOLTAGE_VALUE ADDR_BEEP_ENABLE + 1
#define ADDR_QC_ENABLE ADDR_VOLTAGE_VALUE + 1
#define ADDR_WAKEUP_THRESHOLD ADDR_QC_ENABLE + 1
#define ADDR_CURRENT_TIP ADDR_WAKEUP_THRESHOLD + 1
#define ADDR_NUMBER_OF_TIPS ADDR_CURRENT_TIP + 1
#define ADDR_TIP_NAME ADDR_NUMBER_OF_TIPS + 1
#define ADDR_CAL_TEMP ADDR_TIP_NAME + TIPNAMELENGTH *TIPMAX
#define ADDR_LANGUAGE ADDR_CAL_TEMP + 2 * CALNUM *TIPMAX
#define ADDR_HAND_SIDE ADDR_LANGUAGE + 1
#define ADDR_EEPROM_SIZE ADDR_HAND_SIDE + 1
bool system_init_flag = false;
extern uint16_t DefaultTemp;
extern uint16_t SleepTemp;
extern uint8_t BoostTemp;
extern uint16_t time2sleep;
extern uint8_t time2off;
extern uint8_t timeOfBoost;
extern uint8_t MainScrType;
extern bool PIDenable;
extern bool beepEnable;
extern volatile uint8_t VoltageValue;
extern bool QCEnable;
extern uint8_t WAKEUPthreshold;
extern uint8_t CurrentTip;
extern uint8_t NumberOfTips;
extern char TipName[TIPMAX][TIPNAMELENGTH];
extern uint16_t CalTemp[TIPMAX][CALNUM];
extern uint8_t language;
extern uint8_t hand_side;
bool write_default_EEPROM()
{
Serial.println("Writing default config to EEPROM");
EEPROM.writeUShort(ADDR_DEFAULT_TEMP, TEMP_DEFAULT);
EEPROM.writeUShort(ADDR_SLEEP_TEMP, TEMP_SLEEP);
EEPROM.writeUChar(ADDR_BOOST_TEMP, TEMP_BOOST);
EEPROM.writeUShort(ADDR_TIME_2_SLEEP, TIME2SLEEP);
EEPROM.writeUChar(ADDR_TIME_2_OFF, TIME2OFF);
EEPROM.writeUChar(ADDR_TIME_OF_BOOST, TIMEOFBOOST);
EEPROM.writeUChar(ADDR_MAIN_SCREEN, MAINSCREEN);
EEPROM.writeBool(ADDR_PID_ENABLE, PID_ENABLE);
EEPROM.writeBool(ADDR_BEEP_ENABLE, BEEP_ENABLE);
EEPROM.writeUChar(ADDR_VOLTAGE_VALUE, VOLTAGE_VALUE);
EEPROM.writeBool(ADDR_QC_ENABLE, QC_ENABLE);
EEPROM.writeUChar(ADDR_WAKEUP_THRESHOLD, WAKEUP_THRESHOLD);
EEPROM.writeUChar(ADDR_CURRENT_TIP, 0);
EEPROM.writeUChar(ADDR_NUMBER_OF_TIPS, 1);
CalTemp[0][0] = TEMP200;
CalTemp[0][1] = TEMP280;
CalTemp[0][2] = TEMP360;
CalTemp[0][3] = TEMPCHP;
// TipName[0][TIPNAMELENGTH] = {TIPNAME};
for (uint8_t i = 0; i < 1; i++)
{
EEPROM.writeString(ADDR_TIP_NAME + i * TIPNAMELENGTH, TipName[i]);
for (uint8_t j = 0; j < CALNUM; j++)
{
EEPROM.writeUShort(ADDR_CAL_TEMP + i * 2 * CALNUM + j * 2, CalTemp[i][j]);
}
}
EEPROM.writeUChar(ADDR_LANGUAGE, DEFAULT_LANGUAGE);
EEPROM.writeUChar(ADDR_HAND_SIDE, DEFAULT_HAND_SIDE);
EEPROM.writeUInt(ADDR_SYSTEM_INIT_FLAG, VERSION_NUM);
if (EEPROM.commit())
{
Serial.println("Default config Done");
return true;
}
else
{
Serial.println("Default config Failed");
return false;
}
}
bool init_EEPROM()
{
Serial.println("Initialising EEPROM");
if (!EEPROM.begin(ADDR_EEPROM_SIZE))
{
Serial.println("Failed to initialise EEPROM");
// Serial.println("Restarting...");
// delay(1000);
// ESP.restart();
return false;
}
Serial.println("EEPROM Done");
return true;
}
bool update_EEPROM()
{
Serial.println("Updating EEPROM");
EEPROM.writeUShort(ADDR_DEFAULT_TEMP, DefaultTemp);
EEPROM.writeUShort(ADDR_SLEEP_TEMP, SleepTemp);
EEPROM.writeUChar(ADDR_BOOST_TEMP, BoostTemp);
EEPROM.writeUShort(ADDR_TIME_2_SLEEP, time2sleep);
EEPROM.writeUChar(ADDR_TIME_2_OFF, time2off);
EEPROM.writeUChar(ADDR_TIME_OF_BOOST, timeOfBoost);
EEPROM.writeUChar(ADDR_MAIN_SCREEN, MainScrType);
EEPROM.writeBool(ADDR_PID_ENABLE, PIDenable);
EEPROM.writeBool(ADDR_BEEP_ENABLE, beepEnable);
EEPROM.writeUChar(ADDR_VOLTAGE_VALUE, VoltageValue);
EEPROM.writeBool(ADDR_QC_ENABLE, QCEnable);
EEPROM.writeUChar(ADDR_WAKEUP_THRESHOLD, WAKEUPthreshold);
EEPROM.writeUChar(ADDR_CURRENT_TIP, CurrentTip);
EEPROM.writeUChar(ADDR_NUMBER_OF_TIPS, NumberOfTips);
for (uint8_t i = 0; i < NumberOfTips; i++)
{
EEPROM.writeString(ADDR_TIP_NAME + i * TIPNAMELENGTH, TipName[i]);
for (uint8_t j = 0; j < CALNUM; j++)
{
EEPROM.writeUShort(ADDR_CAL_TEMP + i * 2 * CALNUM + j * 2, CalTemp[i][j]);
}
}
EEPROM.writeUChar(ADDR_LANGUAGE, language);
EEPROM.writeUChar(ADDR_HAND_SIDE, hand_side);
EEPROM.writeUInt(ADDR_SYSTEM_INIT_FLAG, VERSION_NUM);
if (EEPROM.commit())
{
Serial.println("EEPROM Update Done");
return true;
}
else
{
Serial.println("EEPROM Update Failed");
return false;
}
}
bool read_EEPROM()
{
Serial.println("Reading EEPROM");
// write_default_EEPROM();
// system_init_flag = EEPROM.readUInt(ADDR_SYSTEM_INIT_FLAG);
if (EEPROM.readUInt(ADDR_SYSTEM_INIT_FLAG) != VERSION_NUM)
{
// return false;
Serial.println("System didn't initialised");
write_default_EEPROM();
}
// EEPROM.readString(ADDR_WIFI_SSID_1).toCharArray(WiFi_SSID_1, sizeof(WiFi_SSID_1));
DefaultTemp = EEPROM.readUShort(ADDR_DEFAULT_TEMP);
SleepTemp = EEPROM.readUShort(ADDR_SLEEP_TEMP);
BoostTemp = EEPROM.readUChar(ADDR_BOOST_TEMP);
time2sleep = EEPROM.readUShort(ADDR_TIME_2_SLEEP);
time2off = EEPROM.readUChar(ADDR_TIME_2_OFF);
timeOfBoost = EEPROM.readUChar(ADDR_TIME_OF_BOOST);
MainScrType = EEPROM.readUChar(ADDR_MAIN_SCREEN);
PIDenable = EEPROM.readBool(ADDR_PID_ENABLE);
beepEnable = EEPROM.readBool(ADDR_BEEP_ENABLE);
VoltageValue = EEPROM.readUChar(ADDR_VOLTAGE_VALUE);
QCEnable = EEPROM.readBool(ADDR_QC_ENABLE);
WAKEUPthreshold = EEPROM.readUChar(ADDR_WAKEUP_THRESHOLD);
CurrentTip = EEPROM.readUChar(ADDR_CURRENT_TIP);
NumberOfTips = EEPROM.readUChar(ADDR_NUMBER_OF_TIPS);
for (uint8_t i = 0; i < NumberOfTips; i++)
{
EEPROM.readString(ADDR_TIP_NAME + i * TIPNAMELENGTH).toCharArray(TipName[i], sizeof(TipName[i]));
for (uint8_t j = 0; j < CALNUM; j++)
{
CalTemp[i][j] = EEPROM.readUShort(ADDR_CAL_TEMP + i * 2 * CALNUM + j * 2);
}
}
language = EEPROM.readUChar(ADDR_LANGUAGE);
hand_side = EEPROM.readUChar(ADDR_HAND_SIDE);
return true;
}
bool update_default_temp_EEPROM()
{
Serial.println("Updating default temp in EEPROM");
EEPROM.writeUShort(ADDR_DEFAULT_TEMP, DefaultTemp);
if (EEPROM.commit())
{
Serial.println("Default temp Update Done");
return true;
}
else
{
Serial.println("Default temp Update Failed");
return false;
}
}
================================================
FILE: SolderingPen_ESP32S2/config.h
================================================
// Firmware version
#define VERSION "v4.5.3" //20240130
#define VERSION_NUM 422
// Type of MOSFET
#define P_MOSFET // P_MOSFET or N_MOSFET
// Type of OLED Controller
// #define SSD1306
#define SH1107
//typedef u8g2_uint_t u8g_uint_t;
#define SCREEN_OFFSET 2
// 旋转编码器的类型
#define ROTARY_TYPE 0 // 0: 2 increments/step; 1: 4 increments/step (default)
#define BUTTON_DELAY 5
// Pins
#define SENSOR_PIN 1 // tip temperature sense 烙铁头温感
#define VIN_PIN 6 // input voltage sense 检测输入电压
#define BUZZER_PIN 3 // buzzer 蜂鸣器
#define BUTTON_PIN 0 // switch 按键right
#define BUTTON_P_PIN 4 // 1 键位为“+”
#define BUTTON_N_PIN 2 // 2 键位为“-”
#define CONTROL_PIN 5 // heater MOSFET PWM control 加热器MOSFET PWM控制
#define CONTROL_CHANNEL 2 // PWM channel
#define CONTROL_FREQ 200 // PWM frequency
#define CONTROL_FREQ_20V 1000 // PWM frequency for 20V
#define CONTROL_RES 8 // PWM resolution
#define PD_CFG_0 16
#define PD_CFG_1 17
#define PD_CFG_2 18
// 默认温度控制值(推荐焊接温度:300~380°C)
#define TEMP_MIN 50 // 最小温度
#define TEMP_MAX 450 // 最大温度
#define TEMP_DEFAULT 260 // 默认温度
#define TEMP_SLEEP 150 // 休眠温度
#define TEMP_BOOST 50 // 升温步进
#define TEMP_STEP 10 // 旋转编码器温度变化步进
#define POWER_LIMIT_15 170 // 功率限制
#define POWER_LIMIT_20 255 // 功率限制
#define POWER_LIMIT_20_2 127 // 功率限制
// 默认的T12烙铁头温度校准值
#define TEMP200 200 // temperature at ADC = 200
#define TEMP280 280 // temperature at ADC = 280
#define TEMP360 360 // temperature at ADC = 360
#define TEMPCHP 35 // chip temperature while calibration 校准时芯片温度
#define CALNUM 4 // Calibration point number
#define TIPMAX 8 // max number of tips
#define TIPNAMELENGTH 6 // max length of tip names (including termination)
#define TIPNAME "PTS " // default tip name
// 默认的定时器值 (0 = 禁用)
#define TIME2SLEEP 60 // 几秒钟后进入睡眠模式
#define TIME2OFF 5 // 几分钟后就要关闭加热器了
#define TIMEOFBOOST 60 // 停留在加热模式多少秒
#define WAKEUP_THRESHOLD 10 // MPU 震动检测精度,数值越小,越灵敏
// Control values
#define TIME2SETTLE 5000 // 以微秒为单位的时间允许OpAmp输出稳定
#define TIME2SETTLE_20V 2000 // 以微秒为单位的时间允许OpAmp输出稳定
#define SMOOTHIE 0.05 // OpAmp输出平滑系数 (1=无平滑; 默认:0.05)
#define PID_ENABLE false // enable PID control
#define BEEP_ENABLE true // enable/disable buzzer
#define VOLTAGE_VALUE 3 // 电压值
#define QC_ENABLE false // enable/disable QC3.0
#define MAINSCREEN 1 // type of main screen (0: big numbers; 1: more infos)
// EEPROM identifier
#define EEPROM_SIZE 1024
// MOSFET control definitions
#if defined(P_MOSFET) // P-Channel MOSFET
#define HEATER_ON 255
#define HEATER_OFF 0
#define HEATER_PWM 255 - Output
#elif defined(N_MOSFET) // N-Channel MOSFET
#define HEATER_ON 0
#define HEATER_OFF 255
#define HEATER_PWM Output
#else
#error Wrong MOSFET type!
#endif
//Language
#define DEFAULT_LANGUAGE 0
//Hand side
#define DEFAULT_HAND_SIDE 1
================================================
FILE: boards/PTS200.json
================================================
{
"build": {
"arduino": {
"ldscript": "esp32s2_out.ld"
},
"core": "esp32",
"extra_flags": [
"-DARDUINO_USB_CDC_ON_BOOT=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0X303A",
"0x80C5"
]
],
"mcu": "esp32s2",
"variant": "esp32s2"
},
"debug": {
"openocd_board": "esp32s2.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Songguo PTS200",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://github.com/Eddddddddy/Songguo-PTS200",
"vendor": "Eddy"
}
================================================
FILE: docs/update_guide.md
================================================
Please use the user version for regular upgrades. Connect the device to the computer with a USB cable, open the firmware upgrade option in the device's menu, and drag the firmware file into the device's MSC storage.
If there is an upgrade failure or other problems with the firmware, you can use the factory version of the firmware and use the ESP flash tool to write the firmware at address 0x0000. Select ESP32S2-Develop-Internal USB to download.
================================================
FILE: platformio.ini
================================================
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
src_dir = SolderingPen_ESP32S2
[env:solderingpen]
platform = espressif32
board = PTS200
framework = arduino
lib_deps =
lennarthennigs/Button2 @ ^2.2.2
vdeconinck/QC3Control @ ^1.4.1
olikraus/U8g2 @ ^2.34.17
madhephaestus/ESP32AnalogRead @ ^0.2.1
br3ttb/PID @ ^1.2.1
sparkfun/SparkFun LIS2DH12 Arduino Library @ ^1.0.3
gitextract_rrchcozt/ ├── .gitignore ├── Power Calculator.numbers ├── Power Calculator.xlsx ├── README.md ├── SolderingPen_ESP32S2/ │ ├── Languages.h │ ├── PTS200_16.h │ ├── SolderingPen_ESP32S2.ino │ ├── UtilsEEPROM.h │ └── config.h ├── boards/ │ └── PTS200.json ├── docs/ │ └── update_guide.md └── platformio.ini
SYMBOL INDEX (5 symbols across 1 files) FILE: SolderingPen_ESP32S2/UtilsEEPROM.h function write_default_EEPROM (line 50) | bool write_default_EEPROM() function init_EEPROM (line 101) | bool init_EEPROM() function update_EEPROM (line 116) | bool update_EEPROM() function read_EEPROM (line 161) | bool read_EEPROM() function update_default_temp_EEPROM (line 208) | bool update_default_temp_EEPROM()
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (106K chars).
[
{
"path": ".gitignore",
"chars": 135,
"preview": ".pioenvs\n.piolibdeps\n.clang_complete\n.gcc-flags.json\n.pio\n.vscode\n.DS_Store\n.idea\nSolderingPen_ESP32S2/build\nSolderingPe"
},
{
"path": "README.md",
"chars": 1313,
"preview": "# Songguo PTS200 \n## Introduction\n1. PD3.0 and QC3 fast charge protocol\n\n2. 20V 5A 100W maximum power\n<!-- 内置IMU,用于休眠检测 "
},
{
"path": "SolderingPen_ESP32S2/Languages.h",
"chars": 7526,
"preview": "// 菜单项\nconst uint8_t language_types = 3;\n// \"温控类型\", \"溫控類型\", \"Control Type"
},
{
"path": "SolderingPen_ESP32S2/PTS200_16.h",
"chars": 22815,
"preview": "/*\n Fontname: -FreeType-Alibaba PuHuiTi Medium-Medium-R-Normal--16-120-96-96-P-142-ISO10646-1\n Copyright: Copyright � "
},
{
"path": "SolderingPen_ESP32S2/SolderingPen_ESP32S2.ino",
"chars": 48243,
"preview": "//\n#include \"config.h\"\n\n//\n#include <Button2.h>\n#include <QC3Control.h>\n\n//\n#include \"FirmwareMSC.h\"\n#include \"Languages"
},
{
"path": "SolderingPen_ESP32S2/UtilsEEPROM.h",
"chars": 6629,
"preview": "#include <EEPROM.h>\n\n#define ADDR_SYSTEM_INIT_FLAG 0\n#define ADDR_DEFAULT_TEMP ADDR_SYSTEM_INIT_FLAG + 4\n#define ADDR_SL"
},
{
"path": "SolderingPen_ESP32S2/config.h",
"chars": 3206,
"preview": "// Firmware version\n#define VERSION \"v4.5.3\" //20240130\n#define VERSION_NUM 422\n\n// Type of MOSFET\n#define P_MOSFET // P"
},
{
"path": "boards/PTS200.json",
"chars": 879,
"preview": "{\n \"build\": {\n \"arduino\": {\n \"ldscript\": \"esp32s2_out.ld\"\n },\n \"core\": \"esp32\",\n \"extra_fl"
},
{
"path": "docs/update_guide.md",
"chars": 449,
"preview": "Please use the user version for regular upgrades. Connect the device to the computer with a USB cable, open the firmware"
},
{
"path": "platformio.ini",
"chars": 709,
"preview": "; PlatformIO Project Configuration File\n;\n; Build options: build flags, source filter\n; Upload options: custom uploa"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the Eddddddddy/Songguo-PTS200 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (89.8 KB), approximately 34.3k tokens, and a symbol index with 5 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.