站内搜索
更多
智能UV固化灯(PCB阻焊绿油维修专用)最新版本支持OTA升级
专业版

智能UV固化灯(PCB阻焊绿油维修专用)最新版本支持OTA升级

简介

一款亮度可调,可定时,可手机控制,可用于多种场景的智能UV固化灯(ArduinoIDE开发)V2.0的PCB搭配V1.6的程序,后续可以直接OTA升级

简介:一款亮度可调,可定时,可手机控制,可用于多种场景的智能UV固化灯(ArduinoIDE开发)V2.0的PCB搭配V1.6的程序,后续可以直接OTA升级
星火计划2024

开源协议

GPL 3.0

(未经作者授权,禁止转载)
创建时间:2024-01-19 16:05:46更新时间:2026-07-14 10:18:24

描述

演示视频

https://www.bilibili.com/video/BV1VvupzcES5/?spm_id_from=333.1387.homepage.video_card.click&vd_source=29ae08546a1b93abd55b3aff4533217c

项目说明

本项目是基于上一代UV灯改进而来,同样是ArduinoIDE设计的,主要由软件+PCB+3D模型组成,功能如下:在UV灯顶部设计有3个按键和一个0.96寸OLED,左右按键主要用于“切换不同菜单”,中间键主要负责“确认和退出”,菜单主要有“亮度控制菜单;定时菜单;电量菜单,散热风扇菜单,手机控制菜单”组成。

项目相关功能

主要由亮度控制菜单;定时菜单;电量菜单,散热风扇菜单,手机控制菜单组成的一些功能:
亮度控制:通过IO口输出PWM信号来控制MOS管开关,从而实现亮度调节,当UV灯工作时氛围灯显示蓝色。
定时器菜单:主要用于一些特定场景的定时熄灭,小时,分钟,秒都是可以进行定时的,当然使用的是ESP8266内部的定时器,时间会有偏差,并不是特别准确(秒很准),比如当固化阻焊绿油,可以定时1分钟倒计时,(氛围灯显示绿色),时间到自动熄灭,外加蜂鸣器提醒,可以自由设置时间。
电量菜单:由于这个灯珠有15W所以是非常耗电的,我设置了一个低电量提醒功能,当电量小于(30%~5%区间可调),进行低电量报警,提醒用户充电。
散热风扇菜单:主要用于控制风扇转速,加快UV灯铝基板与电池的散热,同样采用PWM方式控制。
手机控制菜单:当进入该菜单,ESP8266会生成一个WIFI当手机连上WIFI,并通过手机浏览器输入IP地址,就可以实现单机控制UV灯。

设计原理

本次更新主要为了弥补一代的不足之处:
1:一代设计的是黑色外壳,同时由于内部螺母没有很多的处理,使用热熔螺母容易出现滑丝的情况,且受力不合理,二代改为预埋螺母连接更加牢靠。
2:一代是一个5向按键控制,占用IO口较多,导致无法增加蜂鸣器电路和风扇控制电路,二代,改为3个按键,且支持蜂鸣器与散热风扇独立控制。

image.png
image.png

** 3:对一代的充电电路做了更新,由原来的FM4256更换为IP2326(8V/1.5A)输出,充电更快。(最近充电宝爆炸的事情比较火,所以为了更保险一点,我还设计了热敏电阻)充电更安全。
**

image.png
image.png

** 4:一代设计的是黑色吸光,且外壳不适合嵌入亚克力,所以二代对氛围灯进行了增加,更加直观。
5:电池保护电路同样进行了改进,采用四颗MOS管两两并联,可保证电池电流大功率输出。**

image.png
image.png

软件说明

软件部分主要使用的库有

#include "U8g2lib.h    //OLED驱动库
#include     //ESP8266WIFI库
#include  //Web网页库
#include //WS2812氛围灯库

主要setup函数有:
通过一个for循环进行IO口的初始化,非常适合定义多个IO口场合

  for(int i=0; i<3; i++)
  pinMode(Key[i], INPUT_PULLUP); //输入上拉模式
  pinMode(LED, OUTPUT);
  digitalWrite(LED,LOW);
  analogWrite(LED, map(uv_brightness, 0, 100, 0, 1023));
  pinMode(Fan, OUTPUT);
  analogWrite(Fan, map(fan_speed, 0, 100, 0, 1023));
  pinMode(Buzzer, OUTPUT);
}

loop函数:电池电量监测-->判断WIFI是否连接-->按键是否被按下-->定时函数-->氛围灯函数-->蜂鸣器函数-->绘制显示界面-->刷新显示

void DianChi(){
  // 1. 读取电池电压
  voltage = readBatteryVoltage();
  percent = calculateBatteryPercent(voltage);
  
  // 2. 检查低电量
  static bool lowBatteryWarningShown = false;
  if (percent < LOW_BATTERY_PERCENT) {
    if (!lowBatteryWarningShown) {
      displayLowBatteryWarning();
      lowBatteryWarningShown = true;
      ledState = LED_PINK_BLINK;  // 设置LED为粉色闪烁
      triggerLowBatteryAlarm();   // 触发低电量蜂鸣报警
    }
  } else {
    lowBatteryWarningShown = false;

     // 检查充电状态(假设充电时电压高于8.6V)
    if (voltage > 8.6) {
      if (percent < 100) {
        ledState = LED_PURPLE_BREATH; // 充电中
      } else {
        ledState = LED_OFF; // 充电完成
        // 停止任何蜂鸣声
        buzzerState = BUZZER_OFF;
        noTone(Buzzer);
      }
    } else if (ledState == LED_PINK_BLINK) {
      ledState = LED_OFF; // 退出低电量状态
      buzzerState = BUZZER_OFF; // 关闭低电量报警
      noTone(Buzzer);
    }
  }
}

void handleButtons(){
  //防抖处理
  if(millis() - lastDebounceTime < debounceDelay) return;

  //选择按键
  if(digitalRead(Key[0]) == LOW && !button_select_clicked){
    button_select_clicked = 1;
    triggerKeyBeep(); // 按键提示音
    if(current_screen == ZHU_JIE_MIAN){
      //主菜单进入子菜单
      switch(menu_selection){
        case 0: current_screen = LIANG_DU; break;
        case 1: current_screen = DING_SHI; break;
        case 2: current_screen = DIAN_LIANG; break;
        case 3: current_screen = FENG_SHAN; break;
        case 4: current_screen = SHOU_JI_WIFI; 
                activateWifiAP();//激活WIFI热点
                break;
      }
    }else if(current_screen == DING_SHI){
      //定时器专用逻辑
      if(timerState == SETTING){
        startTimer();
      }else if(timerState == RUNNING || timerState == FINISHED){
        cancelTimer();
        current_screen = ZHU_JIE_MIAN;//返回主菜单
      }
    }else if(current_screen == SHOU_JI_WIFI){
      deactivateWifiAP();//关闭WIFI热点
      current_screen = ZHU_JIE_MIAN;
    }else{
      current_screen = ZHU_JIE_MIAN;
    }
    lastDebounceTime = millis();
    return;
  }

  //上按键
  if(digitalRead(Key[1]) == LOW){
    triggerKeyBeep(); // 按键提示音
    switch(current_screen){
      case ZHU_JIE_MIAN:
        menu_selection = (menu_selection - 1 + NUM_ITEMS) % NUM_ITEMS;
        break;

      case LIANG_DU:
        uv_brightness = min(100,uv_brightness + 5);
        analogWrite(LED, map(uv_brightness, 0, 100, 0, 255));
        break;

      case DING_SHI:
        if(timerState == SETTING){
          //循环选择时间单位
          if(selectedUnit == HOURS) selectedUnit = MINUTES;
          else if(selectedUnit == MINUTES) selectedUnit = SECONDS;
          else selectedUnit = HOURS; 
        }
        break;

      case FENG_SHAN:
        fan_speed = min(100, fan_speed + 5);
        analogWrite(Fan, map(fan_speed, 0, 100, 0, 255));
        break;
      case DIAN_LIANG:
        battery_warning = min(30, battery_warning + 1);
        break;
    }
    lastDebounceTime = millis();
    return;
  }

  //下按键
  if(digitalRead(Key[2]) == LOW){
    triggerKeyBeep(); // 按键提示音
    switch(current_screen){
      case ZHU_JIE_MIAN:
        menu_selection = (menu_selection + 1) % NUM_ITEMS;
        break;
      case LIANG_DU:
        uv_brightness = max(0, uv_brightness - 5);
        analogWrite(LED, map(uv_brightness, 0, 100, 0, 255));
        break;
      case DING_SHI:
        if(timerState == SETTING){
          //增加当前单位值
          if(selectedUnit == HOURS) setHours = (setHours + 1) % 24;
          else if(selectedUnit == MINUTES) setMinutes = (setMinutes + 1) % 60;
          else setSeconds = (setSeconds + 1) % 60;
        }
        break;
      case FENG_SHAN:
        fan_speed = max(0, fan_speed - 5);
        analogWrite(Fan, map(fan_speed, 0, 100, 0, 255));
        break;
      case DIAN_LIANG:
        battery_warning = max(5, battery_warning - 1);
        break;
    }
    lastDebounceTime = millis();
    return;
  }
  
  // 当UV灯手动开启时,设置蓝色呼吸灯
  if (uv_brightness > 0 && timerState != RUNNING) {
    ledState = LED_BLUE_BREATH;
  } else if (uv_brightness == 0 && ledState == LED_BLUE_BREATH) {
    ledState = LED_OFF;
  }

  //重置按钮状态
  if (digitalRead(Key[0]) == HIGH) button_select_clicked = 0;
 
}
void handleTimer() {
  if (timerState == RUNNING) {
    // 定时器运行时设置LED为绿色常亮
    ledState = LED_GREEN_SOLID;

    unsigned long elapsed = millis() - startMillis;
    
    if (elapsed >= remainingTime) {
      // 倒计时结束
      timerState = FINISHED;
      remainingTime = 0;
      // 关闭UV灯和风扇
      uv_brightness = 0;
      fan_speed = 0;
      // 关闭相关设备
      analogWrite(LED, map(uv_brightness, 0, 100, 0, 1023));
      analogWrite(Fan, map(fan_speed, 0, 100, 0, 1023));
      
      // 关闭LED
      ledState = LED_OFF;
      
      // 发出结束提示音
      triggerTimerEndBeep(); // 使用特殊结束音
    } else {
      // 更新剩余时间
      remainingTime -= elapsed;
      startMillis = millis();
    }
  }
  
  // 更新闪烁状态
  if (millis() - lastBlink > BLINK_INTERVAL) {
    blinkState_LED = !blinkState_LED;
    lastBlink = millis();
  }
}

void handleLEDs() {
  switch(ledState) {
    case LED_OFF:
      setAllLEDs(0, 0, 0); // 关闭所有LED
      break;
      
    case LED_BLUE_BREATH:
      updateBreathEffect(0, 0, 255); // 蓝色呼吸效果
      break;
      
    case LED_GREEN_SOLID:
      setAllLEDs(0, 255, 0); // 绿色常亮
      break;
      
    case LED_PINK_BLINK:
      updateBlinkEffect(255, 20, 147); // 粉色闪烁效果
      break;
      
    case LED_PURPLE_BREATH:
      updateBreathEffect(148, 0, 211); // 紫色呼吸效果
      break;
  }
}
void drawInterface() {
  u8g2.clearBuffer();
  updateDisplay(voltage, percent);//所有界面显示电池状态

  switch(current_screen) {
    case ZHU_JIE_MIAN:
      drawMainMenu();
      break;   
    case LIANG_DU:
      drawBrightnessMenu();
      break;
    case FENG_SHAN:
      drawFanMenu();
      break;
    case DIAN_LIANG:
      drawBatteryMenu();
      break;
    case DING_SHI:
      drawTimerMenu();
      break;
    case SHOU_JI_WIFI:
      draWifiMenu();
     break;
  }
}

安装说明

实物图

image.png

image.png

image.png

image.png






设计图

未生成预览图,请在编辑器重新保存一次

BOM

暂无BOM

3D模型

序号文件名称下载次数
暂无数据

附件

序号文件名称下载次数
暂无数据
克隆工程
添加到专辑
0
0
分享
侵权投诉
知识产权声明&复刻说明

本项目为开源硬件项目,其相关的知识产权归创作者所有。创作者在本平台上传该硬件项目仅供平台用户用于学习交流及研究,不包括任何商业性使用,请勿用于商业售卖或其他盈利性的用途;如您认为本项目涉嫌侵犯了您的相关权益,请点击上方“侵权投诉”按钮,我们将按照嘉立创《侵权投诉与申诉规则》进行处理。

请在进行项目复刻时自行验证电路的可行性,并自行辨别该项目是否对您适用。您对复刻项目的任何后果负责,无论何种情况,本平台将不对您在复刻项目时,遇到的任何因开源项目电路设计问题所导致的直接、间接等损害负责。

底部导航