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; double pressure_val = 0; //气压数据 如果设置初始值为-1则不检测气压 传感器强制执行 int running_type = 0; //运行状态 0不运行 1篮球 2摩托车 3汽车 4自行车 5自定义 uint32_t running_time; 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 < 50; i++) { tmp = tmp + analogRead(pin_no); } avg = tmp / 50; ADCVoltage = ((avg * 3.3) / (4095)) + 0.138; 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; } 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; //运行气压自定义 ReturnString += ","; ReturnString += TimeString(millis() / 1000); //系统运行时间 Serial.println(ReturnString); return ReturnString; } 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(); //触摸感应处理 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[1] % 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(); if(adcValue!=-1){ pressure_val = adcValue/100000 * 0.0689476 - 0.23; } pressure_type[5] = (running_pressure_type + 0.23) * 100000 / 0.0689476; if (adcValue > 520000 ) { 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); } } } TenthSecondsSinceStartTask(); } unsigned long LastMillis = 0; void TenthSecondsSinceStartTask() //100ms { ESP32Server.handleClient(); delay(2); unsigned long CurrentMillis = millis(); if (abs(int(CurrentMillis - LastMillis)) > 100) { LastMillis = CurrentMillis; TenthSecondsSinceStart++; OnTenthSecond(); } yield(); } bool battery_low = 0; void OnSecond() { #if defined(INPUT_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(); } } 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; //Serial.println(pressure_val); 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);//将所有请求导向自己处理的代码 }