airpump/esp32_air_pump/esp32_air_pump_main.h

598 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

void StartWebServer();
unsigned char RelayPin[LIGHT_NUMBER]; // = {RELAY1,RELAY2};
unsigned char TOUCHLED_PIN[LIGHT_NUMBER]; //触摸按键pin
unsigned char CONTROL_PIN[LIGHT_NUMBER]; //按键开关pin
unsigned char CONTROL_STAT[LIGHT_NUMBER]; //按键开关状态处理
const int threshold_top = 20; //触摸顶部阈值
const int threshold_bottom = 1; //触摸底部阈值,越接近数值越小
const int threshold_count = 4; //触摸计数器有效值,通常会有意外的自动触发
int touchread[4] = {100, 100, 100, 100}; //初始化触摸读取值为100无触摸
int touchDetected[4] = {}; //通过touchdetected持续计数判断是否按键防止无触碰触发
bool touch_touched[4] = {}; //单击判断,作为灯开关的判断
int touch_touched_times[4] = {}; //单击次数,单击切换模式,双击
int touch_touching_time[4] = {}; //持续触摸秒数,用于判断长按事件,长按关闭,长按开启,开启状态长按调光,
bool touch_STATE[4] = {0, 0, 0, 0}; // 定义按键触发对象状态变量初始值true开启
const double min_voltage = 6; //电池检测最低电压
double bat_voltage;
int running_type = 0; //运行状态 0不运行 1篮球 2摩托车 3汽车 4自行车 5自定义
uint32_t running_time;
double pressure_val = -1; //气压数据 如果设置初始值为-1则不检测气压 传感器强制执行
int pressure_type[6] = {600000, 1305485, 3762277, 3839579, 5691781, 1305485}; //气压类型 0不运行 1篮球 2摩托车 3汽车 4自行车
float running_pressure_type;
int ndrdy = SDA_PIN; //SDA
int clck = SCL_PIN; //SCL
unsigned long TenthSecondsSinceStart = 0;
void TenthSecondsSinceStartTask();
void OnTenthSecond();
void OnSecond();
WebServer ESP32Server(80);
double return_voltage_value(int pin_no)
{
double tmp = 0;
double ADCVoltage = 0;
double inputVoltage = 0;
double avg = 0;
for (int i = 0; i < 150; i++)
{
tmp = tmp + analogRead(pin_no);
}
avg = tmp / 150;
ADCVoltage = ((avg * 3.3) / (4095)) + 0.112;
inputVoltage = ADCVoltage / (R2_VOLTAGE / (R1_VOLTAGE + R2_VOLTAGE)); // formula for calculating voltage in i.e. GND
return inputVoltage;
}
//触摸感应处理
void touchAttach(int touchID, uint8_t touchPin) {
touchread[touchID] = touchRead(touchPin);
if ( touchread[touchID] <= threshold_top && touchread[touchID] > threshold_bottom ) { //达到触发值的计数
delay(38); // 0.038秒
touchDetected[touchID]++; //持续触摸计数
if ( (touchDetected[touchID] >= threshold_count) && digitalRead(TOUCHLED_PIN[touchID]) == HIGH ) { //达到触发值的,灯不亮则亮灯
//digitalWrite(TOUCHLED_PIN[touchID], LOW);
}
} else if (touchread[touchID] > threshold_top) { //无触摸处理
if ( digitalRead(TOUCHLED_PIN[touchID]) == LOW ) { //灭触摸灯
//digitalWrite(TOUCHLED_PIN[touchID], HIGH);
}
if ( touchDetected[touchID] >= threshold_count ) { //检测无触摸之前的有效计数,触摸过则标记
touch_touched[touchID] = true;
touch_touched_times[touchID]++; //触摸计数+1
}
touch_touching_time[touchID] = 0; //持续触摸时间清零
touchDetected[touchID] = 0; //持续触摸计数清零
}
}
//按键开关的防抖处理判断
void controlAttach(int touchID, int touch_type = 0) { // 0 常开或常闭开关 1 轻触开关
//按键开关,根据是否跟上一次状态相同作出判断,如果当前相同则不动作
if ( CONTROL_STAT[touchID] == !digitalRead(CONTROL_PIN[touchID])) {
int val1 = digitalRead(CONTROL_PIN[touchID]);
delay(38); // 0.038秒
int val11 = digitalRead(CONTROL_PIN[touchID]);
if (val11 != val1) {
delay(15);
val11 = digitalRead(CONTROL_PIN[touchID]);
}
delay(168); // 故意不要连续读取
if (val1 == val11) { // 确定不是抖动
if ( CONTROL_STAT[touchID] == !digitalRead(CONTROL_PIN[touchID])) {
touch_touched[touchID] = true;
touch_touched_times[touchID]++;
if (touch_type == 0) //常开或常闭开关更新状态,轻触开关则不更新
CONTROL_STAT[touchID] = digitalRead(CONTROL_PIN[touchID]);
}
}
}
}
long readADC()
{
if (digitalRead(ndrdy))
return -1;
long result = 0;
for (int i = 0; i < 24; i++)
{
digitalWrite(clck, HIGH);
delayMicroseconds(1);
int new_bit = digitalRead(ndrdy);
digitalWrite(clck, LOW);
delayMicroseconds(1);
result <<= 1;
result |= new_bit;
}
for (int i = 0; i < 3; i++)
{
digitalWrite(clck, HIGH);
delayMicroseconds(1);
digitalWrite(clck, LOW);
delayMicroseconds(1);
}
return result;
}
void setup()
{
delay(50);
Serial.begin(115200);
Serial.println("");
while (!Serial) {}
if (pressure_val != -1) {
pinMode(ndrdy, INPUT);
digitalWrite(ndrdy, LOW);
pinMode(clck, OUTPUT);
digitalWrite(clck, LOW);
while (digitalRead(ndrdy)) {}
while (!digitalRead(ndrdy)) {}
}
CONTROL_PIN[0] = CONTROL_1_PIN; //按键
CONTROL_PIN[1] = CONTROL_2_PIN;
CONTROL_PIN[2] = CONTROL_3_PIN;
TOUCHLED_PIN[0] = TOUCHLED_1_PIN; //指示灯
TOUCHLED_PIN[1] = TOUCHLED_2_PIN;
TOUCHLED_PIN[2] = TOUCHLED_3_PIN;
for (byte i = 0; i < LIGHT_NUMBER; i++)
{
//机械开关 接地 低电平触发
pinMode(CONTROL_PIN[i], INPUT_PULLUP); //设置按键管脚上拉输入模式
pinMode(TOUCHLED_PIN[i], OUTPUT);
digitalWrite(TOUCHLED_PIN[i], HIGH); //低电平有效
CONTROL_STAT[i] = digitalRead(CONTROL_PIN[i]); //开关所在状态读取,当前可能为高或者低
}
RelayPin[0] = LIGHT_1_PIN;
RelayPin[1] = LIGHT_2_PIN;
RelayPin[2] = LIGHT_3_PIN;
for (byte i = 0; i < LIGHT_NUMBER; i++)
{
pinMode(RelayPin[i], OUTPUT);
digitalWrite(RelayPin[i], HIGH); //低电平有效
}
uint32_t chipId = 0;
for (int i = 0; i < 17; i = i + 8) {
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
Serial.printf("Chip ID: %d\r\n", chipId);
Serial.printf("ESP32 Chip ID = %04X", (uint16_t)(ESP.getEfuseMac() >> 32)); //print High 2 bytes
Serial.printf("%08X\r\n", (uint32_t)ESP.getEfuseMac()); //print Low 4bytes.
Serial.printf("Chip model = %s Rev %d\r\n", ESP.getChipModel(), ESP.getChipRevision());
Serial.printf("This chip has %d cores CpuFreqMHz = %u\r\n", ESP.getChipCores(), ESP.getCpuFreqMHz());
Serial.printf("get Cycle Count = %u\r\n", ESP.getCycleCount());
Serial.printf("SDK version:%s\r\n", ESP.getSdkVersion()); //获取IDF版本
//获取片内内存 Internal RAM
Serial.printf("Total heap size = %u\t", ESP.getHeapSize());
Serial.printf("Available heap = %u\r\n", ESP.getFreeHeap());
Serial.printf("Lowest level of free heap since boot = %u\r\n", ESP.getMinFreeHeap());
Serial.printf("Largest block of heap that can be allocated at once = %u\r\n", ESP.getMaxAllocHeap());
//SPI RAM
Serial.printf("Total Psram size = %u\t", ESP.getPsramSize());
Serial.printf("Available Psram = %u\r\n", ESP.getFreePsram());
Serial.printf("Lowest level of free Psram since boot = %u\r\n", ESP.getMinFreePsram());
Serial.printf("Largest block of Psram that can be allocated at once = %u\r\n", ESP.getMinFreePsram());
sprintf(mac_tmp, "%02X\r\n", (uint32_t)(ESP.getEfuseMac() >> (24) ));
sprintf(mac_tmp, "ESP32-%c%c%c%c%c%c", mac_tmp[4], mac_tmp[5], mac_tmp[2], mac_tmp[3], mac_tmp[0], mac_tmp[1] );
//wifi初始化
WiFi.mode(WIFI_AP);
while (!WiFi.softAP(ssid, password)) {}; //启动AP
Serial.println("AP启动成功");
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());
byte mac[6];
WiFi.macAddress(mac);
WiFi.setHostname(ServerName);
Serial.printf("macAddress 0x%02X:0x%02X:0x%02X:0x%02X:0x%02X:0x%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
//以下是启动OTA可以通过WiFi刷新固件
ArduinoOTA.setHostname(ServerName);
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
Serial.println("ATO Ready");
Serial.println("");
// 启动闪存文件系统
if (SPIFFS.begin())
{
Serial.println("SPIFFS Started.");
}
else
{
Serial.println("SPIFFS Failed to Start.");
}
StartWebServer();
Serial.println("System ready");
Serial.println("-----------------------------------------------");
}
void loop()
{
ArduinoOTA.handle();
ESP32Server.handleClient();
delay(2);
TenthSecondsSinceStartTask();
//触摸感应处理
touchAttach(0, T4);
touchAttach(1, T3);
touchAttach(2, T2);
for (byte i = 0; i < LIGHT_NUMBER; i++)
{
controlAttach(i, 1); //按键开关处理
if (touch_touched[i]) {
Serial.print(i);
Serial.print(" control touched\t");
running_type = touch_touched_times[i] % 6;
Serial.println(running_type);
switch (i) {
case 0: //启停控制
if ( running_type > 0 && !touch_STATE[i]) { //有类型选择且未运行
touch_STATE[i] = 1; //启动状态修改
digitalWrite(RelayPin[i], LOW);
running_time = millis();
Serial.println(" Start Running ");
} else {
touch_STATE[i] = 0;
digitalWrite(RelayPin[i], HIGH);
Serial.println(" Sop Running ");
}
break;
case 1: //灯控制
switch (running_type) {
case 0: // 全暗不启动
digitalWrite(TOUCHLED_PIN[2], HIGH);
digitalWrite(TOUCHLED_PIN[1], HIGH);
digitalWrite(TOUCHLED_PIN[0], HIGH);
break;
case 1: //篮球 0.6bar
digitalWrite(TOUCHLED_PIN[2], LOW);
digitalWrite(TOUCHLED_PIN[1], HIGH);
digitalWrite(TOUCHLED_PIN[0], HIGH);
break;
case 2: //汽车2.5
digitalWrite(TOUCHLED_PIN[2], HIGH);
digitalWrite(TOUCHLED_PIN[1], LOW);
digitalWrite(TOUCHLED_PIN[0], HIGH);
break;
case 3: //摩托车
digitalWrite(TOUCHLED_PIN[2], LOW);
digitalWrite(TOUCHLED_PIN[1], LOW);
digitalWrite(TOUCHLED_PIN[0], HIGH);
break;
case 4: //自行车
digitalWrite(TOUCHLED_PIN[2], HIGH);
digitalWrite(TOUCHLED_PIN[1], HIGH);
digitalWrite(TOUCHLED_PIN[0], LOW);
break;
case 5: //自定义
digitalWrite(TOUCHLED_PIN[2], LOW);
digitalWrite(TOUCHLED_PIN[1], LOW);
digitalWrite(TOUCHLED_PIN[0], LOW);
break;
}
break;
case 2:
break;
}
touch_touched[i] = false;
}
}
if ( pressure_val != -1) { //传感器正常
long adcValue = readADC();
pressure_val = adcValue / 100000 * 0.0689476;
pressure_type[5] = running_pressure_type*100000 / 0.0689476;
if (adcValue > 600000 ) {
Serial.print("ADC reading: ");
Serial.print(adcValue);
Serial.print("\t");
Serial.print(pressure_val);
Serial.print("bar\t");
Serial.println(pressure_type[5]);
}
if (touch_STATE[0]) { //启动 充气执行超过3分钟自动停止
if (adcValue >= pressure_type[running_type] || ((millis() - running_time) / 1000) > 180 ) //气压达到设定值则停机
{
touch_STATE[0] = 0;
delay(500);
digitalWrite(RelayPin[0], HIGH);
Serial.println(" End of Run ");
delay(500);
}
}
} else { //无传感器强制启动设定时间1分钟停机
if (touch_STATE[0]) {
if ( ((millis() - running_time) / 1000) > 60 ){
touch_STATE[0] = 0;
delay(500);
digitalWrite(RelayPin[0], HIGH);
Serial.println(" End of Run ");
delay(500);
}
}
}
}
unsigned long LastMillis = 0;
void TenthSecondsSinceStartTask() //100ms
{
unsigned long CurrentMillis = millis();
if (abs(int(CurrentMillis - LastMillis)) > 100)
{
LastMillis = CurrentMillis;
TenthSecondsSinceStart++;
OnTenthSecond();
}
}
bool battery_low = 0;
void OnSecond()
{
#if defined(BAT_VOLTAGE_SENSE_PIN) //电池电压检测
bat_voltage = return_voltage_value(INPUT_VOLTAGE_SENSE_PIN);
if (bat_voltage < min_voltage && !battery_low) {
battery_low = 1;
digitalWrite(RelayPin[0], HIGH); //关闭电机
while (battery_low) { //电池电压低闪灯
if (millis() % 500 < 250) {
digitalWrite(TOUCHLED_PIN[2], HIGH);
digitalWrite(TOUCHLED_PIN[1], HIGH);
digitalWrite(TOUCHLED_PIN[0], HIGH);
} else {
digitalWrite(TOUCHLED_PIN[2], LOW);
digitalWrite(TOUCHLED_PIN[1], LOW);
digitalWrite(TOUCHLED_PIN[0], LOW);
}
}
}
#endif
}
void OnTenthSecond() // 100ms 十分之一秒
{
if (TenthSecondsSinceStart % 10 == 0) //10次为1秒
{
OnSecond();
}
}
String TimeString(int TimeMillis) {
String stringTime;
stringTime += int(TimeMillis / 60 / 60);
stringTime += ":";
stringTime += int(TimeMillis / 60 % 60);
stringTime += ":";
stringTime += TimeMillis % 60;
return stringTime;
}
String ProcessUpdate() //页面更新
{
//自动生成一串用“,”隔开的字符串。
//HTML脚本会按照“, ”分割,形成一个字符串数组。
//并把这个数组填个表格的相应部分。
String ReturnString;
if (touch_STATE[0]) {
ReturnString += TimeString((millis() - running_time) / 1000);
} else {
ReturnString += "0";
}
ReturnString += ",";
ReturnString += bat_voltage; //电压值
ReturnString += ",";
ReturnString += pressure_val; //气压值
ReturnString += ",";
ReturnString += touch_STATE[0]; //运行状态
ReturnString += ",";
ReturnString += running_type; //运行方式
ReturnString += ",";
ReturnString += running_pressure_type; //运行气压自定义
//Serial.println(ReturnString);
return ReturnString;
}
void PocessControl(int DeviceType, int DeviceIndex, int Operation, float Operation2)
{
String ReturnString;
if (DeviceType == 0)
{
int SysIndex = Operation / 3;
if (Operation % 3 == 0)
{ //重新设置传感器
pressure_val =0;
pinMode(ndrdy, INPUT);
digitalWrite(ndrdy, LOW);
pinMode(clck, OUTPUT);
digitalWrite(clck, LOW);
while (digitalRead(ndrdy)) {}
while (!digitalRead(ndrdy)) {}
}
else if (Operation % 3 == 1)
{
}
else if (Operation % 3 == 2)
{
ReturnString += "系统重启,请等待重新连接";
printf("Reboot...");
esp_restart();
}
}
if (DeviceType == 1) //启停
{
if (Operation == 0)
{
running_pressure_type = Operation2;
touch_touched[0] = 1; //启停按过
touch_touched_times[0] = DeviceIndex;
touch_touched[1] = 1;
touch_touched_times[1] = DeviceIndex;
}
}
if (DeviceType == 2) //类型选择
{
running_pressure_type = Operation2;
touch_touched[1] = 1;
touch_touched_times[1] = DeviceIndex;
}
}
bool handleFileRead(String path) { //处理主页访问
String contentType = "text/html";
if (SPIFFS.exists(path)) { // 如果访问的文件可以在SPIFFS中找到
File file = SPIFFS.open(path, "r"); // 则尝试打开该文件
ESP32Server.streamFile(file, contentType); // 并且将该文件返回给浏览器
file.close(); // 并且关闭文件
return true; // 返回true
}
return false; // 如果文件未找到则返回false
}
void handleNotFound()
{
// 获取用户请求网址信息
String webAddress = ESP32Server.uri();
int AutheTimes = 0;
if (!ESP32Server.authenticate(username, userpassword)) //校验用户是否登录
{
if (AutheTimes == 3) {
ESP32Server.send(404, "text/plain", "Bye");
} else {
AutheTimes++;
return ESP32Server.requestAuthentication(); //请求进行用户登录认证
}
}
//打印出请求
if (webAddress != "/update")
{
printf("%s\n", webAddress.c_str());
}
//如果是主页请求则发送FLASH中的index.html文件
if (webAddress.endsWith("/")) { // 如果访问地址以"/"为结尾
webAddress = "/index.html"; // 则将访问地址修改为/index.html便于SPIFFS访问
// 通过handleFileRead函数处处理用户访问
handleFileRead(webAddress);
}
else if (webAddress.endsWith("update"))
{
ESP32Server.send(200, "text/plain", ProcessUpdate());
}
else if (webAddress.startsWith("/Control"))
{
if (ESP32Server.args() == 3)
{
int DeviceType = ESP32Server.arg(0).toInt();
int DeviceIndex = ESP32Server.arg(1).toInt();
int Operation = ESP32Server.arg(2).toInt();
float Operation2 = ESP32Server.arg(2).toFloat();
if (DeviceType == 1) {
Operation = 0;
}
printf("DeviceType:%d DeviceIndex:%d Operation:%d Operation2:%.2f\n", DeviceType, DeviceIndex, Operation, Operation2 );
PocessControl(DeviceType, DeviceIndex, Operation, Operation2);
}
else
{
ESP32Server.send(404, "text/plain", "404 Not Found");
}
}
else
{
ESP32Server.send(404, "text/plain", "404 Not Found");
}
}
void StartWebServer()
{
ESP32Server.begin();
ESP32Server.onNotFound(handleNotFound);//将所有请求导向自己处理的代码
}