一、结构设计
潜水手表结构分为上盖与底壳两部分如图一所示。潜水表整体结构如图二所示,蓝色的为触摸屏,白灰色的是电池,绿色的是PCB,黑灰色的是传感器,红色的是磁吸触点。
二、硬件设计
1.核心部件
1)主控:选用 ESP32C3H4 作为主控,自带4MB闪存,无需外加闪存,节省布局空间。需要外加40Mhz的晶振电路,
2)电源:选用 AXP2101 作为PMU,可给电池充电,输出DCDC、LDO给主控以及外设供电,通过I2C可配置输出电压大小(调节屏幕亮度等)、读取电池电量以及重启电源和关掉电源。
3)传感器:选用ST的压力传感器:LPS28DFWTR。可检测气压与温度,检测部位防水,最大量程4060 hPa,理论最大检测水深为310.6m。
4)触摸屏:1.28寸圆屏,240*240屏幕,SPI接口,显示驱动GC9A01,触摸驱动CST816T。
5)RTC: 选用 PCF8563MM/TR,封装较小,节省空间(MSOP-8)。
6)电池:100mAh,21*11*4mm。
2.电路部分
1. 只使用一路I2C连接所有外设,包括触摸屏的触摸引脚(TP-SCL、TP-SDA)。两路I2C同时使用好像有问题。
2. RTC供电使用一颗LDO芯片供电,电池电压直接接到LDO的输入端。未找到AXP2101的RTCLDO输出电压的配置寄存器。
3.主控的GPIO9接按键接地。IO9拉低,主控上电进入Boot模式,通过串口烧录。
三、软件部分
1.安装对应的库
使用Arduino IDE进行编程,在库管理栏搜索外设对应的库,如图三所示
2.初始化代码
#define axp_ADDRESS 0x34
void setup()
{
//初始化串口
Serial.begin(115200);
//指定I2C引脚进行初始化
Wire.begin(1,0);
//屏幕触控初始化
touch.begin();
//初始化PMU
axp2101_init();
//初始化屏幕
tft.init(); //初始化
tft.fillScreen(TFT_BLACK);
tft.setSwapBytes(true); //使图片颜色由RGB->BGR
tft.setRotation(4);
//初始化LPS28DFW
while(pressureSensor.begin(i2cAddress) != LPS28DFW_OK)
{
Serial.println("Error: LPS28DFW not connected, check wiring and I2C address!");
tft.drawString("LPS Err", 30, 90);
delay(1000);
}
//配置为最大量程4060hPa
pressureSensor.setModeConfig(&modeConfig2);
//初始化Preferences,读取Flash里面的变量
preferences.begin("my-app", false);
max_long_time = preferences.getInt("mylongtime", 0); // 默认值为0
max_depth = preferences.getFloat("mymaxdetpth", 0);
max_depth_time =preferences.getFloat("mymaxdetpthtime", 0);
preferences.end();
}
3.AXP2101的配置
//PMU初始化
void axp2101_init()
{
//set_axp2101_r(0x16,0);//输入电流限制100ma
set_axp2101_r(0x20,0x04);//充电时开机 set_axp2101_r(0x20,0x06)
set_axp2101_r(0x21,0x02);//使能软件关机
set_axp2101_r(0x61,0x01);//预充电电流限制25ma
set_axp2101_r(0x62,0x02);//恒流充电电流限制50ma
set_axp2101_r(0x63,0x10);//终止电流限制0ma
set_axp2101_r(0x80,0x01);//只使能DCDC1
set_axp2101_r(0x92,0x1c);//配置aldo1输出为3.3v
set_axp2101_r(0x94,0x17);//配置aldo3-LCD输出为2.8v
}
//获取电池电量
void get_bat_power()
{
power_data=get_data_axp2101(0xA4);
if(power_data>100)
power_data=100;
}
//往寄存器写入
void set_axp2101_r(uint8_t sub,uint8_t data)
{
Wire.beginTransmission(axp_ADDRESS);
Wire.write(sub);
Wire.write(data);
Wire.endTransmission();
}
//读取寄存器的值
uint8_t get_data_axp2101(uint8_t sub)
{
// 读取寄存器的当前值
Wire.beginTransmission(axp_ADDRESS);
Wire.write(sub);
Wire.endTransmission();
Wire.requestFrom(axp_ADDRESS, 1);
uint8_t regValue = Wire.read();
Wire.endTransmission();
return regValue;
}
4.传感器数据的读取与计算
1)海拔计算
计算海拔高度通常需要使用标准大气压公式或经验公式。一个常用的方法是使用国际标准大气层(ISA)模型中的公式,该公式假定温度随高度线性变化并给出了一种近似的计算方法。以下是一个常用的经验公式,用于根据海平面气压和实际测量的气压计算海拔高度:
其中:
- h 是海拔高度(米)
- T0是海平面标准温度(K),通常为 288.15 K
- L 是对流层内的温度递减率(K/m),通常为 0.0065 K/m
- P 是测量的气压(Pa)
- P0 是海平面标准气压(Pa),通常为 101325 Pa
- R是通用气体常数,8.3144598 J/(mol·K)
- g是重力加速度,9.80665 m/s²
- M 是空气的摩尔质量,0.0289644 kg/mo
2)水深计算
要根据已知的压力计算海水的深度,可以使用类似的方法。假设海水的密度为常数(通常为1025 kg/m³,取决于温度和盐度),并且压力是绝对压力。
其中:
- d 是水深(米)
- P 是测量的绝对压力(帕斯卡,Pa)
- P0 是海平面上的大气压力(帕斯卡,Pa),通常为101325 Pa
- ρ 是海水的密度(公斤/立方米,kg/m³),通常为1025 kg/m³
- g 是重力加速度(米/秒²,m/s²),通常取9.80665 m/s²
3)代码
//更新数据
pressureSensor.getSensorData();
Pressure = pressureSensor.data.pressure.hpa;
//计算水深
float deph = ( (Pressure*100 - 101325) / (1025.0 * 9.8) );
//计算海拔
float height =get_altitude(Pressure , pressureSensor.data.heat.deg_c);
float get_altitude(float CurrentPressure,float CurrentTemperature)
{
return (float)(1.0-pow((CurrentPressure / 1013.25), (1.0 / 5.255)) ) * (CurrentTemperature + 273.15) / 0.0065;
}
四、效果