УФ сушка лака для ногтей

karl2233
Offline
Зарегистрирован: 05.07.2015

в общем, решил я своей мамзели сворганииь таке.

корпус будет из пластиковой коробки(полно подходящих в посудных лавках), светодиоды нашел в Китае(тут важно подобрать их не только по мощности, но и по длине волны - разный гель требует своей).

разработал ТЗ:

1. нужен таймер с дискретностью 5 сек и выдержкой до 10 мин.

2. регулировка яркости свечения УФ диодов.

3. отключаемый(переодически включаемый) маленький вентилятор, теплый воздух от диодов гнать на ногти, с регулировкий скорости.

4. индикация на двух 3-х сегментниках - один время, второй шим диодов и вентилятора.

5. управление - энкодер или три кнопки(мамзель блондинка, боюсь больше не осилит).

и тут я плотно завис - пока разобрался с управлением семисегментниками и нашел скетч таймера совершенно не понимаю как до кучи всё это собрать.

по сему вопрос - если есть нароботки по данной(или смежной) теме - делитесь, плз :)

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Люди наоборот из ламп для ногтей что-то делают...
http://m.instructables.com/id/Printed-Circuit-Board-Production-using-UV-...

karl2233
Offline
Зарегистрирован: 05.07.2015

ну... такие темы видел. каждому своё(с)

управление светодиодами и вентилятором - по типу как в соседних ветках паяльные станции.

вот, в сети нашел код таймера(правда он на два сегмента с несколько странной индикацией)

#include <EEPROM.h>

void setup() {
  ind_setup();
  kbd_setup();
  out_setup();
  config_setup();
}

void loop() {
  ind_refresh();
  ind_update();
  kbd_update();
  timer_update();
  out_update();
  config_update();
  beep_update();
  delay(10);
}

//Config///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct {
  unsigned long time;
  byte crc;
} config;
#define CONFIG_WRITE_DELAY 500
unsigned int config_timer;
void config_setup() {
  config_read();
  if (config.time > (3600 * 99)) config.time = 1;
}
void config_update() {
  if (config_timer > 0) {
    config_timer--;
    if (config_timer == 0) {
      config_write();
    }
  }
}
void config_read() {
  byte *b = (byte *)&config;
  for (byte i=0; i<sizeof(config); i++)
    *b++ = EEPROM.read(i);
}
void config_write() {
  byte *b = (byte *)&config;
  for (byte i=0; i<sizeof(config); i++)
    EEPROM.write(i, *b++);
}
void config_write_reset() {
  config_timer = CONFIG_WRITE_DELAY;
}

//Timing///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
enum {SEC,MINSEC,MIN,HR}; //time mode
const unsigned int timer_inc[] = {1,10,60,3600};
const unsigned long timer_mode_min[] = {0,60,10*60,60*60};
unsigned long timer = 0;
byte timer_div = 0;
//check if timer is loaded and counting
byte timer_counting() {
  return (timer > 0);
}
//get timer mode (0-seconds, 1-min.sec, 2-min, 3-hr)
byte timer_mode(unsigned long t) {
  if (t < 60) return SEC;
  else if (t < 10 * 60) return MINSEC;
  else if (t < 60 * 60) return MIN;
  else return HR;
}
//get 2-digit value for timer
byte timer_to_byte(unsigned long t) {
  switch (timer_mode(t)) {
    case SEC: return t;
    case MINSEC: return ((t / 60) * 10) + ((t % 60) / 10);
    case MIN: return (t / 60);
    case HR: return (t / 3600);
   }
}
//update timer
void timer_update() {
  if (timer_counting()) {
    if (++timer_div >= 100) {
      timer_div = 0;
      timer--;
      if (timer == 0) {
        //play stop sound
        beep_timer_end();
      } else {
        if (timer <= 10) beep_timer_ending();
      }
    }
  }
}
//set and start timer
void timer_start(unsigned long t) {
  timer = t;
  timer_div = 0;
}

//Indication///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
enum {SEGA=1,SEGB=2,SEGC=4,SEGD=8,SEGE=16,SEGF=32,SEGG=64,SEGH=128}; //segments masks
enum {SEGApin=2,SEGHpin=9}; //segments pins
//HEX 7-seg digits
const byte ind_digits[]={
  SEGA | SEGB | SEGC | SEGD | SEGE | SEGF, //0
  SEGB | SEGC, //1
  SEGA | SEGB | SEGD | SEGE | SEGG, //2
  SEGA | SEGB | SEGC | SEGD | SEGG, //3
  SEGB | SEGC | SEGF | SEGG, //4
  SEGA | SEGC | SEGD | SEGF | SEGG, //5
  SEGA | SEGC | SEGD | SEGE | SEGF | SEGG, //6
  SEGA | SEGB | SEGC, //7
  SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG, //8
  SEGA | SEGB | SEGC | SEGD | SEGF | SEGG, //9
  SEGA | SEGB | SEGC | SEGE | SEGF | SEGG, //A
  SEGC | SEGD | SEGE | SEGF | SEGG, //b
  SEGA | SEGD | SEGE | SEGF, //C
  SEGB | SEGC | SEGD | SEGE | SEGG, //d
  SEGA | SEGD | SEGE | SEGF | SEGG, //E
  SEGA | SEGE | SEGF | SEGG, //F
};
const byte ind_com[] = {10,A1}; //common anode pins
//number of digits
#define IND_SIZE 2
byte ind_buf[IND_SIZE]; //indication buffer
byte ind_cnt; //current digit counter
//setup indication
void ind_setup() {
  //segment pins
  for (byte pin=SEGApin; pin<=SEGHpin; pin++) {
    pinMode(pin, OUTPUT);
    digitalWrite(pin, HIGH);
  }
  //common anodes pins
  for (byte pin=0; pin<IND_SIZE; pin++) {
    pinMode(ind_com[pin], OUTPUT);
    digitalWrite(ind_com[pin], HIGH);
  }
  //clear buffer
  for (byte i=0; i<IND_SIZE; i++) ind_buf[i] = 0;
}
byte ind_digit(byte digit) {
  return ind_digits[digit];
}
//set segments
void ind_set_segs(byte digit) {
  byte mask = 1;
  for (byte pin=SEGApin; pin<=SEGHpin; pin++) {
    digitalWrite(pin, !(digit & mask));
    mask <<= 1;
  }
}
//select digit (0xFF to deselect all)
void ind_set_com(byte num) {
  if (num == 0xFF) { //all OFF
    for (byte com=0; com<IND_SIZE; com++) digitalWrite(ind_com[com], HIGH);
  } else {
    digitalWrite(ind_com[num], LOW);
  }
}
//convert lower half-byte to 7-segment HEX
byte to_hex(byte data) {
  return ind_digit(data & 0xF);
}
//convert decimal 0..99 to BCD 0..0x99
byte to_bcd(byte data) {
  byte result = data % 10;
  data /= 10;
  result += (data % 10) << 4;
  return result;
}
//write 8-bit HEX to indication buffer
void ind_wr_H8(byte data, byte pos) {
  ind_buf[pos] = to_hex(data >> 4);
  ind_buf[pos + 1] = to_hex(data);
}
//refresh indication
void ind_refresh() {
  ind_set_com(0xFF);
  if (++ind_cnt >= IND_SIZE) ind_cnt = 0;
  ind_set_segs(ind_buf[ind_cnt]);
  ind_set_com(ind_cnt);
}
void ind_update() {
  unsigned long t = (!timer_counting()) ? config.time : timer;
  ind_wr_H8(to_bcd(timer_to_byte(t)), 0);
  if (ind_buf[0] == ind_digits[0]) ind_buf[0] = 0;
  if (timer_div < 50) {
    switch (timer_mode(t)) {
      case SEC: break;
      case MINSEC: ind_buf[0] |= SEGH; break;
      case MIN: ind_buf[1] |= SEGH; break;
      case HR: ind_buf[0] |= SEGH; ind_buf[1] |= SEGH; break;
    }
  }
}

//Keyboard/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
byte kbd_buf[2]; //current/previous keyboard states
byte kbd_cnt; //keypress counter
enum {KBD_UP=1, KBD_DOWN=2, KBD_SET=3}; //key codes
enum {KBD_CNT_SHORT=5, KBD_CNT_LONG=100, KBD_CNT_START=250, KBD_REPEAT=10}; //key press counter values
#define KBD_CNT_REPEAT (KBD_CNT_LONG - KBD_REPEAT)
void kbd_setup() {
  pinMode(12, INPUT_PULLUP);
  digitalWrite(12, HIGH);
  pinMode(13, INPUT_PULLUP);
  digitalWrite(13, HIGH);
}
byte kbd_read() {
  return (!digitalRead(12) << 1) | !digitalRead(13);
}
byte kbd_press(byte code, byte cnt) {
    return (kbd_buf[1] == code) && (kbd_cnt == cnt);
}
byte kbd_press2(byte code, byte cnt1, byte cnt2) {
    return (kbd_buf[1] == code) && ((kbd_cnt == cnt1) || (kbd_cnt == cnt2));
}
void kbd_update(void) {
  kbd_buf[0] = kbd_read();
  if (kbd_buf[1] != kbd_buf[0]) {
    kbd_cnt = 0;
    kbd_buf[1] = kbd_buf[0];
  } else {
    if (kbd_cnt < 255) kbd_cnt++;
    if (!timer_counting()) {
      if (kbd_press2(KBD_UP, KBD_CNT_SHORT, KBD_CNT_LONG)) {
        if (kbd_cnt == KBD_CNT_LONG) kbd_cnt = KBD_CNT_REPEAT;
        else beep_key_press();
        config.time += timer_inc[timer_mode(config.time)];
        if (config.time > (3600UL * 99)) config.time = (3600UL * 99);
        config_write_reset();
        beep_stop();
      }
      else if (kbd_press2(KBD_DOWN, KBD_CNT_SHORT, KBD_CNT_LONG)) {
        if (kbd_cnt == KBD_CNT_LONG) kbd_cnt = KBD_CNT_REPEAT;
        else beep_key_press();
        if (config.time > 1) {
          byte m = timer_mode(config.time);
          if ((m > 0)&&(config.time == timer_mode_min[m])) m--;
          config.time -= timer_inc[m];
          config_write_reset();
        }
        beep_stop();
      }
      //start timer
      else if (kbd_press(KBD_SET, KBD_CNT_SHORT)) {
        timer_start(config.time);
        beep_stop();
        beep_timer_start();
      }
    } else {
      //stop timer
      if (kbd_press(KBD_SET, KBD_CNT_SHORT)) {
        timer = 0;
        beep_timer_stop();
      }
    }
  }
}

//Out/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define OUT_PIN A0
void out_setup() {
  pinMode(OUT_PIN, OUTPUT);
  digitalWrite(OUT_PIN, LOW);
}
void out_update() {
  if (timer_counting()) digitalWrite(OUT_PIN, HIGH);
  else digitalWrite(OUT_PIN, LOW);
}

//Beeper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define BEEP_FREQ 2500
unsigned int beep_cnt;
void beep(byte len) {
  if (len == 0) noTone(11);
  else if (len == 1) tone(11, BEEP_FREQ);
  else tone(11, BEEP_FREQ, len);
}
void beep_stop() {
  beep_cnt = 0;
  beep(0);
}
void beep_update() {
  if (beep_cnt > 0) {
    beep_cnt--;
    if (beep_cnt == 0) beep(0);
    else {
//      beep((beep_cnt & 0x20) && (beep_cnt & 0x4) && (beep_cnt & 0x02));
      beep((beep_cnt & 0x40) && (beep_cnt & 0x08));
    }
  }
}
void beep_timer_end() {
  beep_cnt = 1000;
}
void beep_timer_start() {
  beep(100);
}
void beep_timer_stop() {
  beep(100);
}
void beep_timer_ending() {
  beep(50);
}
void beep_key_press() {
  beep(30);
}

 

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

У моей на лампе одна кнопка включает, вторая устанавливает таймер отключения 2мин, правда лампа заводская.

Вы планируете столько опций, а нужны ли они все?

ИМХО

karl2233
Offline
Зарегистрирован: 05.07.2015

вот такую лампу я и хочу переделать(это один вариант). ну или с "0" сделать на светодиодах.

тут основное это таймер с гибкой настройкой - что б руки не пожечь и что б разные лаки(точнее гели) гарантировано сохли.

индикация времени и мощности излучения диодов - тож вроде нужно, циферки запомнить проще(какой лак да при какой мощности и времени).

вентилятор - тот да, можно включать кнопочкой а ШИМ на 555 таймере заорганизовать.

вроде особо лишнего нет.

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

если уже ставите контроллер тогда таймер не555 не нужен ардуино легко два шима потянет один на диоды второй на вентилятор.
Семисигментники гемор еще тот(((

karl2233
Offline
Зарегистрирован: 05.07.2015

да, геморр тот, но у меня есть трёхразрядный индикатор и он места меньше LCD занимает.

ну и в первом приближении понятно как работает =)

кароч, прикинул что к чему:

- будет таймер с выдержкой 9 мин 59 сек;

- два ШИМ (один на вентилятор, второй на светики);

- три кнопки управления (select, uр, down);

есть вопросы, если кто сталкиваолся подскажите плз:

1. вот, нарыл скетч таймера (он для четырёх разрядного и без сдвигового регистра). вопрос в том, что пока не стал указывать сегмент "F" с двумя буквами, вылетало с ошибкой "незадекларировано".

почему так?

/*
Arduino 4 digits 7 segments LED countdown timer with buzzerm from
electronicsblog.net. If You share/use this code elsewhere on the internet
please meantion this code source.
*/

// segment | Arduino board PIN number 
#define A 2
#define B 3
#define C 4
#define D 5
#define E 6
#define FF 7
#define G 8
#define DP 9
// Commonn cathodes control
#define GND1 10
#define GND2 11
#define GND3 12
#define GND4 13
// buttons
/*
Button_start - start/pause timer and in setup mode inreases minutes
and seconds values
Button_set - if timer is paused it resets timer to start. Long press
activates setup mode in which button is for going through minutes, seconds setup
and leaving setup mode.
*/
#define Button_start A1
#define Button_set A2
#define Buzzer A3
#define LED A0 // or relay insted
int i=0; 
char run=0; // shows if timer is runnig
int b=0;  //for buttons
int c=0;
int d=0; // for buzzer
char set_mode=0; // shows if timer is in setup mode
char alarm =0;  // if "1" buzzer is on

//timer variables
// user setted and "turn on" values
int default_Sec=59;
int default_Min=99;

// current values
int Sec;
int Min;
//timer interrupt
ISR(TIMER1_OVF_vect) {
Sec--; // timer values decreases
TCNT1=0x0BDC;  
}

// functions to display digits
void digit0 () {
digitalWrite(A, HIGH);
digitalWrite(B, HIGH);
digitalWrite(C, HIGH);
digitalWrite(D, HIGH);
digitalWrite(E, HIGH);
digitalWrite(FF, HIGH);
digitalWrite(G, LOW);
};
void digit1 () {
digitalWrite(A,LOW);
digitalWrite(B, HIGH);
digitalWrite(C, HIGH);
digitalWrite(D, LOW);
digitalWrite(E, LOW);
digitalWrite(FF, LOW);
digitalWrite(G, LOW);
};
void digit2 () {
digitalWrite(A,HIGH);
digitalWrite(B, HIGH);
digitalWrite(C, LOW);
digitalWrite(D, HIGH);
digitalWrite(E, HIGH);
digitalWrite(FF, LOW);
digitalWrite(G, HIGH);
};
void digit3 () {
digitalWrite(A,HIGH);
digitalWrite(B, HIGH);
digitalWrite(C, HIGH);
digitalWrite(D, HIGH);
digitalWrite(E, LOW);
digitalWrite(FF, LOW);
digitalWrite(G, HIGH);
};
void digit4 () {
digitalWrite(A,LOW);
digitalWrite(B, HIGH);
digitalWrite(C, HIGH);
digitalWrite(D, LOW);
digitalWrite(E, LOW);
digitalWrite(FF, HIGH);
digitalWrite(G, HIGH);
};
void digit5 () {
digitalWrite(A,HIGH);
digitalWrite(B, LOW);
digitalWrite(C, HIGH);
digitalWrite(D, HIGH);
digitalWrite(E, LOW); 
digitalWrite(FF, HIGH);
digitalWrite(G, HIGH);
};
void digit6 () {
digitalWrite(A,HIGH);
digitalWrite(B, LOW);
digitalWrite(C, HIGH);
digitalWrite(D, HIGH);
digitalWrite(E, HIGH); 
digitalWrite(FF, HIGH);
digitalWrite(G, HIGH);
};
void digit7 () {
digitalWrite(A,HIGH);
digitalWrite(B, HIGH);
digitalWrite(C, HIGH);
digitalWrite(D, LOW);
digitalWrite(E, LOW); 
digitalWrite(FF, LOW);
digitalWrite(G, LOW);
};
void digit8 () {
digitalWrite(A, HIGH);
digitalWrite(B, HIGH);
digitalWrite(C, HIGH);
digitalWrite(D, HIGH);
digitalWrite(E, HIGH);
digitalWrite(FF, HIGH);
digitalWrite(G, HIGH);
};
void digit9 () {
digitalWrite(A, HIGH);
digitalWrite(B, HIGH);
digitalWrite(C, HIGH);
digitalWrite(D, HIGH);
digitalWrite(E, LOW);
digitalWrite(FF, HIGH);
digitalWrite(G, HIGH);
};


//function to display digit from inputed int

void showdigit (int digit)

{
  
 switch (digit) {
 
 case 0:
 digit0 ();
 break;
 
 case 1:
 digit1 ();
 break;
 
 case 2:
 digit2 ();
 break;
 
 case 3:
 digit3 ();
 break;
 
 case 4:
 digit4 ();
 break;
 
 case 5:
 digit5 ();
 break;
 
 case 6:
 digit6 ();
 break;
 
 case 7:
 digit7 ();
 break;
 
 case 8:
 digit8 ();
 break;
 
 case 9:
 digit9 ();
 break;
 
 default:

 
 
 break;
 
 
 
 }; 

};


// showing 4 digits
//  not only shows 4 digit number, but also there is option to turn on
//only selected digits and decimal point.

void showdigits (int number, char digit_on, char  decimal_point) 
{
digitalWrite(GND4, LOW);
  // e.g. we have "1234"
  showdigit(number/1000);  // segments are set to display "1"
  if (decimal_point&8) {digitalWrite(DP, HIGH);} else {digitalWrite(DP, LOW);};
  if (digit_on&8) {
digitalWrite(GND1, HIGH); // first digit on,
digitalWrite(GND2, LOW); // other off
digitalWrite(GND3, LOW);
 }
 delay (1);


number = number%1000;  // remainder of 1234/1000 is 234
digitalWrite(GND1, LOW); // first digit is off
 showdigit(number/100); //// segments are set to display "2"
if (decimal_point&4) {digitalWrite(DP, HIGH);} else {digitalWrite(DP, LOW);};
 if (digit_on&4) {
digitalWrite(GND2, HIGH); // second digit is on
  } delay (1);// and so on....
 
number =number%100;    
digitalWrite(GND2, LOW);
showdigit(number/10);
if (decimal_point&2) {digitalWrite(DP, HIGH);} else {digitalWrite(DP, LOW);};
 if (digit_on&2) {
digitalWrite(GND3, HIGH);
 }
 delay (1);

number =number%10; 
digitalWrite(GND3, LOW);
showdigit(number); 
if (decimal_point&1) {digitalWrite(DP, HIGH);} else {digitalWrite(DP, LOW);};
 if (digit_on&1) {
digitalWrite(GND4, HIGH); 
  }
  delay (1);
}; 
void setup()
{
pinMode(A, OUTPUT);
pinMode(B, OUTPUT);
pinMode(C, OUTPUT);
pinMode(D, OUTPUT);
pinMode(E, OUTPUT);
pinMode(FF, OUTPUT);
pinMode(G, OUTPUT);
pinMode(DP, OUTPUT);
pinMode(GND1, OUTPUT);
pinMode(GND2, OUTPUT);
pinMode(GND3, OUTPUT);
pinMode(GND4, OUTPUT);

pinMode(Button_start, INPUT);
digitalWrite(Button_start, HIGH); //pull up resistor

pinMode(Button_set, INPUT);
digitalWrite(Button_set, HIGH); //pull up resistor

pinMode(Buzzer, OUTPUT);
pinMode(LED, OUTPUT);

TIMSK1=0x01; // enabled global and timer overflow interrupt;
TCCR1A = 0x00; // normal operation 148 page (mode0);

TCNT1=0x0BDC;

TCCR1B = 0x00; // stop hardware timer

// loading default timer values

Sec = default_Sec ; 
Min = default_Min ;



};
void loop ()

{
 //////////// button_start////////// 
  if (!digitalRead(Button_start)&&!b) {
  
  if (!set_mode) { if (run) {TCCR1B=0x00; run=0;} else {TCCR1B=0x04; run=1;}}
  
  if (set_mode==1) {Min++;} 
  
   if (set_mode==2) {Sec++;} 
      
   if (set_mode) {b=25;} else b=100;
  
         };
         
 if (!digitalRead(Button_start)&&b==1) {
     
        };       


if (!b==0) b--;

 //////////// button_set///////// 
 if (!digitalRead(Button_set)&&!c) {
  
   if(!run&&!set_mode) {Min=default_Min; Sec=default_Sec;}
            
  if (set_mode>0) set_mode++;
  
  if (set_mode==3) {set_mode=0;  default_Sec = Sec ;
default_Min = Min; }
  
   c=100;      };   
   
 if (!digitalRead(Button_set)&&c==1&&!run) {
   
     set_mode=1;
     
     c=100;
   
        };       


if (!c==0) c--;
////////////////////////////

if (set_mode) {if (Sec==60) {Sec=00;} 

 if (Min==100) {Min=0;} }

      
       else {
 
 if (Sec==-1) {Min--;Sec=59;} 
 
 }  
 
 
//decimal point indication control 

if (!set_mode) {
    
  if (!(Sec%2)) { showdigits (Min*100+Sec,0x0F,0x04); } //0X00

  else  {
  showdigits (Min*100+Sec,0x0F,0x00); }; //0000

} 
else {
  
  if (set_mode==1) {
  
  showdigits (Min*100+Sec,0x0F,0x0C);   //XX00
                                } 
      else { 
                     
                     
                     
                     showdigits (Min*100+Sec,0x0F,0x03);      } //00XX

}
if (run) {  // to do while timer is running; e.g. control relay 

digitalWrite(LED, HIGH);


} else digitalWrite(LED, LOW);



if ((Min==0)&&(Sec==0)&&run) {
run=0;
TCCR1B=0x00; //stop timer

//// to do after count down is finished e.g. start alarm as in this example


alarm=1;
d=500;

}

// Alarm part
if (alarm) { if (!(d%100)) { // sound 500/100= 5 times ;
  tone(Buzzer, 440, 200); }
  d--; 
  if (d==0) {alarm=0; Sec = default_Sec ;
  Min = default_Min ; // After alarm is off, timer goes to start
          }
    }  
  
};

2. второй вопрос -  как организовать меню? в смысле выбор что кнопками регулируется.

например, при нажатии на кнопку select один раз - мигают разряды секунд (двумя другими кнопками в этот  момент можно менять значение), второй раз - разряд минут. при длительном нажатии - старт отсчёта.

а когда отсчёт идёт, кнопка select(при однократном нажатии) позволяет устанавливать ШИМ для светодиодов(в первом разряде "d", в двух других от 0 до 99), при втором нажатии  - в первом разряде появится символ "t", в двух других регулировка от 0 до 99.

длинное нажатие - возврат к отображению времени с сохранением настроек ШИМ.

как-то так.